blob: 9cec000f7397697404d769f0347656178226c1bf [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 Brandlc9d77b22012-05-01 11:56:22 +020012 python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-p] [-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')
Georg Brandlc9d77b22012-05-01 11:56:22 +020018 -p/--process: use time.process_time() (default is time.perf_counter())
19 -t/--time: use time.time() (deprecated)
20 -c/--clock: use time.clock() (deprecated)
Guido van Rossum0070f002003-03-15 12:25:00 +000021 -v/--verbose: print raw timing results; repeat for more digits precision
Guido van Rossume8577b72003-03-06 03:02:10 +000022 -h/--help: print this usage message and exit
Georg Brandl794f5b32010-08-01 08:52:32 +000023 --: separate options from statement, use when statement starts with -
Guido van Rossumb3f09d42003-03-05 23:31:58 +000024 statement: statement to be timed (default 'pass')
Guido van Rossumb7ab6002003-03-06 02:32:19 +000025
26A multi-line statement may be given by specifying each line as a
27separate argument; indented lines are possible by enclosing an
Guido van Rossum6e31aad2003-03-07 01:33:18 +000028argument in quotes and using leading spaces. Multiple -s options are
29treated similarly.
Guido van Rossumb7ab6002003-03-06 02:32:19 +000030
31If -n is not given, a suitable number of loops is calculated by trying
32successive powers of 10 until the total time is at least 0.2 seconds.
33
Guido van Rossume8577b72003-03-06 03:02:10 +000034Note: there is a certain baseline overhead associated with executing a
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040035pass statement. It differs between versions. The code here doesn't try
36to hide it, but you should be aware of it. The baseline overhead can be
37measured by invoking the program without arguments.
Guido van Rossum6e31aad2003-03-07 01:33:18 +000038
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040039Classes:
40
41 Timer
42
43Functions:
44
45 timeit(string, string) -> float
46 repeat(string, string) -> list
47 default_timer() -> float
48
Guido van Rossumb3f09d42003-03-05 23:31:58 +000049"""
50
Raymond Hettinger816ed1b2004-01-04 03:47:51 +000051import gc
Guido van Rossumb3f09d42003-03-05 23:31:58 +000052import sys
Guido van Rossumb3f09d42003-03-05 23:31:58 +000053import time
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040054import itertools
Guido van Rossumb3f09d42003-03-05 23:31:58 +000055
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040056__all__ = ["Timer", "timeit", "repeat", "default_timer"]
Guido van Rossumb3f09d42003-03-05 23:31:58 +000057
Guido van Rossum538f1d82003-03-14 17:21:00 +000058dummy_src_name = "<timeit-src>"
Guido van Rossumb3f09d42003-03-05 23:31:58 +000059default_number = 1000000
Guido van Rossum0070f002003-03-15 12:25:00 +000060default_repeat = 3
Victor Stinnerfe98e2f2012-04-29 03:01:20 +020061default_timer = time.perf_counter
Guido van Rossumb3f09d42003-03-05 23:31:58 +000062
Guido van Rossumb7ab6002003-03-06 02:32:19 +000063# Don't change the indentation of the template; the reindent() calls
64# in Timer.__init__() depend on setup being indented 4 spaces and stmt
65# being indented 8 spaces.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000066template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000067def inner(_it, _timer):
Raymond Hettingerc800af42011-04-04 09:28:25 -070068 {setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +000069 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000070 for _i in _it:
Raymond Hettingerc800af42011-04-04 09:28:25 -070071 {stmt}
Guido van Rossum538f1d82003-03-14 17:21:00 +000072 _t1 = _timer()
73 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000074"""
75
76def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000077 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000078 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000079
Guido van Rossumd8faa362007-04-27 19:54:29 +000080def _template_func(setup, func):
81 """Create a timer function. Used if the "statement" is a callable."""
Raymond Hettingerb646aa12009-04-03 02:45:36 +000082 def inner(_it, _timer, _func=func):
Guido van Rossumd8faa362007-04-27 19:54:29 +000083 setup()
84 _t0 = _timer()
85 for _i in _it:
Raymond Hettingerb646aa12009-04-03 02:45:36 +000086 _func()
Guido van Rossumd8faa362007-04-27 19:54:29 +000087 _t1 = _timer()
88 return _t1 - _t0
89 return inner
90
Guido van Rossumb3f09d42003-03-05 23:31:58 +000091class 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
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000110 ns = {}
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000111 if isinstance(stmt, str):
Serhiy Storchaka2bef5852015-01-26 12:09:17 +0200112 # Check that the code can be compiled outside a function
113 if isinstance(setup, str):
114 compile(setup, dummy_src_name, "exec")
115 compile(setup + '\n' + stmt, dummy_src_name, "exec")
116 else:
117 compile(stmt, dummy_src_name, "exec")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000118 stmt = reindent(stmt, 8)
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000119 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000120 setup = reindent(setup, 4)
Raymond Hettingerc800af42011-04-04 09:28:25 -0700121 src = template.format(stmt=stmt, setup=setup)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200122 elif callable(setup):
Raymond Hettingerc800af42011-04-04 09:28:25 -0700123 src = template.format(stmt=stmt, setup='_setup()')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000124 ns['_setup'] = setup
125 else:
126 raise ValueError("setup is neither a string nor callable")
127 self.src = src # Save for traceback display
128 code = compile(src, dummy_src_name, "exec")
129 exec(code, globals(), ns)
130 self.inner = ns["inner"]
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200131 elif callable(stmt):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000132 self.src = None
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000133 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000134 _setup = setup
135 def setup():
136 exec(_setup, globals(), ns)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200137 elif not callable(setup):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000138 raise ValueError("setup is neither a string nor callable")
139 self.inner = _template_func(setup, stmt)
140 else:
141 raise ValueError("stmt is neither a string nor callable")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000142
Guido van Rossum538f1d82003-03-14 17:21:00 +0000143 def print_exc(self, file=None):
144 """Helper to print a traceback from the timed code.
145
146 Typical use:
147
148 t = Timer(...) # outside the try/except
149 try:
150 t.timeit(...) # or t.repeat(...)
151 except:
152 t.print_exc()
153
154 The advantage over the standard traceback is that source lines
155 in the compiled template will be displayed.
156
157 The optional file argument directs where the traceback is
158 sent; it defaults to sys.stderr.
159 """
160 import linecache, traceback
Guido van Rossumd8faa362007-04-27 19:54:29 +0000161 if self.src is not None:
162 linecache.cache[dummy_src_name] = (len(self.src),
163 None,
164 self.src.split("\n"),
165 dummy_src_name)
166 # else the source is already stored somewhere else
167
Guido van Rossum538f1d82003-03-14 17:21:00 +0000168 traceback.print_exc(file=file)
169
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000170 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000171 """Time 'number' executions of the main statement.
172
173 To be precise, this executes the setup statement once, and
174 then returns the time it takes to execute the main statement
175 a number of times, as a float measured in seconds. The
176 argument is the number of times through the loop, defaulting
177 to one million. The main statement, the setup statement and
178 the timer function to be used are passed to the constructor.
179 """
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -0400180 it = itertools.repeat(None, number)
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000181 gcold = gc.isenabled()
182 gc.disable()
Raymond Hettinger3a081f52011-07-29 00:02:04 -0700183 try:
184 timing = self.inner(it, self.timer)
185 finally:
186 if gcold:
187 gc.enable()
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000188 return timing
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000189
190 def repeat(self, repeat=default_repeat, number=default_number):
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000191 """Call timeit() a few times.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000192
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000193 This is a convenience function that calls the timeit()
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000194 repeatedly, returning a list of results. The first argument
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000195 specifies how many times to call timeit(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000196 the second argument specifies the timer argument, defaulting
197 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000198
199 Note: it's tempting to calculate mean and standard deviation
200 from the result vector and report these. However, this is not
201 very useful. In a typical case, the lowest value gives a
202 lower bound for how fast your machine can run the given code
203 snippet; higher values in the result vector are typically not
204 caused by variability in Python's speed, but by other
205 processes interfering with your timing accuracy. So the min()
206 of the result is probably the only number you should be
207 interested in. After that, you should look at the entire
208 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000209 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000210 r = []
211 for i in range(repeat):
212 t = self.timeit(number)
213 r.append(t)
214 return r
215
Guido van Rossumd8faa362007-04-27 19:54:29 +0000216def timeit(stmt="pass", setup="pass", timer=default_timer,
217 number=default_number):
218 """Convenience function to create Timer object and call timeit method."""
219 return Timer(stmt, setup, timer).timeit(number)
220
221def repeat(stmt="pass", setup="pass", timer=default_timer,
222 repeat=default_repeat, number=default_number):
223 """Convenience function to create Timer object and call repeat method."""
224 return Timer(stmt, setup, timer).repeat(repeat, number)
225
R David Murraya88da672011-03-16 17:32:27 -0400226def main(args=None, *, _wrap_timer=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000227 """Main program, used when run as a script.
228
R David Murraya88da672011-03-16 17:32:27 -0400229 The optional 'args' argument specifies the command line to be parsed,
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000230 defaulting to sys.argv[1:].
231
232 The return value is an exit code to be passed to sys.exit(); it
233 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000234
235 When an exception happens during timing, a traceback is printed to
236 stderr and the return value is 1. Exceptions at other times
237 (including the template compilation) are not caught.
R David Murraya88da672011-03-16 17:32:27 -0400238
239 '_wrap_timer' is an internal interface used for unit testing. If it
240 is not None, it must be a callable that accepts a timer function
241 and returns another timer function (used for unit testing).
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000242 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000243 if args is None:
244 args = sys.argv[1:]
245 import getopt
246 try:
Georg Brandlc9d77b22012-05-01 11:56:22 +0200247 opts, args = getopt.getopt(args, "n:s:r:tcpvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000248 ["number=", "setup=", "repeat=",
Georg Brandlc9d77b22012-05-01 11:56:22 +0200249 "time", "clock", "process",
250 "verbose", "help"])
Guido van Rossumb940e112007-01-10 16:19:56 +0000251 except getopt.error as err:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000252 print(err)
253 print("use -h/--help for command line help")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000254 return 2
255 timer = default_timer
256 stmt = "\n".join(args) or "pass"
257 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000258 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000259 repeat = default_repeat
260 verbose = 0
261 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000262 for o, a in opts:
263 if o in ("-n", "--number"):
264 number = int(a)
265 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000266 setup.append(a)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000267 if o in ("-r", "--repeat"):
268 repeat = int(a)
269 if repeat <= 0:
270 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000271 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000272 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000273 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000274 timer = time.clock
Georg Brandlc9d77b22012-05-01 11:56:22 +0200275 if o in ("-p", "--process"):
276 timer = time.process_time
Guido van Rossum0070f002003-03-15 12:25:00 +0000277 if o in ("-v", "--verbose"):
278 if verbose:
279 precision += 1
280 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000281 if o in ("-h", "--help"):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000282 print(__doc__, end=' ')
Guido van Rossume8577b72003-03-06 03:02:10 +0000283 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000284 setup = "\n".join(setup) or "pass"
Raymond Hettinger22952a32003-05-20 04:59:56 +0000285 # Include the current directory, so that local imports work (sys.path
286 # contains the directory of this script, rather than the current
287 # directory)
288 import os
289 sys.path.insert(0, os.curdir)
R David Murraya88da672011-03-16 17:32:27 -0400290 if _wrap_timer is not None:
291 timer = _wrap_timer(timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000292 t = Timer(stmt, setup, timer)
293 if number == 0:
294 # determine number so that 0.2 <= total time < 2.0
295 for i in range(1, 10):
296 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000297 try:
298 x = t.timeit(number)
299 except:
300 t.print_exc()
301 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000302 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000303 print("%d loops -> %.*g secs" % (number, precision, x))
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000304 if x >= 0.2:
305 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000306 try:
307 r = t.repeat(repeat, number)
308 except:
309 t.print_exc()
310 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000311 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000312 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000313 print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
314 print("%d loops," % number, end=' ')
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000315 usec = best * 1e6 / number
Guido van Rossum57172082003-10-20 23:38:28 +0000316 if usec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000317 print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
Guido van Rossum57172082003-10-20 23:38:28 +0000318 else:
319 msec = usec / 1000
320 if msec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000321 print("best of %d: %.*g msec per loop" % (repeat, precision, msec))
Guido van Rossum57172082003-10-20 23:38:28 +0000322 else:
323 sec = msec / 1000
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000324 print("best of %d: %.*g sec per loop" % (repeat, precision, sec))
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000325 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000326
327if __name__ == "__main__":
328 sys.exit(main())