blob: b203c2c087d6763b624f1f15ceb490ee3c36ca46 [file] [log] [blame]
Guido van Rossum6e31aad2003-03-07 01:33:18 +00001"""Tool for measuring execution time of small code snippets.
Guido van Rossumb3f09d42003-03-05 23:31:58 +00002
Guido van Rossumb7ab6002003-03-06 02:32:19 +00003This module avoids a number of common traps for measuring execution
4times. See also Tim Peters' introduction to the Algorithms chapter in
5the Python Cookbook, published by O'Reilly.
Guido van Rossumb3f09d42003-03-05 23:31:58 +00006
Guido van Rossumb7ab6002003-03-06 02:32:19 +00007Library usage: see the Timer class.
Guido van Rossumb3f09d42003-03-05 23:31:58 +00008
9Command line usage:
Guido van Rossume8577b72003-03-06 03:02:10 +000010 python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement]
Guido van Rossumb3f09d42003-03-05 23:31:58 +000011
12Options:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000013 -n/--number N: how many times to execute 'statement' (default: see below)
Guido van Rossum0070f002003-03-15 12:25:00 +000014 -r/--repeat N: how many times to repeat the timer (default 3)
Guido van Rossum6e31aad2003-03-07 01:33:18 +000015 -s/--setup S: statement to be executed once initially (default 'pass')
Guido van Rossumb3f09d42003-03-05 23:31:58 +000016 -t/--time: use time.time() (default on Unix)
17 -c/--clock: use time.clock() (default on Windows)
Guido van Rossum0070f002003-03-15 12:25:00 +000018 -v/--verbose: print raw timing results; repeat for more digits precision
Guido van Rossume8577b72003-03-06 03:02:10 +000019 -h/--help: print this usage message and exit
Guido van Rossumb3f09d42003-03-05 23:31:58 +000020 statement: statement to be timed (default 'pass')
Guido van Rossumb7ab6002003-03-06 02:32:19 +000021
22A multi-line statement may be given by specifying each line as a
23separate argument; indented lines are possible by enclosing an
Guido van Rossum6e31aad2003-03-07 01:33:18 +000024argument in quotes and using leading spaces. Multiple -s options are
25treated similarly.
Guido van Rossumb7ab6002003-03-06 02:32:19 +000026
27If -n is not given, a suitable number of loops is calculated by trying
28successive powers of 10 until the total time is at least 0.2 seconds.
29
30The difference in default timer function is because on Windows,
31clock() has microsecond granularity but time()'s granularity is 1/60th
32of a second; on Unix, clock() has 1/100th of a second granularity and
33time() is much more precise. On either platform, the default timer
34functions measures wall clock time, not the CPU time. This means that
35other processes running on the same computer may interfere with the
36timing. The best thing to do when accurate timing is necessary is to
Guido van Rossum0070f002003-03-15 12:25:00 +000037repeat the timing a few times and use the best time. The -r option is
38good for this; the default of 3 repetitions is probably enough in most
39cases. On Unix, you can use clock() to measure CPU time.
Guido van Rossume8577b72003-03-06 03:02:10 +000040
41Note: there is a certain baseline overhead associated with executing a
42pass statement. The code here doesn't try to hide it, but you should
Guido van Rossum6e31aad2003-03-07 01:33:18 +000043be aware of it. The baseline overhead can be measured by invoking the
44program without arguments.
45
46The baseline overhead differs between Python versions! Also, to
47fairly compare older Python versions to Python 2.3, you may want to
48use python -O for the older versions to avoid timing SET_LINENO
49instructions.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000050"""
51
52import sys
53import math
54import time
Guido van Rossum6e31aad2003-03-07 01:33:18 +000055try:
56 import itertools
57except ImportError:
58 # Must be an older Python version (see timeit() below)
59 itertools = None
Guido van Rossumb3f09d42003-03-05 23:31:58 +000060
61__all__ = ["Timer"]
62
Guido van Rossum538f1d82003-03-14 17:21:00 +000063dummy_src_name = "<timeit-src>"
Guido van Rossumb3f09d42003-03-05 23:31:58 +000064default_number = 1000000
Guido van Rossum0070f002003-03-15 12:25:00 +000065default_repeat = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +000066
67if sys.platform == "win32":
68 # On Windows, the best timer is time.clock()
69 default_timer = time.clock
70else:
71 # On most other platforms the best timer is time.time()
72 default_timer = time.time
73
Guido van Rossumb7ab6002003-03-06 02:32:19 +000074# Don't change the indentation of the template; the reindent() calls
75# in Timer.__init__() depend on setup being indented 4 spaces and stmt
76# being indented 8 spaces.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000077template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000078def inner(_it, _timer):
Guido van Rossumb3f09d42003-03-05 23:31:58 +000079 %(setup)s
Guido van Rossum538f1d82003-03-14 17:21:00 +000080 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000081 for _i in _it:
Guido van Rossumb3f09d42003-03-05 23:31:58 +000082 %(stmt)s
Guido van Rossum538f1d82003-03-14 17:21:00 +000083 _t1 = _timer()
84 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000085"""
86
87def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000088 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000089 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000090
91class Timer:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000092 """Class for timing execution speed of small code snippets.
93
94 The constructor takes a statement to be timed, an additional
95 statement used for setup, and a timer function. Both statements
96 default to 'pass'; the timer function is platform-dependent (see
97 module doc string).
98
99 To measure the execution time of the first statement, use the
100 timeit() method. The repeat() method is a convenience to call
101 timeit() multiple times and return a list of results.
102
103 The statements may contain newlines, as long as they don't contain
104 multi-line string literals.
105 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000106
107 def __init__(self, stmt="pass", setup="pass", timer=default_timer):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000108 """Constructor. See class doc string."""
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000109 self.timer = timer
110 stmt = reindent(stmt, 8)
111 setup = reindent(setup, 4)
112 src = template % {'stmt': stmt, 'setup': setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +0000113 self.src = src # Save for traceback display
114 code = compile(src, dummy_src_name, "exec")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000115 ns = {}
116 exec code in globals(), ns
117 self.inner = ns["inner"]
118
Guido van Rossum538f1d82003-03-14 17:21:00 +0000119 def print_exc(self, file=None):
120 """Helper to print a traceback from the timed code.
121
122 Typical use:
123
124 t = Timer(...) # outside the try/except
125 try:
126 t.timeit(...) # or t.repeat(...)
127 except:
128 t.print_exc()
129
130 The advantage over the standard traceback is that source lines
131 in the compiled template will be displayed.
132
133 The optional file argument directs where the traceback is
134 sent; it defaults to sys.stderr.
135 """
136 import linecache, traceback
137 linecache.cache[dummy_src_name] = (len(self.src),
138 None,
139 self.src.split("\n"),
140 dummy_src_name)
141 traceback.print_exc(file=file)
142
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000143 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000144 """Time 'number' executions of the main statement.
145
146 To be precise, this executes the setup statement once, and
147 then returns the time it takes to execute the main statement
148 a number of times, as a float measured in seconds. The
149 argument is the number of times through the loop, defaulting
150 to one million. The main statement, the setup statement and
151 the timer function to be used are passed to the constructor.
152 """
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000153 if itertools:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000154 it = itertools.repeat(None, number)
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000155 else:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000156 it = [None] * number
157 return self.inner(it, self.timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000158
159 def repeat(self, repeat=default_repeat, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000160 """Call timer() a few times.
161
162 This is a convenience function that calls the timer()
163 repeatedly, returning a list of results. The first argument
Guido van Rossum0070f002003-03-15 12:25:00 +0000164 specifies how many times to call timer(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000165 the second argument specifies the timer argument, defaulting
166 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000167
168 Note: it's tempting to calculate mean and standard deviation
169 from the result vector and report these. However, this is not
170 very useful. In a typical case, the lowest value gives a
171 lower bound for how fast your machine can run the given code
172 snippet; higher values in the result vector are typically not
173 caused by variability in Python's speed, but by other
174 processes interfering with your timing accuracy. So the min()
175 of the result is probably the only number you should be
176 interested in. After that, you should look at the entire
177 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000178 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000179 r = []
180 for i in range(repeat):
181 t = self.timeit(number)
182 r.append(t)
183 return r
184
185def main(args=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000186 """Main program, used when run as a script.
187
188 The optional argument specifies the command line to be parsed,
189 defaulting to sys.argv[1:].
190
191 The return value is an exit code to be passed to sys.exit(); it
192 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000193
194 When an exception happens during timing, a traceback is printed to
195 stderr and the return value is 1. Exceptions at other times
196 (including the template compilation) are not caught.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000197 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000198 if args is None:
199 args = sys.argv[1:]
200 import getopt
201 try:
Guido van Rossum0070f002003-03-15 12:25:00 +0000202 opts, args = getopt.getopt(args, "n:s:r:tcvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000203 ["number=", "setup=", "repeat=",
Guido van Rossum0070f002003-03-15 12:25:00 +0000204 "time", "clock", "verbose", "help"])
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000205 except getopt.error, err:
206 print err
Guido van Rossume8577b72003-03-06 03:02:10 +0000207 print "use -h/--help for command line help"
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000208 return 2
209 timer = default_timer
210 stmt = "\n".join(args) or "pass"
211 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000212 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000213 repeat = default_repeat
214 verbose = 0
215 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000216 for o, a in opts:
217 if o in ("-n", "--number"):
218 number = int(a)
219 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000220 setup.append(a)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000221 if o in ("-r", "--repeat"):
222 repeat = int(a)
223 if repeat <= 0:
224 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000225 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000226 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000227 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000228 timer = time.clock
Guido van Rossum0070f002003-03-15 12:25:00 +0000229 if o in ("-v", "--verbose"):
230 if verbose:
231 precision += 1
232 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000233 if o in ("-h", "--help"):
234 print __doc__,
235 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000236 setup = "\n".join(setup) or "pass"
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000237 t = Timer(stmt, setup, timer)
238 if number == 0:
239 # determine number so that 0.2 <= total time < 2.0
240 for i in range(1, 10):
241 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000242 try:
243 x = t.timeit(number)
244 except:
245 t.print_exc()
246 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000247 if verbose:
248 print "%d loops -> %.*g secs" % (number, precision, x)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000249 if x >= 0.2:
250 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000251 try:
252 r = t.repeat(repeat, number)
253 except:
254 t.print_exc()
255 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000256 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000257 if verbose:
258 print "raw times:", " ".join(["%.*g" % (precision, x) for x in r])
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000259 print "%d loops," % number,
260 usec = best * 1e6 / number
Guido van Rossum0070f002003-03-15 12:25:00 +0000261 print "best of %d: %.*g usec per loop" % (repeat, precision, usec)
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000262 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000263
264if __name__ == "__main__":
265 sys.exit(main())