blob: caa7da3391e26497d2d4e249a181ab5a77baecc2 [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
Robert Collins302dbc62015-03-18 09:54:50 +130022 -u/--unit: set the output time unit (usec, msec, or sec)
Guido van Rossume8577b72003-03-06 03:02:10 +000023 -h/--help: print this usage message and exit
Georg Brandl794f5b32010-08-01 08:52:32 +000024 --: separate options from statement, use when statement starts with -
Guido van Rossumb3f09d42003-03-05 23:31:58 +000025 statement: statement to be timed (default 'pass')
Guido van Rossumb7ab6002003-03-06 02:32:19 +000026
27A multi-line statement may be given by specifying each line as a
28separate argument; indented lines are possible by enclosing an
Guido van Rossum6e31aad2003-03-07 01:33:18 +000029argument in quotes and using leading spaces. Multiple -s options are
30treated similarly.
Guido van Rossumb7ab6002003-03-06 02:32:19 +000031
32If -n is not given, a suitable number of loops is calculated by trying
33successive powers of 10 until the total time is at least 0.2 seconds.
34
Guido van Rossume8577b72003-03-06 03:02:10 +000035Note: there is a certain baseline overhead associated with executing a
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040036pass statement. It differs between versions. The code here doesn't try
37to hide it, but you should be aware of it. The baseline overhead can be
38measured by invoking the program without arguments.
Guido van Rossum6e31aad2003-03-07 01:33:18 +000039
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040040Classes:
41
42 Timer
43
44Functions:
45
46 timeit(string, string) -> float
47 repeat(string, string) -> list
48 default_timer() -> float
49
Guido van Rossumb3f09d42003-03-05 23:31:58 +000050"""
51
Raymond Hettinger816ed1b2004-01-04 03:47:51 +000052import gc
Guido van Rossumb3f09d42003-03-05 23:31:58 +000053import sys
Guido van Rossumb3f09d42003-03-05 23:31:58 +000054import time
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040055import itertools
Guido van Rossumb3f09d42003-03-05 23:31:58 +000056
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -040057__all__ = ["Timer", "timeit", "repeat", "default_timer"]
Guido van Rossumb3f09d42003-03-05 23:31:58 +000058
Guido van Rossum538f1d82003-03-14 17:21:00 +000059dummy_src_name = "<timeit-src>"
Guido van Rossumb3f09d42003-03-05 23:31:58 +000060default_number = 1000000
Guido van Rossum0070f002003-03-15 12:25:00 +000061default_repeat = 3
Victor Stinnerfe98e2f2012-04-29 03:01:20 +020062default_timer = time.perf_counter
Guido van Rossumb3f09d42003-03-05 23:31:58 +000063
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -040064_globals = globals
65
Guido van Rossumb7ab6002003-03-06 02:32:19 +000066# Don't change the indentation of the template; the reindent() calls
67# in Timer.__init__() depend on setup being indented 4 spaces and stmt
68# being indented 8 spaces.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000069template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000070def inner(_it, _timer):
Raymond Hettingerc800af42011-04-04 09:28:25 -070071 {setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +000072 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000073 for _i in _it:
Raymond Hettingerc800af42011-04-04 09:28:25 -070074 {stmt}
Guido van Rossum538f1d82003-03-14 17:21:00 +000075 _t1 = _timer()
76 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000077"""
78
79def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000080 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000081 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000082
Guido van Rossumd8faa362007-04-27 19:54:29 +000083def _template_func(setup, func):
84 """Create a timer function. Used if the "statement" is a callable."""
Raymond Hettingerb646aa12009-04-03 02:45:36 +000085 def inner(_it, _timer, _func=func):
Guido van Rossumd8faa362007-04-27 19:54:29 +000086 setup()
87 _t0 = _timer()
88 for _i in _it:
Raymond Hettingerb646aa12009-04-03 02:45:36 +000089 _func()
Guido van Rossumd8faa362007-04-27 19:54:29 +000090 _t1 = _timer()
91 return _t1 - _t0
92 return inner
93
Guido van Rossumb3f09d42003-03-05 23:31:58 +000094class Timer:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000095 """Class for timing execution speed of small code snippets.
96
97 The constructor takes a statement to be timed, an additional
98 statement used for setup, and a timer function. Both statements
99 default to 'pass'; the timer function is platform-dependent (see
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400100 module doc string). If 'globals' is specified, the code will be
101 executed within that namespace (as opposed to inside timeit's
102 namespace).
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000103
104 To measure the execution time of the first statement, use the
105 timeit() method. The repeat() method is a convenience to call
106 timeit() multiple times and return a list of results.
107
108 The statements may contain newlines, as long as they don't contain
109 multi-line string literals.
110 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000111
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400112 def __init__(self, stmt="pass", setup="pass", timer=default_timer,
113 globals=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000114 """Constructor. See class doc string."""
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000115 self.timer = timer
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400116 local_ns = {}
117 global_ns = _globals() if globals is None else globals
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000118 if isinstance(stmt, str):
Serhiy Storchaka2bef5852015-01-26 12:09:17 +0200119 # Check that the code can be compiled outside a function
120 if isinstance(setup, str):
121 compile(setup, dummy_src_name, "exec")
122 compile(setup + '\n' + stmt, dummy_src_name, "exec")
123 else:
124 compile(stmt, dummy_src_name, "exec")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000125 stmt = reindent(stmt, 8)
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000126 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000127 setup = reindent(setup, 4)
Raymond Hettingerc800af42011-04-04 09:28:25 -0700128 src = template.format(stmt=stmt, setup=setup)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200129 elif callable(setup):
Raymond Hettingerc800af42011-04-04 09:28:25 -0700130 src = template.format(stmt=stmt, setup='_setup()')
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400131 local_ns['_setup'] = setup
Guido van Rossumd8faa362007-04-27 19:54:29 +0000132 else:
133 raise ValueError("setup is neither a string nor callable")
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400134 self.src = src # Save for traceback display
Guido van Rossumd8faa362007-04-27 19:54:29 +0000135 code = compile(src, dummy_src_name, "exec")
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400136 exec(code, global_ns, local_ns)
137 self.inner = local_ns["inner"]
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200138 elif callable(stmt):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139 self.src = None
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000140 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000141 _setup = setup
142 def setup():
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400143 exec(_setup, global_ns, local_ns)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200144 elif not callable(setup):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000145 raise ValueError("setup is neither a string nor callable")
146 self.inner = _template_func(setup, stmt)
147 else:
148 raise ValueError("stmt is neither a string nor callable")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000149
Guido van Rossum538f1d82003-03-14 17:21:00 +0000150 def print_exc(self, file=None):
151 """Helper to print a traceback from the timed code.
152
153 Typical use:
154
155 t = Timer(...) # outside the try/except
156 try:
157 t.timeit(...) # or t.repeat(...)
158 except:
159 t.print_exc()
160
161 The advantage over the standard traceback is that source lines
162 in the compiled template will be displayed.
163
164 The optional file argument directs where the traceback is
165 sent; it defaults to sys.stderr.
166 """
167 import linecache, traceback
Guido van Rossumd8faa362007-04-27 19:54:29 +0000168 if self.src is not None:
169 linecache.cache[dummy_src_name] = (len(self.src),
170 None,
171 self.src.split("\n"),
172 dummy_src_name)
173 # else the source is already stored somewhere else
174
Guido van Rossum538f1d82003-03-14 17:21:00 +0000175 traceback.print_exc(file=file)
176
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000177 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000178 """Time 'number' executions of the main statement.
179
180 To be precise, this executes the setup statement once, and
181 then returns the time it takes to execute the main statement
182 a number of times, as a float measured in seconds. The
183 argument is the number of times through the loop, defaulting
184 to one million. The main statement, the setup statement and
185 the timer function to be used are passed to the constructor.
186 """
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -0400187 it = itertools.repeat(None, number)
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000188 gcold = gc.isenabled()
189 gc.disable()
Raymond Hettinger3a081f52011-07-29 00:02:04 -0700190 try:
191 timing = self.inner(it, self.timer)
192 finally:
193 if gcold:
194 gc.enable()
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000195 return timing
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000196
197 def repeat(self, repeat=default_repeat, number=default_number):
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000198 """Call timeit() a few times.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000199
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000200 This is a convenience function that calls the timeit()
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000201 repeatedly, returning a list of results. The first argument
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000202 specifies how many times to call timeit(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000203 the second argument specifies the timer argument, defaulting
204 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000205
206 Note: it's tempting to calculate mean and standard deviation
207 from the result vector and report these. However, this is not
208 very useful. In a typical case, the lowest value gives a
209 lower bound for how fast your machine can run the given code
210 snippet; higher values in the result vector are typically not
211 caused by variability in Python's speed, but by other
212 processes interfering with your timing accuracy. So the min()
213 of the result is probably the only number you should be
214 interested in. After that, you should look at the entire
215 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000216 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000217 r = []
218 for i in range(repeat):
219 t = self.timeit(number)
220 r.append(t)
221 return r
222
Guido van Rossumd8faa362007-04-27 19:54:29 +0000223def timeit(stmt="pass", setup="pass", timer=default_timer,
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400224 number=default_number, globals=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000225 """Convenience function to create Timer object and call timeit method."""
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400226 return Timer(stmt, setup, timer, globals).timeit(number)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000227
228def repeat(stmt="pass", setup="pass", timer=default_timer,
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400229 repeat=default_repeat, number=default_number, globals=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000230 """Convenience function to create Timer object and call repeat method."""
Antoine Pitrouef3b9ed2014-08-22 23:13:50 -0400231 return Timer(stmt, setup, timer, globals).repeat(repeat, number)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000232
R David Murraya88da672011-03-16 17:32:27 -0400233def main(args=None, *, _wrap_timer=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000234 """Main program, used when run as a script.
235
R David Murraya88da672011-03-16 17:32:27 -0400236 The optional 'args' argument specifies the command line to be parsed,
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000237 defaulting to sys.argv[1:].
238
239 The return value is an exit code to be passed to sys.exit(); it
240 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000241
242 When an exception happens during timing, a traceback is printed to
243 stderr and the return value is 1. Exceptions at other times
244 (including the template compilation) are not caught.
R David Murraya88da672011-03-16 17:32:27 -0400245
246 '_wrap_timer' is an internal interface used for unit testing. If it
247 is not None, it must be a callable that accepts a timer function
248 and returns another timer function (used for unit testing).
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000249 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000250 if args is None:
251 args = sys.argv[1:]
252 import getopt
253 try:
Robert Collins302dbc62015-03-18 09:54:50 +1300254 opts, args = getopt.getopt(args, "n:u:s:r:tcpvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000255 ["number=", "setup=", "repeat=",
Georg Brandlc9d77b22012-05-01 11:56:22 +0200256 "time", "clock", "process",
Robert Collins302dbc62015-03-18 09:54:50 +1300257 "verbose", "unit=", "help"])
Guido van Rossumb940e112007-01-10 16:19:56 +0000258 except getopt.error as err:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000259 print(err)
260 print("use -h/--help for command line help")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000261 return 2
262 timer = default_timer
263 stmt = "\n".join(args) or "pass"
264 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000265 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000266 repeat = default_repeat
267 verbose = 0
Robert Collins302dbc62015-03-18 09:54:50 +1300268 time_unit = None
269 units = {"usec": 1, "msec": 1e3, "sec": 1e6}
Guido van Rossum0070f002003-03-15 12:25:00 +0000270 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000271 for o, a in opts:
272 if o in ("-n", "--number"):
273 number = int(a)
274 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000275 setup.append(a)
Robert Collins302dbc62015-03-18 09:54:50 +1300276 if o in ("-u", "--unit"):
277 if a in units:
278 time_unit = a
279 else:
280 print("Unrecognized unit. Please select usec, msec, or sec.",
281 file=sys.stderr)
282 return 2
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000283 if o in ("-r", "--repeat"):
284 repeat = int(a)
285 if repeat <= 0:
286 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000287 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000288 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000289 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000290 timer = time.clock
Georg Brandlc9d77b22012-05-01 11:56:22 +0200291 if o in ("-p", "--process"):
292 timer = time.process_time
Guido van Rossum0070f002003-03-15 12:25:00 +0000293 if o in ("-v", "--verbose"):
294 if verbose:
295 precision += 1
296 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000297 if o in ("-h", "--help"):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000298 print(__doc__, end=' ')
Guido van Rossume8577b72003-03-06 03:02:10 +0000299 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000300 setup = "\n".join(setup) or "pass"
Raymond Hettinger22952a32003-05-20 04:59:56 +0000301 # Include the current directory, so that local imports work (sys.path
302 # contains the directory of this script, rather than the current
303 # directory)
304 import os
305 sys.path.insert(0, os.curdir)
R David Murraya88da672011-03-16 17:32:27 -0400306 if _wrap_timer is not None:
307 timer = _wrap_timer(timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000308 t = Timer(stmt, setup, timer)
309 if number == 0:
310 # determine number so that 0.2 <= total time < 2.0
311 for i in range(1, 10):
312 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000313 try:
314 x = t.timeit(number)
315 except:
316 t.print_exc()
317 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000318 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000319 print("%d loops -> %.*g secs" % (number, precision, x))
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000320 if x >= 0.2:
321 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000322 try:
323 r = t.repeat(repeat, number)
324 except:
325 t.print_exc()
326 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000327 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000328 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000329 print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
330 print("%d loops," % number, end=' ')
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000331 usec = best * 1e6 / number
Robert Collins302dbc62015-03-18 09:54:50 +1300332 if time_unit is not None:
333 print("best of %d: %.*g %s per loop" % (repeat, precision,
334 usec/units[time_unit], time_unit))
Guido van Rossum57172082003-10-20 23:38:28 +0000335 else:
Robert Collins302dbc62015-03-18 09:54:50 +1300336 if usec < 1000:
337 print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
Guido van Rossum57172082003-10-20 23:38:28 +0000338 else:
Robert Collins302dbc62015-03-18 09:54:50 +1300339 msec = usec / 1000
340 if msec < 1000:
341 print("best of %d: %.*g msec per loop" % (repeat,
342 precision, msec))
343 else:
344 sec = msec / 1000
345 print("best of %d: %.*g sec per loop" % (repeat,
346 precision, sec))
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000347 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000348
349if __name__ == "__main__":
350 sys.exit(main())