blob: 5efe4f9ab425eb0e00ebac6a716792dd7cba5421 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
Skip Montanarocfd55502003-04-08 19:49:40 +00002
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:
Georg Brandl794f5b32010-08-01 08:52:32 +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')
Victor Stinnerfe98e2f2012-04-29 03:01:20 +020018 -t/--time: use time.time()
19 -c/--clock: use time.clock()
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
Georg Brandl794f5b32010-08-01 08:52:32 +000022 --: separate options from statement, use when statement starts with -
Guido van Rossumb3f09d42003-03-05 23:31:58 +000023 statement: statement to be timed (default 'pass')
Guido van Rossumb7ab6002003-03-06 02:32:19 +000024
25A multi-line statement may be given by specifying each line as a
26separate argument; indented lines are possible by enclosing an
Guido van Rossum6e31aad2003-03-07 01:33:18 +000027argument in quotes and using leading spaces. Multiple -s options are
28treated similarly.
Guido van Rossumb7ab6002003-03-06 02:32:19 +000029
30If -n is not given, a suitable number of loops is calculated by trying
31successive powers of 10 until the total time is at least 0.2 seconds.
32
33The difference in default timer function is because on Windows,
34clock() has microsecond granularity but time()'s granularity is 1/60th
35of a second; on Unix, clock() has 1/100th of a second granularity and
36time() is much more precise. On either platform, the default timer
Martin v. Löwis7bdc4842003-09-20 11:09:28 +000037functions measure wall clock time, not the CPU time. This means that
Guido van Rossumb7ab6002003-03-06 02:32:19 +000038other processes running on the same computer may interfere with the
39timing. The best thing to do when accurate timing is necessary is to
Guido van Rossum0070f002003-03-15 12:25:00 +000040repeat the timing a few times and use the best time. The -r option is
41good for this; the default of 3 repetitions is probably enough in most
42cases. On Unix, you can use clock() to measure CPU time.
Guido van Rossume8577b72003-03-06 03:02:10 +000043
44Note: there is a certain baseline overhead associated with executing a
45pass statement. The code here doesn't try to hide it, but you should
Guido van Rossum6e31aad2003-03-07 01:33:18 +000046be aware of it. The baseline overhead can be measured by invoking the
47program without arguments.
48
49The baseline overhead differs between Python versions! Also, to
50fairly compare older Python versions to Python 2.3, you may want to
51use python -O for the older versions to avoid timing SET_LINENO
52instructions.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000053"""
54
Raymond Hettinger816ed1b2004-01-04 03:47:51 +000055import gc
Guido van Rossumb3f09d42003-03-05 23:31:58 +000056import sys
Guido van Rossumb3f09d42003-03-05 23:31:58 +000057import time
Guido van Rossum6e31aad2003-03-07 01:33:18 +000058try:
59 import itertools
60except ImportError:
61 # Must be an older Python version (see timeit() below)
62 itertools = None
Guido van Rossumb3f09d42003-03-05 23:31:58 +000063
64__all__ = ["Timer"]
65
Guido van Rossum538f1d82003-03-14 17:21:00 +000066dummy_src_name = "<timeit-src>"
Guido van Rossumb3f09d42003-03-05 23:31:58 +000067default_number = 1000000
Guido van Rossum0070f002003-03-15 12:25:00 +000068default_repeat = 3
Victor Stinnerfe98e2f2012-04-29 03:01:20 +020069default_timer = time.perf_counter
Guido van Rossumb3f09d42003-03-05 23:31:58 +000070
Guido van Rossumb7ab6002003-03-06 02:32:19 +000071# Don't change the indentation of the template; the reindent() calls
72# in Timer.__init__() depend on setup being indented 4 spaces and stmt
73# being indented 8 spaces.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000074template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000075def inner(_it, _timer):
Raymond Hettingerc800af42011-04-04 09:28:25 -070076 {setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +000077 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000078 for _i in _it:
Raymond Hettingerc800af42011-04-04 09:28:25 -070079 {stmt}
Guido van Rossum538f1d82003-03-14 17:21:00 +000080 _t1 = _timer()
81 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000082"""
83
84def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000085 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000086 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000087
Guido van Rossumd8faa362007-04-27 19:54:29 +000088def _template_func(setup, func):
89 """Create a timer function. Used if the "statement" is a callable."""
Raymond Hettingerb646aa12009-04-03 02:45:36 +000090 def inner(_it, _timer, _func=func):
Guido van Rossumd8faa362007-04-27 19:54:29 +000091 setup()
92 _t0 = _timer()
93 for _i in _it:
Raymond Hettingerb646aa12009-04-03 02:45:36 +000094 _func()
Guido van Rossumd8faa362007-04-27 19:54:29 +000095 _t1 = _timer()
96 return _t1 - _t0
97 return inner
98
Guido van Rossumb3f09d42003-03-05 23:31:58 +000099class Timer:
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000100 """Class for timing execution speed of small code snippets.
101
102 The constructor takes a statement to be timed, an additional
103 statement used for setup, and a timer function. Both statements
104 default to 'pass'; the timer function is platform-dependent (see
105 module doc string).
106
107 To measure the execution time of the first statement, use the
108 timeit() method. The repeat() method is a convenience to call
109 timeit() multiple times and return a list of results.
110
111 The statements may contain newlines, as long as they don't contain
112 multi-line string literals.
113 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000114
115 def __init__(self, stmt="pass", setup="pass", timer=default_timer):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000116 """Constructor. See class doc string."""
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000117 self.timer = timer
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000118 ns = {}
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000119 if isinstance(stmt, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000120 stmt = reindent(stmt, 8)
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000121 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000122 setup = reindent(setup, 4)
Raymond Hettingerc800af42011-04-04 09:28:25 -0700123 src = template.format(stmt=stmt, setup=setup)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200124 elif callable(setup):
Raymond Hettingerc800af42011-04-04 09:28:25 -0700125 src = template.format(stmt=stmt, setup='_setup()')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000126 ns['_setup'] = setup
127 else:
128 raise ValueError("setup is neither a string nor callable")
129 self.src = src # Save for traceback display
130 code = compile(src, dummy_src_name, "exec")
131 exec(code, globals(), ns)
132 self.inner = ns["inner"]
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200133 elif callable(stmt):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000134 self.src = None
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000135 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000136 _setup = setup
137 def setup():
138 exec(_setup, globals(), ns)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200139 elif not callable(setup):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000140 raise ValueError("setup is neither a string nor callable")
141 self.inner = _template_func(setup, stmt)
142 else:
143 raise ValueError("stmt is neither a string nor callable")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000144
Guido van Rossum538f1d82003-03-14 17:21:00 +0000145 def print_exc(self, file=None):
146 """Helper to print a traceback from the timed code.
147
148 Typical use:
149
150 t = Timer(...) # outside the try/except
151 try:
152 t.timeit(...) # or t.repeat(...)
153 except:
154 t.print_exc()
155
156 The advantage over the standard traceback is that source lines
157 in the compiled template will be displayed.
158
159 The optional file argument directs where the traceback is
160 sent; it defaults to sys.stderr.
161 """
162 import linecache, traceback
Guido van Rossumd8faa362007-04-27 19:54:29 +0000163 if self.src is not None:
164 linecache.cache[dummy_src_name] = (len(self.src),
165 None,
166 self.src.split("\n"),
167 dummy_src_name)
168 # else the source is already stored somewhere else
169
Guido van Rossum538f1d82003-03-14 17:21:00 +0000170 traceback.print_exc(file=file)
171
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000172 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000173 """Time 'number' executions of the main statement.
174
175 To be precise, this executes the setup statement once, and
176 then returns the time it takes to execute the main statement
177 a number of times, as a float measured in seconds. The
178 argument is the number of times through the loop, defaulting
179 to one million. The main statement, the setup statement and
180 the timer function to be used are passed to the constructor.
181 """
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000182 if itertools:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000183 it = itertools.repeat(None, number)
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000184 else:
Guido van Rossumdd42edc2003-03-21 14:54:19 +0000185 it = [None] * number
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000186 gcold = gc.isenabled()
187 gc.disable()
Raymond Hettinger3a081f52011-07-29 00:02:04 -0700188 try:
189 timing = self.inner(it, self.timer)
190 finally:
191 if gcold:
192 gc.enable()
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000193 return timing
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000194
195 def repeat(self, repeat=default_repeat, number=default_number):
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000196 """Call timeit() a few times.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000197
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000198 This is a convenience function that calls the timeit()
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000199 repeatedly, returning a list of results. The first argument
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000200 specifies how many times to call timeit(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000201 the second argument specifies the timer argument, defaulting
202 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000203
204 Note: it's tempting to calculate mean and standard deviation
205 from the result vector and report these. However, this is not
206 very useful. In a typical case, the lowest value gives a
207 lower bound for how fast your machine can run the given code
208 snippet; higher values in the result vector are typically not
209 caused by variability in Python's speed, but by other
210 processes interfering with your timing accuracy. So the min()
211 of the result is probably the only number you should be
212 interested in. After that, you should look at the entire
213 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000214 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000215 r = []
216 for i in range(repeat):
217 t = self.timeit(number)
218 r.append(t)
219 return r
220
Guido van Rossumd8faa362007-04-27 19:54:29 +0000221def timeit(stmt="pass", setup="pass", timer=default_timer,
222 number=default_number):
223 """Convenience function to create Timer object and call timeit method."""
224 return Timer(stmt, setup, timer).timeit(number)
225
226def repeat(stmt="pass", setup="pass", timer=default_timer,
227 repeat=default_repeat, number=default_number):
228 """Convenience function to create Timer object and call repeat method."""
229 return Timer(stmt, setup, timer).repeat(repeat, number)
230
R David Murraya88da672011-03-16 17:32:27 -0400231def main(args=None, *, _wrap_timer=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000232 """Main program, used when run as a script.
233
R David Murraya88da672011-03-16 17:32:27 -0400234 The optional 'args' argument specifies the command line to be parsed,
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000235 defaulting to sys.argv[1:].
236
237 The return value is an exit code to be passed to sys.exit(); it
238 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000239
240 When an exception happens during timing, a traceback is printed to
241 stderr and the return value is 1. Exceptions at other times
242 (including the template compilation) are not caught.
R David Murraya88da672011-03-16 17:32:27 -0400243
244 '_wrap_timer' is an internal interface used for unit testing. If it
245 is not None, it must be a callable that accepts a timer function
246 and returns another timer function (used for unit testing).
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000247 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000248 if args is None:
249 args = sys.argv[1:]
250 import getopt
251 try:
Guido van Rossum0070f002003-03-15 12:25:00 +0000252 opts, args = getopt.getopt(args, "n:s:r:tcvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000253 ["number=", "setup=", "repeat=",
Guido van Rossum0070f002003-03-15 12:25:00 +0000254 "time", "clock", "verbose", "help"])
Guido van Rossumb940e112007-01-10 16:19:56 +0000255 except getopt.error as err:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000256 print(err)
257 print("use -h/--help for command line help")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000258 return 2
259 timer = default_timer
260 stmt = "\n".join(args) or "pass"
261 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000262 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000263 repeat = default_repeat
264 verbose = 0
265 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000266 for o, a in opts:
267 if o in ("-n", "--number"):
268 number = int(a)
269 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000270 setup.append(a)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000271 if o in ("-r", "--repeat"):
272 repeat = int(a)
273 if repeat <= 0:
274 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000275 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000276 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000277 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000278 timer = time.clock
Guido van Rossum0070f002003-03-15 12:25:00 +0000279 if o in ("-v", "--verbose"):
280 if verbose:
281 precision += 1
282 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000283 if o in ("-h", "--help"):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000284 print(__doc__, end=' ')
Guido van Rossume8577b72003-03-06 03:02:10 +0000285 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000286 setup = "\n".join(setup) or "pass"
Raymond Hettinger22952a32003-05-20 04:59:56 +0000287 # Include the current directory, so that local imports work (sys.path
288 # contains the directory of this script, rather than the current
289 # directory)
290 import os
291 sys.path.insert(0, os.curdir)
R David Murraya88da672011-03-16 17:32:27 -0400292 if _wrap_timer is not None:
293 timer = _wrap_timer(timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000294 t = Timer(stmt, setup, timer)
295 if number == 0:
296 # determine number so that 0.2 <= total time < 2.0
297 for i in range(1, 10):
298 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000299 try:
300 x = t.timeit(number)
301 except:
302 t.print_exc()
303 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000304 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000305 print("%d loops -> %.*g secs" % (number, precision, x))
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000306 if x >= 0.2:
307 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000308 try:
309 r = t.repeat(repeat, number)
310 except:
311 t.print_exc()
312 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000313 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000314 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000315 print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
316 print("%d loops," % number, end=' ')
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000317 usec = best * 1e6 / number
Guido van Rossum57172082003-10-20 23:38:28 +0000318 if usec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000319 print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
Guido van Rossum57172082003-10-20 23:38:28 +0000320 else:
321 msec = usec / 1000
322 if msec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000323 print("best of %d: %.*g msec per loop" % (repeat, precision, msec))
Guido van Rossum57172082003-10-20 23:38:28 +0000324 else:
325 sec = msec / 1000
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000326 print("best of %d: %.*g sec per loop" % (repeat, precision, sec))
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000327 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000328
329if __name__ == "__main__":
330 sys.exit(main())