blob: 2c0c146e6f13f539201c55f122388491b8620d77 [file] [log] [blame]
Guido van Rossumb3f09d42003-03-05 23:31:58 +00001"""Framework for timing execution speed of small code snippets.
2
3This avoids a number of common traps for timing frameworks (see also
4Tim Peters' introduction to the timing chapter in the Python
5Cookbook).
6
7(To use this with older versions of Python, the dependency on the
8itertools module is easily removed; instead of itertools.repeat(None,
9count) you can use [None]*count; this is barely slower.)
10
11Command line usage:
12 python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [statement]
13
14Options:
15 -n/--number N: how many times to execute 'statement' (default varies)
16 -r/--repeat N: how many times to repeat the timer (default 1)
17 -s/--setup S: statements executed once before 'statement' (default 'pass')
18 -t/--time: use time.time() (default on Unix)
19 -c/--clock: use time.clock() (default on Windows)
20 statement: statement to be timed (default 'pass')
21"""
22
23import sys
24import math
25import time
26import itertools
27
28__all__ = ["Timer"]
29
30default_number = 1000000
31default_repeat = 10
32
33if sys.platform == "win32":
34 # On Windows, the best timer is time.clock()
35 default_timer = time.clock
36else:
37 # On most other platforms the best timer is time.time()
38 default_timer = time.time
39
40template = """
41def inner(number, timer):
42 %(setup)s
43 seq = itertools.repeat(None, number)
44 t0 = timer()
45 for i in seq:
46 %(stmt)s
47 t1 = timer()
48 return t1-t0
49"""
50
51def reindent(src, indent):
52 return ("\n" + " "*indent).join(src.split("\n"))
53
54class Timer:
55
56 def __init__(self, stmt="pass", setup="pass", timer=default_timer):
57 self.timer = timer
58 stmt = reindent(stmt, 8)
59 setup = reindent(setup, 4)
60 src = template % {'stmt': stmt, 'setup': setup}
61 code = compile(src, "<src>", "exec")
62 ns = {}
63 exec code in globals(), ns
64 self.inner = ns["inner"]
65
66 def timeit(self, number=default_number):
67 return self.inner(number, self.timer)
68
69 def repeat(self, repeat=default_repeat, number=default_number):
70 r = []
71 for i in range(repeat):
72 t = self.timeit(number)
73 r.append(t)
74 return r
75
76def main(args=None):
77 if args is None:
78 args = sys.argv[1:]
79 import getopt
80 try:
81 opts, args = getopt.getopt(args, "n:s:r:tc",
82 ["number=", "setup=", "repeat=",
83 "time", "clock"])
84 except getopt.error, err:
85 print err
86 return 2
87 timer = default_timer
88 stmt = "\n".join(args) or "pass"
89 number = 0 # auto-determine
90 setup = "pass"
91 repeat = 1
92 for o, a in opts:
93 if o in ("-n", "--number"):
94 number = int(a)
95 if o in ("-s", "--setup"):
96 setup = a
97 if o in ("-r", "--repeat"):
98 repeat = int(a)
99 if repeat <= 0:
100 repeat = 1
101 if o in ("-t", "time"):
102 timer = time.time
103 if o in ("-c", "clock"):
104 timer = time.clock
105 t = Timer(stmt, setup, timer)
106 if number == 0:
107 # determine number so that 0.2 <= total time < 2.0
108 for i in range(1, 10):
109 number = 10**i
110 x = t.timeit(number)
111 if x >= 0.2:
112 break
113 r = t.repeat(repeat, number)
114 best = min(r)
115 print "%d loops," % number,
116 usec = best * 1e6 / number
117 if repeat > 1:
118 print "best of %d: %.3f usec" % (repeat, usec)
119 else:
120 print "time: %.3f usec" % usec
121
122if __name__ == "__main__":
123 sys.exit(main())