blob: 4ad4a39e550e676ae2a917fa8bccb9b49e89d22a [file] [log] [blame]
Skip Montanarocfd55502003-04-08 19:49:40 +00001#! /usr/bin/env python
2
Guido van Rossum6e31aad2003-03-07 01:33:18 +00003"""Tool for measuring execution time of small code snippets.
Guido van Rossumb3f09d42003-03-05 23:31:58 +00004
Guido van Rossumb7ab6002003-03-06 02:32:19 +00005This module avoids a number of common traps for measuring execution
6times. See also Tim Peters' introduction to the Algorithms chapter in
7the Python Cookbook, published by O'Reilly.
Guido van Rossumb3f09d42003-03-05 23:31:58 +00008
Guido van Rossumb7ab6002003-03-06 02:32:19 +00009Library usage: see the Timer class.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000010
11Command line usage:
Guido van Rossume8577b72003-03-06 03:02:10 +000012 python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement]
Guido van Rossumb3f09d42003-03-05 23:31:58 +000013
14Options:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000015 -n/--number N: how many times to execute 'statement' (default: see below)
Guido van Rossum0070f002003-03-15 12:25:00 +000016 -r/--repeat N: how many times to repeat the timer (default 3)
Guido van Rossum6e31aad2003-03-07 01:33:18 +000017 -s/--setup S: statement to be executed once initially (default 'pass')
Guido van Rossumb3f09d42003-03-05 23:31:58 +000018 -t/--time: use time.time() (default on Unix)
19 -c/--clock: use time.clock() (default on Windows)
Guido van Rossum0070f002003-03-15 12:25:00 +000020 -v/--verbose: print raw timing results; repeat for more digits precision
Guido van Rossume8577b72003-03-06 03:02:10 +000021 -h/--help: print this usage message and exit
Guido van Rossumb3f09d42003-03-05 23:31:58 +000022 statement: statement to be timed (default 'pass')
Guido van Rossumb7ab6002003-03-06 02:32:19 +000023
24A multi-line statement may be given by specifying each line as a
25separate argument; indented lines are possible by enclosing an
Guido van Rossum6e31aad2003-03-07 01:33:18 +000026argument in quotes and using leading spaces. Multiple -s options are
27treated similarly.
Guido van Rossumb7ab6002003-03-06 02:32:19 +000028
29If -n is not given, a suitable number of loops is calculated by trying
30successive powers of 10 until the total time is at least 0.2 seconds.
31
32The difference in default timer function is because on Windows,
33clock() has microsecond granularity but time()'s granularity is 1/60th
34of a second; on Unix, clock() has 1/100th of a second granularity and
35time() is much more precise. On either platform, the default timer
36functions measures wall clock time, not the CPU time. This means that
37other processes running on the same computer may interfere with the
38timing. The best thing to do when accurate timing is necessary is to
Guido van Rossum0070f002003-03-15 12:25:00 +000039repeat the timing a few times and use the best time. The -r option is
40good for this; the default of 3 repetitions is probably enough in most
41cases. On Unix, you can use clock() to measure CPU time.
Guido van Rossume8577b72003-03-06 03:02:10 +000042
43Note: there is a certain baseline overhead associated with executing a
44pass statement. The code here doesn't try to hide it, but you should
Guido van Rossum6e31aad2003-03-07 01:33:18 +000045be aware of it. The baseline overhead can be measured by invoking the
46program without arguments.
47
48The baseline overhead differs between Python versions! Also, to
49fairly compare older Python versions to Python 2.3, you may want to
50use python -O for the older versions to avoid timing SET_LINENO
51instructions.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000052"""
53
54import sys
55import math
56import time
Guido van Rossum6e31aad2003-03-07 01:33:18 +000057try:
58 import itertools
59except ImportError:
60 # Must be an older Python version (see timeit() below)
61 itertools = None
Guido van Rossumb3f09d42003-03-05 23:31:58 +000062
63__all__ = ["Timer"]
64
Guido van Rossum538f1d82003-03-14 17:21:00 +000065dummy_src_name = "<timeit-src>"
Guido van Rossumb3f09d42003-03-05 23:31:58 +000066default_number = 1000000
Guido van Rossum0070f002003-03-15 12:25:00 +000067default_repeat = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +000068
69if sys.platform == "win32":
70 # On Windows, the best timer is time.clock()
71 default_timer = time.clock
72else:
73 # On most other platforms the best timer is time.time()
74 default_timer = time.time
75
Guido van Rossumb7ab6002003-03-06 02:32:19 +000076# 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.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000079template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000080def inner(_it, _timer):
Guido van Rossumb3f09d42003-03-05 23:31:58 +000081 %(setup)s
Guido van Rossum538f1d82003-03-14 17:21:00 +000082 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000083 for _i in _it:
Guido van Rossumb3f09d42003-03-05 23:31:58 +000084 %(stmt)s
Guido van Rossum538f1d82003-03-14 17:21:00 +000085 _t1 = _timer()
86 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000087"""
88
89def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000090 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000091 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000092
93class Timer:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000094 """Class for timing execution speed of small code snippets.
95
96 The constructor takes a statement to be timed, an additional
97 statement used for setup, and a timer function. Both statements
98 default to 'pass'; the timer function is platform-dependent (see
99 module doc string).
100
101 To measure the execution time of the first statement, use the
102 timeit() method. The repeat() method is a convenience to call
103 timeit() multiple times and return a list of results.
104
105 The statements may contain newlines, as long as they don't contain
106 multi-line string literals.
107 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000108
109 def __init__(self, stmt="pass", setup="pass", timer=default_timer):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000110 """Constructor. See class doc string."""
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000111 self.timer = timer
112 stmt = reindent(stmt, 8)
113 setup = reindent(setup, 4)
114 src = template % {'stmt': stmt, 'setup': setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +0000115 self.src = src # Save for traceback display
116 code = compile(src, dummy_src_name, "exec")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000117 ns = {}
118 exec code in globals(), ns
119 self.inner = ns["inner"]
120
Guido van Rossum538f1d82003-03-14 17:21:00 +0000121 def print_exc(self, file=None):
122 """Helper to print a traceback from the timed code.
123
124 Typical use:
125
126 t = Timer(...) # outside the try/except
127 try:
128 t.timeit(...) # or t.repeat(...)
129 except:
130 t.print_exc()
131
132 The advantage over the standard traceback is that source lines
133 in the compiled template will be displayed.
134
135 The optional file argument directs where the traceback is
136 sent; it defaults to sys.stderr.
137 """
138 import linecache, traceback
139 linecache.cache[dummy_src_name] = (len(self.src),
140 None,
141 self.src.split("\n"),
142 dummy_src_name)
143 traceback.print_exc(file=file)
144
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000145 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000146 """Time 'number' executions of the main statement.
147
148 To be precise, this executes the setup statement once, and
149 then returns the time it takes to execute the main statement
150 a number of times, as a float measured in seconds. The
151 argument is the number of times through the loop, defaulting
152 to one million. The main statement, the setup statement and
153 the timer function to be used are passed to the constructor.
154 """
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000155 if itertools:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000156 it = itertools.repeat(None, number)
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000157 else:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000158 it = [None] * number
159 return self.inner(it, self.timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000160
161 def repeat(self, repeat=default_repeat, number=default_number):
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000162 """Call timeit() a few times.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000163
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000164 This is a convenience function that calls the timeit()
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000165 repeatedly, returning a list of results. The first argument
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000166 specifies how many times to call timeit(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000167 the second argument specifies the timer argument, defaulting
168 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000169
170 Note: it's tempting to calculate mean and standard deviation
171 from the result vector and report these. However, this is not
172 very useful. In a typical case, the lowest value gives a
173 lower bound for how fast your machine can run the given code
174 snippet; higher values in the result vector are typically not
175 caused by variability in Python's speed, but by other
176 processes interfering with your timing accuracy. So the min()
177 of the result is probably the only number you should be
178 interested in. After that, you should look at the entire
179 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000180 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000181 r = []
182 for i in range(repeat):
183 t = self.timeit(number)
184 r.append(t)
185 return r
186
187def main(args=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000188 """Main program, used when run as a script.
189
190 The optional argument specifies the command line to be parsed,
191 defaulting to sys.argv[1:].
192
193 The return value is an exit code to be passed to sys.exit(); it
194 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000195
196 When an exception happens during timing, a traceback is printed to
197 stderr and the return value is 1. Exceptions at other times
198 (including the template compilation) are not caught.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000199 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000200 if args is None:
201 args = sys.argv[1:]
202 import getopt
203 try:
Guido van Rossum0070f002003-03-15 12:25:00 +0000204 opts, args = getopt.getopt(args, "n:s:r:tcvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000205 ["number=", "setup=", "repeat=",
Guido van Rossum0070f002003-03-15 12:25:00 +0000206 "time", "clock", "verbose", "help"])
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000207 except getopt.error, err:
208 print err
Guido van Rossume8577b72003-03-06 03:02:10 +0000209 print "use -h/--help for command line help"
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000210 return 2
211 timer = default_timer
212 stmt = "\n".join(args) or "pass"
213 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000214 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000215 repeat = default_repeat
216 verbose = 0
217 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000218 for o, a in opts:
219 if o in ("-n", "--number"):
220 number = int(a)
221 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000222 setup.append(a)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000223 if o in ("-r", "--repeat"):
224 repeat = int(a)
225 if repeat <= 0:
226 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000227 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000228 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000229 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000230 timer = time.clock
Guido van Rossum0070f002003-03-15 12:25:00 +0000231 if o in ("-v", "--verbose"):
232 if verbose:
233 precision += 1
234 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000235 if o in ("-h", "--help"):
236 print __doc__,
237 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000238 setup = "\n".join(setup) or "pass"
Raymond Hettinger22952a32003-05-20 04:59:56 +0000239 # Include the current directory, so that local imports work (sys.path
240 # contains the directory of this script, rather than the current
241 # directory)
242 import os
243 sys.path.insert(0, os.curdir)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000244 t = Timer(stmt, setup, timer)
245 if number == 0:
246 # determine number so that 0.2 <= total time < 2.0
247 for i in range(1, 10):
248 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000249 try:
250 x = t.timeit(number)
251 except:
252 t.print_exc()
253 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000254 if verbose:
255 print "%d loops -> %.*g secs" % (number, precision, x)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000256 if x >= 0.2:
257 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000258 try:
259 r = t.repeat(repeat, number)
260 except:
261 t.print_exc()
262 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000263 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000264 if verbose:
265 print "raw times:", " ".join(["%.*g" % (precision, x) for x in r])
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000266 print "%d loops," % number,
267 usec = best * 1e6 / number
Guido van Rossum0070f002003-03-15 12:25:00 +0000268 print "best of %d: %.*g usec per loop" % (repeat, precision, usec)
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000269 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000270
271if __name__ == "__main__":
272 sys.exit(main())