blob: cf7446d8c1f50ef93a63c6c59cb6ec7630b4cdfe [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)
Andrew Kuchling333518e2015-04-21 19:43:33 -040017 -s/--setup S: statement to be executed once initially (default 'pass').
18 Execution time of this setup statement is NOT timed.
Georg Brandlc9d77b22012-05-01 11:56:22 +020019 -p/--process: use time.process_time() (default is time.perf_counter())
20 -t/--time: use time.time() (deprecated)
21 -c/--clock: use time.clock() (deprecated)
Guido van Rossum0070f002003-03-15 12:25:00 +000022 -v/--verbose: print raw timing results; repeat for more digits precision
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
Guido van Rossumb7ab6002003-03-06 02:32:19 +000064# Don't change the indentation of the template; the reindent() calls
65# in Timer.__init__() depend on setup being indented 4 spaces and stmt
66# being indented 8 spaces.
Guido van Rossumb3f09d42003-03-05 23:31:58 +000067template = """
Guido van Rossumdd42edc2003-03-21 14:54:19 +000068def inner(_it, _timer):
Raymond Hettingerc800af42011-04-04 09:28:25 -070069 {setup}
Guido van Rossum538f1d82003-03-14 17:21:00 +000070 _t0 = _timer()
Guido van Rossumdd42edc2003-03-21 14:54:19 +000071 for _i in _it:
Raymond Hettingerc800af42011-04-04 09:28:25 -070072 {stmt}
Guido van Rossum538f1d82003-03-14 17:21:00 +000073 _t1 = _timer()
74 return _t1 - _t0
Guido van Rossumb3f09d42003-03-05 23:31:58 +000075"""
76
77def reindent(src, indent):
Guido van Rossumb7ab6002003-03-06 02:32:19 +000078 """Helper to reindent a multi-line statement."""
Guido van Rossume05dcce2003-03-06 13:09:09 +000079 return src.replace("\n", "\n" + " "*indent)
Guido van Rossumb3f09d42003-03-05 23:31:58 +000080
Guido van Rossumd8faa362007-04-27 19:54:29 +000081def _template_func(setup, func):
82 """Create a timer function. Used if the "statement" is a callable."""
Raymond Hettingerb646aa12009-04-03 02:45:36 +000083 def inner(_it, _timer, _func=func):
Guido van Rossumd8faa362007-04-27 19:54:29 +000084 setup()
85 _t0 = _timer()
86 for _i in _it:
Raymond Hettingerb646aa12009-04-03 02:45:36 +000087 _func()
Guido van Rossumd8faa362007-04-27 19:54:29 +000088 _t1 = _timer()
89 return _t1 - _t0
90 return inner
91
Guido van Rossumb3f09d42003-03-05 23:31:58 +000092class Timer:
Guido van Rossumb7ab6002003-03-06 02:32:19 +000093 """Class for timing execution speed of small code snippets.
94
95 The constructor takes a statement to be timed, an additional
96 statement used for setup, and a timer function. Both statements
97 default to 'pass'; the timer function is platform-dependent (see
98 module doc string).
99
100 To measure the execution time of the first statement, use the
101 timeit() method. The repeat() method is a convenience to call
102 timeit() multiple times and return a list of results.
103
104 The statements may contain newlines, as long as they don't contain
105 multi-line string literals.
106 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000107
108 def __init__(self, stmt="pass", setup="pass", timer=default_timer):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000109 """Constructor. See class doc string."""
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000110 self.timer = timer
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000111 ns = {}
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000112 if isinstance(stmt, str):
Serhiy Storchaka2bef5852015-01-26 12:09:17 +0200113 # Check that the code can be compiled outside a function
114 if isinstance(setup, str):
115 compile(setup, dummy_src_name, "exec")
116 compile(setup + '\n' + stmt, dummy_src_name, "exec")
117 else:
118 compile(stmt, dummy_src_name, "exec")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000119 stmt = reindent(stmt, 8)
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000120 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000121 setup = reindent(setup, 4)
Raymond Hettingerc800af42011-04-04 09:28:25 -0700122 src = template.format(stmt=stmt, setup=setup)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200123 elif callable(setup):
Raymond Hettingerc800af42011-04-04 09:28:25 -0700124 src = template.format(stmt=stmt, setup='_setup()')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000125 ns['_setup'] = setup
126 else:
127 raise ValueError("setup is neither a string nor callable")
128 self.src = src # Save for traceback display
129 code = compile(src, dummy_src_name, "exec")
130 exec(code, globals(), ns)
131 self.inner = ns["inner"]
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200132 elif callable(stmt):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000133 self.src = None
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000134 if isinstance(setup, str):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000135 _setup = setup
136 def setup():
137 exec(_setup, globals(), ns)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200138 elif not callable(setup):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139 raise ValueError("setup is neither a string nor callable")
140 self.inner = _template_func(setup, stmt)
141 else:
142 raise ValueError("stmt is neither a string nor callable")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000143
Guido van Rossum538f1d82003-03-14 17:21:00 +0000144 def print_exc(self, file=None):
145 """Helper to print a traceback from the timed code.
146
147 Typical use:
148
149 t = Timer(...) # outside the try/except
150 try:
151 t.timeit(...) # or t.repeat(...)
152 except:
153 t.print_exc()
154
155 The advantage over the standard traceback is that source lines
156 in the compiled template will be displayed.
157
158 The optional file argument directs where the traceback is
159 sent; it defaults to sys.stderr.
160 """
161 import linecache, traceback
Guido van Rossumd8faa362007-04-27 19:54:29 +0000162 if self.src is not None:
163 linecache.cache[dummy_src_name] = (len(self.src),
164 None,
165 self.src.split("\n"),
166 dummy_src_name)
167 # else the source is already stored somewhere else
168
Guido van Rossum538f1d82003-03-14 17:21:00 +0000169 traceback.print_exc(file=file)
170
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000171 def timeit(self, number=default_number):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000172 """Time 'number' executions of the main statement.
173
174 To be precise, this executes the setup statement once, and
175 then returns the time it takes to execute the main statement
176 a number of times, as a float measured in seconds. The
177 argument is the number of times through the loop, defaulting
178 to one million. The main statement, the setup statement and
179 the timer function to be used are passed to the constructor.
180 """
Terry Jan Reedyd49af5d2013-03-15 03:04:25 -0400181 it = itertools.repeat(None, number)
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000182 gcold = gc.isenabled()
183 gc.disable()
Raymond Hettinger3a081f52011-07-29 00:02:04 -0700184 try:
185 timing = self.inner(it, self.timer)
186 finally:
187 if gcold:
188 gc.enable()
Raymond Hettinger816ed1b2004-01-04 03:47:51 +0000189 return timing
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000190
191 def repeat(self, repeat=default_repeat, number=default_number):
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000192 """Call timeit() a few times.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000193
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000194 This is a convenience function that calls the timeit()
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000195 repeatedly, returning a list of results. The first argument
Skip Montanarofb2a6cc2003-04-08 19:40:19 +0000196 specifies how many times to call timeit(), defaulting to 3;
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000197 the second argument specifies the timer argument, defaulting
198 to one million.
Guido van Rossum55735412003-03-06 16:11:17 +0000199
200 Note: it's tempting to calculate mean and standard deviation
201 from the result vector and report these. However, this is not
202 very useful. In a typical case, the lowest value gives a
203 lower bound for how fast your machine can run the given code
204 snippet; higher values in the result vector are typically not
205 caused by variability in Python's speed, but by other
206 processes interfering with your timing accuracy. So the min()
207 of the result is probably the only number you should be
208 interested in. After that, you should look at the entire
209 vector and apply common sense rather than statistics.
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000210 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000211 r = []
212 for i in range(repeat):
213 t = self.timeit(number)
214 r.append(t)
215 return r
216
Guido van Rossumd8faa362007-04-27 19:54:29 +0000217def timeit(stmt="pass", setup="pass", timer=default_timer,
218 number=default_number):
219 """Convenience function to create Timer object and call timeit method."""
220 return Timer(stmt, setup, timer).timeit(number)
221
222def repeat(stmt="pass", setup="pass", timer=default_timer,
223 repeat=default_repeat, number=default_number):
224 """Convenience function to create Timer object and call repeat method."""
225 return Timer(stmt, setup, timer).repeat(repeat, number)
226
R David Murraya88da672011-03-16 17:32:27 -0400227def main(args=None, *, _wrap_timer=None):
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000228 """Main program, used when run as a script.
229
R David Murraya88da672011-03-16 17:32:27 -0400230 The optional 'args' argument specifies the command line to be parsed,
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000231 defaulting to sys.argv[1:].
232
233 The return value is an exit code to be passed to sys.exit(); it
234 may be None to indicate success.
Guido van Rossum538f1d82003-03-14 17:21:00 +0000235
236 When an exception happens during timing, a traceback is printed to
237 stderr and the return value is 1. Exceptions at other times
238 (including the template compilation) are not caught.
R David Murraya88da672011-03-16 17:32:27 -0400239
240 '_wrap_timer' is an internal interface used for unit testing. If it
241 is not None, it must be a callable that accepts a timer function
242 and returns another timer function (used for unit testing).
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000243 """
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000244 if args is None:
245 args = sys.argv[1:]
246 import getopt
247 try:
Georg Brandlc9d77b22012-05-01 11:56:22 +0200248 opts, args = getopt.getopt(args, "n:s:r:tcpvh",
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000249 ["number=", "setup=", "repeat=",
Georg Brandlc9d77b22012-05-01 11:56:22 +0200250 "time", "clock", "process",
251 "verbose", "help"])
Guido van Rossumb940e112007-01-10 16:19:56 +0000252 except getopt.error as err:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000253 print(err)
254 print("use -h/--help for command line help")
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000255 return 2
256 timer = default_timer
257 stmt = "\n".join(args) or "pass"
258 number = 0 # auto-determine
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000259 setup = []
Guido van Rossum0070f002003-03-15 12:25:00 +0000260 repeat = default_repeat
261 verbose = 0
262 precision = 3
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000263 for o, a in opts:
264 if o in ("-n", "--number"):
265 number = int(a)
266 if o in ("-s", "--setup"):
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000267 setup.append(a)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000268 if o in ("-r", "--repeat"):
269 repeat = int(a)
270 if repeat <= 0:
271 repeat = 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000272 if o in ("-t", "--time"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000273 timer = time.time
Guido van Rossume8577b72003-03-06 03:02:10 +0000274 if o in ("-c", "--clock"):
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000275 timer = time.clock
Georg Brandlc9d77b22012-05-01 11:56:22 +0200276 if o in ("-p", "--process"):
277 timer = time.process_time
Guido van Rossum0070f002003-03-15 12:25:00 +0000278 if o in ("-v", "--verbose"):
279 if verbose:
280 precision += 1
281 verbose += 1
Guido van Rossume8577b72003-03-06 03:02:10 +0000282 if o in ("-h", "--help"):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000283 print(__doc__, end=' ')
Guido van Rossume8577b72003-03-06 03:02:10 +0000284 return 0
Guido van Rossum6e31aad2003-03-07 01:33:18 +0000285 setup = "\n".join(setup) or "pass"
Raymond Hettinger22952a32003-05-20 04:59:56 +0000286 # Include the current directory, so that local imports work (sys.path
287 # contains the directory of this script, rather than the current
288 # directory)
289 import os
290 sys.path.insert(0, os.curdir)
R David Murraya88da672011-03-16 17:32:27 -0400291 if _wrap_timer is not None:
292 timer = _wrap_timer(timer)
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000293 t = Timer(stmt, setup, timer)
294 if number == 0:
295 # determine number so that 0.2 <= total time < 2.0
296 for i in range(1, 10):
297 number = 10**i
Guido van Rossum538f1d82003-03-14 17:21:00 +0000298 try:
299 x = t.timeit(number)
300 except:
301 t.print_exc()
302 return 1
Guido van Rossum0070f002003-03-15 12:25:00 +0000303 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000304 print("%d loops -> %.*g secs" % (number, precision, x))
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000305 if x >= 0.2:
306 break
Guido van Rossum538f1d82003-03-14 17:21:00 +0000307 try:
308 r = t.repeat(repeat, number)
309 except:
310 t.print_exc()
311 return 1
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000312 best = min(r)
Guido van Rossum0070f002003-03-15 12:25:00 +0000313 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000314 print("raw times:", " ".join(["%.*g" % (precision, x) for x in r]))
315 print("%d loops," % number, end=' ')
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000316 usec = best * 1e6 / number
Guido van Rossum57172082003-10-20 23:38:28 +0000317 if usec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000318 print("best of %d: %.*g usec per loop" % (repeat, precision, usec))
Guido van Rossum57172082003-10-20 23:38:28 +0000319 else:
320 msec = usec / 1000
321 if msec < 1000:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000322 print("best of %d: %.*g msec per loop" % (repeat, precision, msec))
Guido van Rossum57172082003-10-20 23:38:28 +0000323 else:
324 sec = msec / 1000
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000325 print("best of %d: %.*g sec per loop" % (repeat, precision, sec))
Guido van Rossumb7ab6002003-03-06 02:32:19 +0000326 return None
Guido van Rossumb3f09d42003-03-05 23:31:58 +0000327
328if __name__ == "__main__":
329 sys.exit(main())