cinap_lenrekadd hg and python4bb9e2215 years agoHistory
224 lines · 8.3 KB · TeX
RawDownload
\section{\module{timeit} ---         Measure execution time of small code snippets} \declaremodule{standard}{timeit}\modulesynopsis{Measure the execution time of small code snippets.} \versionadded{2.3}\index{Benchmarking}\index{Performance} This module provides a simple way to time small bits of Python code.It has both command line as well as callable interfaces.  It avoids anumber of common traps for measuring execution times.  See also TimPeters' introduction to the ``Algorithms'' chapter in the\citetitle{Python Cookbook}, published by O'Reilly. The module defines the following public class: \begin{classdesc}{Timer}{\optional{stmt=\code{'pass'}                         \optional{, setup=\code{'pass'}                         \optional{, timer=<timer function>}}}}Class for timing execution speed of small code snippets. The constructor takes a statement to be timed, an additional statementused for setup, and a timer function.  Both statements default to\code{'pass'}; the timer function is platform-dependent (see themodule doc string).  The statements may contain newlines, as long asthey don't contain multi-line string literals. To measure the execution time of the first statement, use the\method{timeit()} method.  The \method{repeat()} method is aconvenience to call \method{timeit()} multiple times and return a listof results.\end{classdesc} \begin{methoddesc}{print_exc}{\optional{file=\constant{None}}}Helper to print a traceback from the timed code. Typical use: \begin{verbatim}    t = Timer(...)       # outside the try/except    try:        t.timeit(...)    # or t.repeat(...)    except:        t.print_exc()\end{verbatim} The advantage over the standard traceback is that source lines in thecompiled template will be displayed.The optional \var{file} argument directs where the traceback is sent;it defaults to \code{sys.stderr}.\end{methoddesc} \begin{methoddesc}{repeat}{\optional{repeat\code{=3} \optional{,                           number\code{=1000000}}}}Call \method{timeit()} a few times. This is a convenience function that calls the \method{timeit()}repeatedly, returning a list of results.  The first argument specifieshow many times to call \method{timeit()}.  The second argumentspecifies the \var{number} argument for \function{timeit()}. \begin{notice}It's tempting to calculate mean and standard deviation from the resultvector and report these.  However, this is not very useful.  In a typicalcase, the lowest value gives a lower bound for how fast your machine can runthe given code snippet; higher values in the result vector are typically notcaused by variability in Python's speed, but by other processes interferingwith your timing accuracy.  So the \function{min()} of the result isprobably the only number you should be interested in.  After that, youshould look at the entire vector and apply common sense rather thanstatistics.\end{notice}\end{methoddesc} \begin{methoddesc}{timeit}{\optional{number\code{=1000000}}}Time \var{number} executions of the main statement.This executes the setup statement once, and thenreturns the time it takes to execute the main statement a number oftimes, measured in seconds as a float.  The argument is the number oftimes through the loop, defaulting to one million.  The mainstatement, the setup statement and the timer function to be used arepassed to the constructor. \begin{notice}By default, \method{timeit()} temporarily turns off garbage collectionduring the timing.  The advantage of this approach is that it makesindependent timings more comparable.  This disadvantage is that GCmay be an important component of the performance of the function beingmeasured.  If so, GC can be re-enabled as the first statement in the\var{setup} string.  For example:\begin{verbatim}    timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()\end{verbatim}\end{notice}\end{methoddesc}  \subsection{Command Line Interface} When called as a program from the command line, the following form is used: \begin{verbatim}python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]\end{verbatim} where the following options are understood: \begin{description}\item[-n N/\longprogramopt{number=N}] how many times to execute 'statement'\item[-r N/\longprogramopt{repeat=N}] how many times to repeat the timer (default 3)\item[-s S/\longprogramopt{setup=S}] statement to be executed once initially (default\code{'pass'})\item[-t/\longprogramopt{time}] use \function{time.time()}(default on all platforms but Windows)\item[-c/\longprogramopt{clock}] use \function{time.clock()} (default on Windows)\item[-v/\longprogramopt{verbose}] print raw timing results; repeat for more digitsprecision\item[-h/\longprogramopt{help}] print a short usage message and exit\end{description} A multi-line statement may be given by specifying each line as aseparate statement argument; indented lines are possible by enclosingan argument in quotes and using leading spaces.  Multiple\programopt{-s} options are treated similarly. If \programopt{-n} is not given, a suitable number of loops iscalculated by trying successive powers of 10 until the total time isat least 0.2 seconds. The default timer function is platform dependent.  On Windows,\function{time.clock()} has microsecond granularity but\function{time.time()}'s granularity is 1/60th of a second; on \UNIX,\function{time.clock()} has 1/100th of a second granularity and\function{time.time()} is much more precise.  On either platform, thedefault timer functions measure wall clock time, not the CPU time.This means that other processes running on the same computer mayinterfere with the timing.  The best thing to do when accurate timingis necessary is to repeat the timing a few times and use the besttime.  The \programopt{-r} option is good for this; the default of 3repetitions is probably enough in most cases.  On \UNIX, you can use\function{time.clock()} to measure CPU time. \begin{notice}  There is a certain baseline overhead associated with executing a  pass statement.  The code here doesn't try to hide it, but you  should be aware of it.  The baseline overhead can be measured by  invoking the program without arguments.\end{notice} The baseline overhead differs between Python versions!  Also, tofairly compare older Python versions to Python 2.3, you may want touse Python's \programopt{-O} option for the older versions to avoidtiming \code{SET_LINENO} instructions. \subsection{Examples} Here are two example sessions (one using the command line, one usingthe module interface) that compare the cost of using\function{hasattr()} vs. \keyword{try}/\keyword{except} to test formissing and present object attributes. \begin{verbatim}% timeit.py 'try:' '  str.__nonzero__' 'except AttributeError:' '  pass'100000 loops, best of 3: 15.7 usec per loop% timeit.py 'if hasattr(str, "__nonzero__"): pass'100000 loops, best of 3: 4.26 usec per loop% timeit.py 'try:' '  int.__nonzero__' 'except AttributeError:' '  pass'1000000 loops, best of 3: 1.43 usec per loop% timeit.py 'if hasattr(int, "__nonzero__"): pass'100000 loops, best of 3: 2.23 usec per loop\end{verbatim} \begin{verbatim}>>> import timeit>>> s = """\... try:...     str.__nonzero__... except AttributeError:...     pass... """>>> t = timeit.Timer(stmt=s)>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)17.09 usec/pass>>> s = """\... if hasattr(str, '__nonzero__'): pass... """>>> t = timeit.Timer(stmt=s)>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)4.85 usec/pass>>> s = """\... try:...     int.__nonzero__... except AttributeError:...     pass... """>>> t = timeit.Timer(stmt=s)>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)1.97 usec/pass>>> s = """\... if hasattr(int, '__nonzero__'): pass... """>>> t = timeit.Timer(stmt=s)>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)3.15 usec/pass\end{verbatim} To give the \module{timeit} module access to functions youdefine, you can pass a \code{setup} parameter which contains an importstatement: \begin{verbatim}def test():    "Stupid test function"    L = []    for i in range(100):        L.append(i) if __name__=='__main__':    from timeit import Timer    t = Timer("test()", "from __main__ import test")    print t.timeit()\end{verbatim}