Accurate timing information for Sage commands - Utilities

Skip to content
Back to top
View this page
Edit this page

# Accurate timing information for Sage commands

This is an implementation of nice timeit functionality, like the `%timeit` magic command in IPython. To use it, use the `timeit` command. This command then calls `sage_timeit()`, which you can find below.

EXAMPLES:

Sage

    sage: timeit('1+1')    # random output
    625 loops, best of 3: 314 ns per loop

Python

    >>> from sage.all import *
    >>> timeit('1+1')    # random output
    625 loops, best of 3: 314 ns per loop

AUTHOR:

> – William Stein, based on code by Fernando Perez included in IPython

class sage.misc.sage_timeit.SageTimeitResult(stats, series=None)

  Bases: `object`

  Represent the statistics of a timeit() command.

  Prints as a string so that it can be easily returned to a user.

  INPUT:

  - `stats` – tuple of length 5 containing the following information:

    > - integer, number of loops

    > - integer, repeat number

    > - Python integer, number of digits to print

    > - number, best timing result

    > - str, time unit

  EXAMPLES:

  Sage

      sage: from sage.misc.sage_timeit import SageTimeitResult
      sage: SageTimeitResult( (3, 5, int(8), pi, 'ms') )                              # needs sage.symbolic
      3 loops, best of 5: 3.1415927 ms per loop

  Python

      >>> from sage.all import *
      >>> from sage.misc.sage_timeit import SageTimeitResult
      >>> SageTimeitResult( (Integer(3), Integer(5), int(Integer(8)), pi, 'ms') )                              # needs sage.symbolic
      3 loops, best of 5: 3.1415927 ms per loop

  Sage

      sage: units = [u"s", u"ms", u"μs", u"ns"]
      sage: scaling = [1, 1e3, 1e6, 1e9]
      sage: number = 7
      sage: repeat = 13
      sage: precision = int(5)
      sage: best = pi / 10 ^ 9                                                        # needs sage.symbolic
      sage: order = 3
      sage: stats = (number, repeat, precision, best * scaling[order], units[order])  # needs sage.symbolic
      sage: SageTimeitResult(stats)                                                   # needs sage.symbolic
      7 loops, best of 13: 3.1416 ns per loop

  [Python]

      >>> from sage.all import *
      >>> units = [u"s", u"ms", u"μs", u"ns"]
      >>> scaling = [Integer(1), RealNumber('1e3'), RealNumber('1e6'), RealNumber('1e9')]
      >>> number = Integer(7)
      >>> repeat = Integer(13)
      >>> precision = int(Integer(5))
      >>> best = pi / Integer(10) ** Integer(9)                                                        # needs sage.symbolic
      >>> order = Integer(3)
      >>> stats = (number, repeat, precision, best * scaling[order], units[order])  # needs sage.symbolic
      >>> SageTimeitResult(stats)                                                   # needs sage.symbolic
      7 loops, best of 13: 3.1416 ns per loop

  If the third argument is not a Python integer, a `TypeError` is raised:

  Sage

      sage: SageTimeitResult( (1, 2, 3, 4, 's') )
      <repr(<sage.misc.sage_timeit.SageTimeitResult at 0x...>) failed: TypeError: * wants int>

  Python

      >>> from sage.all import *
      >>> SageTimeitResult( (Integer(1), Integer(2), Integer(3), Integer(4), 's') )
      <repr(<sage.misc.sage_timeit.SageTimeitResult at 0x...>) failed: TypeError: * wants int>

