symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/timeit.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 #! /usr/bin/env python
       
     2 
       
     3 """Tool for measuring execution time of small code snippets.
       
     4 
       
     5 This module avoids a number of common traps for measuring execution
       
     6 times.  See also Tim Peters' introduction to the Algorithms chapter in
       
     7 the Python Cookbook, published by O'Reilly.
       
     8 
       
     9 Library usage: see the Timer class.
       
    10 
       
    11 Command line usage:
       
    12     python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement]
       
    13 
       
    14 Options:
       
    15   -n/--number N: how many times to execute 'statement' (default: see below)
       
    16   -r/--repeat N: how many times to repeat the timer (default 3)
       
    17   -s/--setup S: statement to be executed once initially (default 'pass')
       
    18   -t/--time: use time.time() (default on Unix)
       
    19   -c/--clock: use time.clock() (default on Windows)
       
    20   -v/--verbose: print raw timing results; repeat for more digits precision
       
    21   -h/--help: print this usage message and exit
       
    22   statement: statement to be timed (default 'pass')
       
    23 
       
    24 A multi-line statement may be given by specifying each line as a
       
    25 separate argument; indented lines are possible by enclosing an
       
    26 argument in quotes and using leading spaces.  Multiple -s options are
       
    27 treated similarly.
       
    28 
       
    29 If -n is not given, a suitable number of loops is calculated by trying
       
    30 successive powers of 10 until the total time is at least 0.2 seconds.
       
    31 
       
    32 The difference in default timer function is because on Windows,
       
    33 clock() has microsecond granularity but time()'s granularity is 1/60th
       
    34 of a second; on Unix, clock() has 1/100th of a second granularity and
       
    35 time() is much more precise.  On either platform, the default timer
       
    36 functions measure wall clock time, not the CPU time.  This means that
       
    37 other processes running on the same computer may interfere with the
       
    38 timing.  The best thing to do when accurate timing is necessary is to
       
    39 repeat the timing a few times and use the best time.  The -r option is
       
    40 good for this; the default of 3 repetitions is probably enough in most
       
    41 cases.  On Unix, you can use clock() to measure CPU time.
       
    42 
       
    43 Note: there is a certain baseline overhead associated with executing a
       
    44 pass statement.  The code here doesn't try to hide it, but you should
       
    45 be aware of it.  The baseline overhead can be measured by invoking the
       
    46 program without arguments.
       
    47 
       
    48 The baseline overhead differs between Python versions!  Also, to
       
    49 fairly compare older Python versions to Python 2.3, you may want to
       
    50 use python -O for the older versions to avoid timing SET_LINENO
       
    51 instructions.
       
    52 """
       
    53 
       
    54 import gc
       
    55 import sys
       
    56 import time
       
    57 try:
       
    58     import itertools
       
    59 except ImportError:
       
    60     # Must be an older Python version (see timeit() below)
       
    61     itertools = None
       
    62 
       
    63 __all__ = ["Timer"]
       
    64 
       
    65 dummy_src_name = "<timeit-src>"
       
    66 default_number = 1000000
       
    67 default_repeat = 3
       
    68 
       
    69 if sys.platform == "win32":
       
    70     # On Windows, the best timer is time.clock()
       
    71     default_timer = time.clock
       
    72 else:
       
    73     # On most other platforms the best timer is time.time()
       
    74     default_timer = time.time
       
    75 
       
    76 # Don't change the indentation of the template; the reindent() calls
       
    77 # in Timer.__init__() depend on setup being indented 4 spaces and stmt
       
    78 # being indented 8 spaces.
       
    79 template = """
       
    80 def inner(_it, _timer):
       
    81     %(setup)s
       
    82     _t0 = _timer()
       
    83     for _i in _it:
       
    84         %(stmt)s
       
    85     _t1 = _timer()
       
    86     return _t1 - _t0
       
    87 """
       
    88 
       
    89 def reindent(src, indent):
       
    90     """Helper to reindent a multi-line statement."""
       
    91     return src.replace("\n", "\n" + " "*indent)
       
    92 
       
    93 def _template_func(setup, func):
       
    94     """Create a timer function. Used if the "statement" is a callable."""
       
    95     def inner(_it, _timer):
       
    96         setup()
       
    97         _t0 = _timer()
       
    98         for _i in _it:
       
    99             func()
       
   100         _t1 = _timer()
       
   101         return _t1 - _t0
       
   102     return inner
       
   103 
       
   104 class Timer:
       
   105     """Class for timing execution speed of small code snippets.
       
   106 
       
   107     The constructor takes a statement to be timed, an additional
       
   108     statement used for setup, and a timer function.  Both statements
       
   109     default to 'pass'; the timer function is platform-dependent (see
       
   110     module doc string).
       
   111 
       
   112     To measure the execution time of the first statement, use the
       
   113     timeit() method.  The repeat() method is a convenience to call
       
   114     timeit() multiple times and return a list of results.
       
   115 
       
   116     The statements may contain newlines, as long as they don't contain
       
   117     multi-line string literals.
       
   118     """
       
   119 
       
   120     def __init__(self, stmt="pass", setup="pass", timer=default_timer):
       
   121         """Constructor.  See class doc string."""
       
   122         self.timer = timer
       
   123         ns = {}
       
   124         if isinstance(stmt, basestring):
       
   125             stmt = reindent(stmt, 8)
       
   126             if isinstance(setup, basestring):
       
   127                 setup = reindent(setup, 4)
       
   128                 src = template % {'stmt': stmt, 'setup': setup}
       
   129             elif callable(setup):
       
   130                 src = template % {'stmt': stmt, 'setup': '_setup()'}
       
   131                 ns['_setup'] = setup
       
   132             else:
       
   133                 raise ValueError("setup is neither a string nor callable")
       
   134             self.src = src # Save for traceback display
       
   135             code = compile(src, dummy_src_name, "exec")
       
   136             exec code in globals(), ns
       
   137             self.inner = ns["inner"]
       
   138         elif callable(stmt):
       
   139             self.src = None
       
   140             if isinstance(setup, basestring):
       
   141                 _setup = setup
       
   142                 def setup():
       
   143                     exec _setup in globals(), ns
       
   144             elif not callable(setup):
       
   145                 raise ValueError("setup is neither a string nor callable")
       
   146             self.inner = _template_func(setup, stmt)
       
   147         else:
       
   148             raise ValueError("stmt is neither a string nor callable")
       
   149 
       
   150     def print_exc(self, file=None):
       
   151         """Helper to print a traceback from the timed code.
       
   152 
       
   153         Typical use:
       
   154 
       
   155             t = Timer(...)       # outside the try/except
       
   156             try:
       
   157                 t.timeit(...)    # or t.repeat(...)
       
   158             except:
       
   159                 t.print_exc()
       
   160 
       
   161         The advantage over the standard traceback is that source lines
       
   162         in the compiled template will be displayed.
       
   163 
       
   164         The optional file argument directs where the traceback is
       
   165         sent; it defaults to sys.stderr.
       
   166         """
       
   167         import linecache, traceback
       
   168         if self.src is not None:
       
   169             linecache.cache[dummy_src_name] = (len(self.src),
       
   170                                                None,
       
   171                                                self.src.split("\n"),
       
   172                                                dummy_src_name)
       
   173         # else the source is already stored somewhere else
       
   174 
       
   175         traceback.print_exc(file=file)
       
   176 
       
   177     def timeit(self, number=default_number):
       
   178         """Time 'number' executions of the main statement.
       
   179 
       
   180         To be precise, this executes the setup statement once, and
       
   181         then returns the time it takes to execute the main statement
       
   182         a number of times, as a float measured in seconds.  The
       
   183         argument is the number of times through the loop, defaulting
       
   184         to one million.  The main statement, the setup statement and
       
   185         the timer function to be used are passed to the constructor.
       
   186         """
       
   187         if itertools:
       
   188             it = itertools.repeat(None, number)
       
   189         else:
       
   190             it = [None] * number
       
   191         gcold = gc.isenabled()
       
   192         gc.disable()
       
   193         timing = self.inner(it, self.timer)
       
   194         if gcold:
       
   195             gc.enable()
       
   196         return timing
       
   197 
       
   198     def repeat(self, repeat=default_repeat, number=default_number):
       
   199         """Call timeit() a few times.
       
   200 
       
   201         This is a convenience function that calls the timeit()
       
   202         repeatedly, returning a list of results.  The first argument
       
   203         specifies how many times to call timeit(), defaulting to 3;
       
   204         the second argument specifies the timer argument, defaulting
       
   205         to one million.
       
   206 
       
   207         Note: it's tempting to calculate mean and standard deviation
       
   208         from the result vector and report these.  However, this is not
       
   209         very useful.  In a typical case, the lowest value gives a
       
   210         lower bound for how fast your machine can run the given code
       
   211         snippet; higher values in the result vector are typically not
       
   212         caused by variability in Python's speed, but by other
       
   213         processes interfering with your timing accuracy.  So the min()
       
   214         of the result is probably the only number you should be
       
   215         interested in.  After that, you should look at the entire
       
   216         vector and apply common sense rather than statistics.
       
   217         """
       
   218         r = []
       
   219         for i in range(repeat):
       
   220             t = self.timeit(number)
       
   221             r.append(t)
       
   222         return r
       
   223 
       
   224 def timeit(stmt="pass", setup="pass", timer=default_timer,
       
   225            number=default_number):
       
   226     """Convenience function to create Timer object and call timeit method."""
       
   227     return Timer(stmt, setup, timer).timeit(number)
       
   228 
       
   229 def repeat(stmt="pass", setup="pass", timer=default_timer,
       
   230            repeat=default_repeat, number=default_number):
       
   231     """Convenience function to create Timer object and call repeat method."""
       
   232     return Timer(stmt, setup, timer).repeat(repeat, number)
       
   233 
       
   234 def main(args=None):
       
   235     """Main program, used when run as a script.
       
   236 
       
   237     The optional argument specifies the command line to be parsed,
       
   238     defaulting to sys.argv[1:].
       
   239 
       
   240     The return value is an exit code to be passed to sys.exit(); it
       
   241     may be None to indicate success.
       
   242 
       
   243     When an exception happens during timing, a traceback is printed to
       
   244     stderr and the return value is 1.  Exceptions at other times
       
   245     (including the template compilation) are not caught.
       
   246     """
       
   247     if args is None:
       
   248         args = sys.argv[1:]
       
   249     import getopt
       
   250     try:
       
   251         opts, args = getopt.getopt(args, "n:s:r:tcvh",
       
   252                                    ["number=", "setup=", "repeat=",
       
   253                                     "time", "clock", "verbose", "help"])
       
   254     except getopt.error, err:
       
   255         print err
       
   256         print "use -h/--help for command line help"
       
   257         return 2
       
   258     timer = default_timer
       
   259     stmt = "\n".join(args) or "pass"
       
   260     number = 0 # auto-determine
       
   261     setup = []
       
   262     repeat = default_repeat
       
   263     verbose = 0
       
   264     precision = 3
       
   265     for o, a in opts:
       
   266         if o in ("-n", "--number"):
       
   267             number = int(a)
       
   268         if o in ("-s", "--setup"):
       
   269             setup.append(a)
       
   270         if o in ("-r", "--repeat"):
       
   271             repeat = int(a)
       
   272             if repeat <= 0:
       
   273                 repeat = 1
       
   274         if o in ("-t", "--time"):
       
   275             timer = time.time
       
   276         if o in ("-c", "--clock"):
       
   277             timer = time.clock
       
   278         if o in ("-v", "--verbose"):
       
   279             if verbose:
       
   280                 precision += 1
       
   281             verbose += 1
       
   282         if o in ("-h", "--help"):
       
   283             print __doc__,
       
   284             return 0
       
   285     setup = "\n".join(setup) or "pass"
       
   286     # Include the current directory, so that local imports work (sys.path
       
   287     # contains the directory of this script, rather than the current
       
   288     # directory)
       
   289     import os
       
   290     sys.path.insert(0, os.curdir)
       
   291     t = Timer(stmt, setup, timer)
       
   292     if number == 0:
       
   293         # determine number so that 0.2 <= total time < 2.0
       
   294         for i in range(1, 10):
       
   295             number = 10**i
       
   296             try:
       
   297                 x = t.timeit(number)
       
   298             except:
       
   299                 t.print_exc()
       
   300                 return 1
       
   301             if verbose:
       
   302                 print "%d loops -> %.*g secs" % (number, precision, x)
       
   303             if x >= 0.2:
       
   304                 break
       
   305     try:
       
   306         r = t.repeat(repeat, number)
       
   307     except:
       
   308         t.print_exc()
       
   309         return 1
       
   310     best = min(r)
       
   311     if verbose:
       
   312         print "raw times:", " ".join(["%.*g" % (precision, x) for x in r])
       
   313     print "%d loops," % number,
       
   314     usec = best * 1e6 / number
       
   315     if usec < 1000:
       
   316         print "best of %d: %.*g usec per loop" % (repeat, precision, usec)
       
   317     else:
       
   318         msec = usec / 1000
       
   319         if msec < 1000:
       
   320             print "best of %d: %.*g msec per loop" % (repeat, precision, msec)
       
   321         else:
       
   322             sec = msec / 1000
       
   323             print "best of %d: %.*g sec per loop" % (repeat, precision, sec)
       
   324     return None
       
   325 
       
   326 if __name__ == "__main__":
       
   327     sys.exit(main())