0001 #! /usr/bin/env python 0002 0003 """Tool for measuring execution time of small code snippets. 0004 0005 This module avoids a number of common traps for measuring execution 0006 times. See also Tim Peters' introduction to the Algorithms chapter in 0007 the Python Cookbook, published by O'Reilly. 0008 0009 Library usage: see the Timer class. 0010 0011 Command line usage: 0012 python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement] 0013 0014 Options: 0015 -n/--number N: how many times to execute 'statement' (default: see below) 0016 -r/--repeat N: how many times to repeat the timer (default 3) 0017 -s/--setup S: statement to be executed once initially (default 'pass') 0018 -t/--time: use time.time() (default on Unix) 0019 -c/--clock: use time.clock() (default on Windows) 0020 -v/--verbose: print raw timing results; repeat for more digits precision 0021 -h/--help: print this usage message and exit 0022 statement: statement to be timed (default 'pass') 0023 0024 A multi-line statement may be given by specifying each line as a 0025 separate argument; indented lines are possible by enclosing an 0026 argument in quotes and using leading spaces. Multiple -s options are 0027 treated similarly. 0028 0029 If -n is not given, a suitable number of loops is calculated by trying 0030 successive powers of 10 until the total time is at least 0.2 seconds. 0031 0032 The difference in default timer function is because on Windows, 0033 clock() has microsecond granularity but time()'s granularity is 1/60th 0034 of a second; on Unix, clock() has 1/100th of a second granularity and 0035 time() is much more precise. On either platform, the default timer 0036 functions measure wall clock time, not the CPU time. This means that 0037 other processes running on the same computer may interfere with the 0038 timing. The best thing to do when accurate timing is necessary is to 0039 repeat the timing a few times and use the best time. The -r option is 0040 good for this; the default of 3 repetitions is probably enough in most 0041 cases. On Unix, you can use clock() to measure CPU time. 0042 0043 Note: there is a certain baseline overhead associated with executing a 0044 pass statement. The code here doesn't try to hide it, but you should 0045 be aware of it. The baseline overhead can be measured by invoking the 0046 program without arguments. 0047 0048 The baseline overhead differs between Python versions! Also, to 0049 fairly compare older Python versions to Python 2.3, you may want to 0050 use python -O for the older versions to avoid timing SET_LINENO 0051 instructions. 0052 """ 0053 0054 import gc 0055 import sys 0056 import time 0057 try: 0058 import itertools 0059 except ImportError: 0060 # Must be an older Python version (see timeit() below) 0061 itertools = None 0062 0063 __all__ = ["Timer"] 0064 0065 dummy_src_name = "<timeit-src>" 0066 default_number = 1000000 0067 default_repeat = 3 0068 0069 if sys.platform == "win32": 0070 # On Windows, the best timer is time.clock() 0071 default_timer = time.clock 0072 else: 0073 # On most other platforms the best timer is time.time() 0074 default_timer = time.time 0075 0076 # Don't change the indentation of the template; the reindent() calls 0077 # in Timer.__init__() depend on setup being indented 4 spaces and stmt 0078 # being indented 8 spaces. 0079 template = """ 0080 def inner(_it, _timer): 0081 %(setup)s 0082 _t0 = _timer() 0083 for _i in _it: 0084 %(stmt)s 0085 _t1 = _timer() 0086 return _t1 - _t0 0087 """ 0088 0089 def reindent(src, indent): 0090 """Helper to reindent a multi-line statement.""" 0091 return src.replace("\n", "\n" + " "*indent) 0092 0093 class Timer: 0094 """Class for timing execution speed of small code snippets. 0095 0096 The constructor takes a statement to be timed, an additional 0097 statement used for setup, and a timer function. Both statements 0098 default to 'pass'; the timer function is platform-dependent (see 0099 module doc string). 0100 0101 To measure the execution time of the first statement, use the 0102 timeit() method. The repeat() method is a convenience to call 0103 timeit() multiple times and return a list of results. 0104 0105 The statements may contain newlines, as long as they don't contain 0106 multi-line string literals. 0107 """ 0108 0109 def __init__(self, stmt="pass", setup="pass", timer=default_timer): 0110 """Constructor. See class doc string.""" 0111 self.timer = timer 0112 stmt = reindent(stmt, 8) 0113 setup = reindent(setup, 4) 0114 src = template % {'stmt': stmt, 'setup': setup} 0115 self.src = src # Save for traceback display 0116 code = compile(src, dummy_src_name, "exec") 0117 ns = {} 0118 exec code in globals(), ns 0119 self.inner = ns["inner"] 0120 0121 def print_exc(self, file=None): 0122 """Helper to print a traceback from the timed code. 0123 0124 Typical use: 0125 0126 t = Timer(...) # outside the try/except 0127 try: 0128 t.timeit(...) # or t.repeat(...) 0129 except: 0130 t.print_exc() 0131 0132 The advantage over the standard traceback is that source lines 0133 in the compiled template will be displayed. 0134 0135 The optional file argument directs where the traceback is 0136 sent; it defaults to sys.stderr. 0137 """ 0138 import linecache, traceback 0139 linecache.cache[dummy_src_name] = (len(self.src), 0140 None, 0141 self.src.split("\n"), 0142 dummy_src_name) 0143 traceback.print_exc(file=file) 0144 0145 def timeit(self, number=default_number): 0146 """Time 'number' executions of the main statement. 0147 0148 To be precise, this executes the setup statement once, and 0149 then returns the time it takes to execute the main statement 0150 a number of times, as a float measured in seconds. The 0151 argument is the number of times through the loop, defaulting 0152 to one million. The main statement, the setup statement and 0153 the timer function to be used are passed to the constructor. 0154 """ 0155 if itertools: 0156 it = itertools.repeat(None, number) 0157 else: 0158 it = [None] * number 0159 gcold = gc.isenabled() 0160 gc.disable() 0161 timing = self.inner(it, self.timer) 0162 if gcold: 0163 gc.enable() 0164 return timing 0165 0166 def repeat(self, repeat=default_repeat, number=default_number): 0167 """Call timeit() a few times. 0168 0169 This is a convenience function that calls the timeit() 0170 repeatedly, returning a list of results. The first argument 0171 specifies how many times to call timeit(), defaulting to 3; 0172 the second argument specifies the timer argument, defaulting 0173 to one million. 0174 0175 Note: it's tempting to calculate mean and standard deviation 0176 from the result vector and report these. However, this is not 0177 very useful. In a typical case, the lowest value gives a 0178 lower bound for how fast your machine can run the given code 0179 snippet; higher values in the result vector are typically not 0180 caused by variability in Python's speed, but by other 0181 processes interfering with your timing accuracy. So the min() 0182 of the result is probably the only number you should be 0183 interested in. After that, you should look at the entire 0184 vector and apply common sense rather than statistics. 0185 """ 0186 r = [] 0187 for i in range(repeat): 0188 t = self.timeit(number) 0189 r.append(t) 0190 return r 0191 0192 def main(args=None): 0193 """Main program, used when run as a script. 0194 0195 The optional argument specifies the command line to be parsed, 0196 defaulting to sys.argv[1:]. 0197 0198 The return value is an exit code to be passed to sys.exit(); it 0199 may be None to indicate success. 0200 0201 When an exception happens during timing, a traceback is printed to 0202 stderr and the return value is 1. Exceptions at other times 0203 (including the template compilation) are not caught. 0204 """ 0205 if args is None: 0206 args = sys.argv[1:] 0207 import getopt 0208 try: 0209 opts, args = getopt.getopt(args, "n:s:r:tcvh", 0210 ["number=", "setup=", "repeat=", 0211 "time", "clock", "verbose", "help"]) 0212 except getopt.error, err: 0213 print err 0214 print "use -h/--help for command line help" 0215 return 2 0216 timer = default_timer 0217 stmt = "\n".join(args) or "pass" 0218 number = 0 # auto-determine 0219 setup = [] 0220 repeat = default_repeat 0221 verbose = 0 0222 precision = 3 0223 for o, a in opts: 0224 if o in ("-n", "--number"): 0225 number = int(a) 0226 if o in ("-s", "--setup"): 0227 setup.append(a) 0228 if o in ("-r", "--repeat"): 0229 repeat = int(a) 0230 if repeat <= 0: 0231 repeat = 1 0232 if o in ("-t", "--time"): 0233 timer = time.time 0234 if o in ("-c", "--clock"): 0235 timer = time.clock 0236 if o in ("-v", "--verbose"): 0237 if verbose: 0238 precision += 1 0239 verbose += 1 0240 if o in ("-h", "--help"): 0241 print __doc__, 0242 return 0 0243 setup = "\n".join(setup) or "pass" 0244 # Include the current directory, so that local imports work (sys.path 0245 # contains the directory of this script, rather than the current 0246 # directory) 0247 import os 0248 sys.path.insert(0, os.curdir) 0249 t = Timer(stmt, setup, timer) 0250 if number == 0: 0251 # determine number so that 0.2 <= total time < 2.0 0252 for i in range(1, 10): 0253 number = 10**i 0254 try: 0255 x = t.timeit(number) 0256 except: 0257 t.print_exc() 0258 return 1 0259 if verbose: 0260 print "%d loops -> %.*g secs" % (number, precision, x) 0261 if x >= 0.2: 0262 break 0263 try: 0264 r = t.repeat(repeat, number) 0265 except: 0266 t.print_exc() 0267 return 1 0268 best = min(r) 0269 if verbose: 0270 print "raw times:", " ".join(["%.*g" % (precision, x) for x in r]) 0271 print "%d loops," % number, 0272 usec = best * 1e6 / number 0273 if usec < 1000: 0274 print "best of %d: %.*g usec per loop" % (repeat, precision, usec) 0275 else: 0276 msec = usec / 1000 0277 if msec < 1000: 0278 print "best of %d: %.*g msec per loop" % (repeat, precision, msec) 0279 else: 0280 sec = msec / 1000 0281 print "best of %d: %.*g sec per loop" % (repeat, precision, sec) 0282 return None 0283 0284 if __name__ == "__main__": 0285 sys.exit(main()) 0286
Generated by PyXR 0.9.4