sage.misc.sage_timeit.sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, precision=3, seconds=False)

  Accurately measure the wall time required to execute `stmt`.

  INPUT:

  - `stmt` – a text string

  - `globals_dict` – dictionary or `None` (default). Evaluate `stmt` in the context of the globals dictionary. If not set, the current `globals()` dictionary is used.

  - `preparse` – (default: use globals preparser default) if `True` preparse `stmt` using the Sage preparser

  - `number` – integer; (default: 0); number of loops

  - `repeat` – integer; (default: 3); number of repetition

  - `precision` – integer; (default: 3); precision of output time

  - `seconds` – boolean (default: `False`); whether to just return time in seconds

  OUTPUT:

  An instance of `SageTimeitResult` unless the optional parameter `seconds=True` is passed. In that case, the elapsed time in seconds is returned as a floating-point number.

  EXAMPLES:

  Sage

      sage: from sage.misc.sage_timeit import sage_timeit
      sage: sage_timeit('3^100000', globals(), preparse=True, number=50)      # random output
      '50 loops, best of 3: 1.97 ms per loop'
      sage: sage_timeit('3^100000', globals(), preparse=False, number=50)     # random output
      '50 loops, best of 3: 67.1 ns per loop'
      sage: a = 10
      sage: sage_timeit('a^2', globals(), number=50)                            # random output
      '50 loops, best of 3: 4.26 us per loop'

  Python

      >>> from sage.all import *
      >>> from sage.misc.sage_timeit import sage_timeit
      >>> sage_timeit('3^100000', globals(), preparse=True, number=Integer(50))      # random output
      '50 loops, best of 3: 1.97 ms per loop'
      >>> sage_timeit('3^100000', globals(), preparse=False, number=Integer(50))     # random output
      '50 loops, best of 3: 67.1 ns per loop'
      >>> a = Integer(10)
      >>> sage_timeit('a^2', globals(), number=Integer(50))                            # random output
      '50 loops, best of 3: 4.26 us per loop'

  If you only want to see the timing and not have access to additional information, just use the `timeit` object:

  Sage

      sage: timeit('10^2', number=50)
      50 loops, best of 3: ... per loop

  [Python]

      >>> from sage.all import *
      >>> timeit('10^2', number=Integer(50))
      50 loops, best of 3: ... per loop

  Using sage_timeit gives you more information though:

  Sage

      sage: s = sage_timeit('10^2', globals(), repeat=1000)
      sage: len(s.series)
      1000
      sage: mean(s.series)   # random output                                          # needs sage.modules
      3.1298141479492283e-07
      sage: min(s.series)    # random output
      2.9258728027343752e-07
      sage: t = stats.TimeSeries(s.series)                                            # needs numpy sage.modules
      sage: t.scale(10^6).plot_histogram(bins=20,figsize=[12,6], ymax=2)              # needs numpy sage.modules sage.plot
      Graphics object consisting of 20 graphics primitives

  Python

      >>> from sage.all import *
      >>> s = sage_timeit('10^2', globals(), repeat=Integer(1000))
      >>> len(s.series)
      1000
      >>> mean(s.series)   # random output                                          # needs sage.modules
      3.1298141479492283e-07
      >>> min(s.series)    # random output
      2.9258728027343752e-07
      >>> t = stats.TimeSeries(s.series)                                            # needs numpy sage.modules
      >>> t.scale(Integer(10)**Integer(6)).plot_histogram(bins=Integer(20),figsize=[Integer(12),Integer(6)], ymax=Integer(2))              # needs numpy sage.modules sage.plot
      Graphics object consisting of 20 graphics primitives

  The input expression can contain newlines (but doctests cannot, so we use `os.linesep` here):

  Sage

      sage: from sage.misc.sage_timeit import sage_timeit
      sage: from os import linesep as CR
      sage: # sage_timeit(r'a = 2\nb=131\nfactor(a^b-1)')
      sage: sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)',                # needs sage.libs.pari
      ....:             globals(), number=10)
      10 loops, best of 3: ... per loop

  [Python]

      >>> from sage.all import *
      >>> from sage.misc.sage_timeit import sage_timeit
      >>> from os import linesep as CR
      >>> # sage_timeit(r'a = 2\nb=131\nfactor(a^b-1)')
      >>> sage_timeit('a = 2' + CR + 'b=131' + CR + 'factor(a^b-1)',                # needs sage.libs.pari
      ...             globals(), number=Integer(10))
      10 loops, best of 3: ... per loop

  Test to make sure that `timeit` behaves well with output:

  Sage

      sage: timeit("print('Hi')", number=50)
      50 loops, best of 3: ... per loop

  Python

      >>> from sage.all import *
      >>> timeit("print('Hi')", number=Integer(50))
      50 loops, best of 3: ... per loop

  If you want a machine-readable output, use the `seconds=True` option:

  Sage

      sage: timeit("print('Hi')", seconds=True)   # random output
      1.42555236816e-06
      sage: t = timeit("print('Hi')", seconds=True)
      sage: t     #r random output
      3.6010742187499999e-07

  [Python]

      >>> from sage.all import *
      >>> timeit("print('Hi')", seconds=True)   # random output
      1.42555236816e-06
      >>> t = timeit("print('Hi')", seconds=True)
      >>> t     #r random output
      3.6010742187499999e-07