summaryrefslogtreecommitdiff
path: root/Lib/timeit.py
blob: 2c0c146e6f13f539201c55f122388491b8620d77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Framework for timing execution speed of small code snippets.

This avoids a number of common traps for timing frameworks (see also
Tim Peters' introduction to the timing chapter in the Python
Cookbook).

(To use this with older versions of Python, the dependency on the
itertools module is easily removed; instead of itertools.repeat(None,
count) you can use [None]*count; this is barely slower.)

Command line usage:
  python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [statement]

Options:
  -n/--number N: how many times to execute 'statement' (default varies)
  -r/--repeat N: how many times to repeat the timer (default 1)
  -s/--setup S: statements executed once before 'statement' (default 'pass')
  -t/--time: use time.time() (default on Unix)
  -c/--clock: use time.clock() (default on Windows)
  statement: statement to be timed (default 'pass')
"""

import sys
import math
import time
import itertools

__all__ = ["Timer"]

default_number = 1000000
default_repeat = 10

if sys.platform == "win32":
    # On Windows, the best timer is time.clock()
    default_timer = time.clock
else:
    # On most other platforms the best timer is time.time()
    default_timer = time.time

template = """
def inner(number, timer):
    %(setup)s
    seq = itertools.repeat(None, number)
    t0 = timer()
    for i in seq:
        %(stmt)s
    t1 = timer()
    return t1-t0
"""

def reindent(src, indent):
    return ("\n" + " "*indent).join(src.split("\n"))

class Timer:

    def __init__(self, stmt="pass", setup="pass", timer=default_timer):
        self.timer = timer
        stmt = reindent(stmt, 8)
        setup = reindent(setup, 4)
        src = template % {'stmt': stmt, 'setup': setup}
        code = compile(src, "<src>", "exec")
        ns = {}
        exec code in globals(), ns
        self.inner = ns["inner"]

    def timeit(self, number=default_number):
        return self.inner(number, self.timer)

    def repeat(self, repeat=default_repeat, number=default_number):
        r = []
        for i in range(repeat):
            t = self.timeit(number)
            r.append(t)
        return r

def main(args=None):
    if args is None:
        args = sys.argv[1:]
    import getopt
    try:
        opts, args = getopt.getopt(args, "n:s:r:tc",
                                   ["number=", "setup=", "repeat=",
                                    "time", "clock"])
    except getopt.error, err:
        print err
        return 2
    timer = default_timer
    stmt = "\n".join(args) or "pass"
    number = 0 # auto-determine
    setup = "pass"
    repeat = 1
    for o, a in opts:
        if o in ("-n", "--number"):
            number = int(a)
        if o in ("-s", "--setup"):
            setup = a
        if o in ("-r", "--repeat"):
            repeat = int(a)
            if repeat <= 0:
                repeat = 1
        if o in ("-t", "time"):
            timer = time.time
        if o in ("-c", "clock"):
            timer = time.clock
    t = Timer(stmt, setup, timer)
    if number == 0:
        # determine number so that 0.2 <= total time < 2.0
        for i in range(1, 10):
            number = 10**i
            x = t.timeit(number)
            if x >= 0.2:
                break
    r = t.repeat(repeat, number)
    best = min(r)
    print "%d loops," % number,
    usec = best * 1e6 / number
    if repeat > 1:
        print "best of %d: %.3f usec" % (repeat, usec)
    else:
        print "time: %.3f usec" % usec

if __name__ == "__main__":
    sys.exit(main())