xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/timeit.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker#! /usr/bin/env python3
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Worker"""Tool for measuring execution time of small code snippets.
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard WorkerThis module avoids a number of common traps for measuring execution
6*cda5da8dSAndroid Build Coastguard Workertimes.  See also Tim Peters' introduction to the Algorithms chapter in
7*cda5da8dSAndroid Build Coastguard Workerthe Python Cookbook, published by O'Reilly.
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard WorkerLibrary usage: see the Timer class.
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard WorkerCommand line usage:
12*cda5da8dSAndroid Build Coastguard Worker    python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement]
13*cda5da8dSAndroid Build Coastguard Worker
14*cda5da8dSAndroid Build Coastguard WorkerOptions:
15*cda5da8dSAndroid Build Coastguard Worker  -n/--number N: how many times to execute 'statement' (default: see below)
16*cda5da8dSAndroid Build Coastguard Worker  -r/--repeat N: how many times to repeat the timer (default 5)
17*cda5da8dSAndroid Build Coastguard Worker  -s/--setup S: statement to be executed once initially (default 'pass').
18*cda5da8dSAndroid Build Coastguard Worker                Execution time of this setup statement is NOT timed.
19*cda5da8dSAndroid Build Coastguard Worker  -p/--process: use time.process_time() (default is time.perf_counter())
20*cda5da8dSAndroid Build Coastguard Worker  -v/--verbose: print raw timing results; repeat for more digits precision
21*cda5da8dSAndroid Build Coastguard Worker  -u/--unit: set the output time unit (nsec, usec, msec, or sec)
22*cda5da8dSAndroid Build Coastguard Worker  -h/--help: print this usage message and exit
23*cda5da8dSAndroid Build Coastguard Worker  --: separate options from statement, use when statement starts with -
24*cda5da8dSAndroid Build Coastguard Worker  statement: statement to be timed (default 'pass')
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard WorkerA multi-line statement may be given by specifying each line as a
27*cda5da8dSAndroid Build Coastguard Workerseparate argument; indented lines are possible by enclosing an
28*cda5da8dSAndroid Build Coastguard Workerargument in quotes and using leading spaces.  Multiple -s options are
29*cda5da8dSAndroid Build Coastguard Workertreated similarly.
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard WorkerIf -n is not given, a suitable number of loops is calculated by trying
32*cda5da8dSAndroid Build Coastguard Workerincreasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
33*cda5da8dSAndroid Build Coastguard Workertotal time is at least 0.2 seconds.
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard WorkerNote: there is a certain baseline overhead associated with executing a
36*cda5da8dSAndroid Build Coastguard Workerpass statement.  It differs between versions.  The code here doesn't try
37*cda5da8dSAndroid Build Coastguard Workerto hide it, but you should be aware of it.  The baseline overhead can be
38*cda5da8dSAndroid Build Coastguard Workermeasured by invoking the program without arguments.
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard WorkerClasses:
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Worker    Timer
43*cda5da8dSAndroid Build Coastguard Worker
44*cda5da8dSAndroid Build Coastguard WorkerFunctions:
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker    timeit(string, string) -> float
47*cda5da8dSAndroid Build Coastguard Worker    repeat(string, string) -> list
48*cda5da8dSAndroid Build Coastguard Worker    default_timer() -> float
49*cda5da8dSAndroid Build Coastguard Worker
50*cda5da8dSAndroid Build Coastguard Worker"""
51*cda5da8dSAndroid Build Coastguard Worker
52*cda5da8dSAndroid Build Coastguard Workerimport gc
53*cda5da8dSAndroid Build Coastguard Workerimport sys
54*cda5da8dSAndroid Build Coastguard Workerimport time
55*cda5da8dSAndroid Build Coastguard Workerimport itertools
56*cda5da8dSAndroid Build Coastguard Worker
57*cda5da8dSAndroid Build Coastguard Worker__all__ = ["Timer", "timeit", "repeat", "default_timer"]
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Workerdummy_src_name = "<timeit-src>"
60*cda5da8dSAndroid Build Coastguard Workerdefault_number = 1000000
61*cda5da8dSAndroid Build Coastguard Workerdefault_repeat = 5
62*cda5da8dSAndroid Build Coastguard Workerdefault_timer = time.perf_counter
63*cda5da8dSAndroid Build Coastguard Worker
64*cda5da8dSAndroid Build Coastguard Worker_globals = globals
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Worker# Don't change the indentation of the template; the reindent() calls
67*cda5da8dSAndroid Build Coastguard Worker# in Timer.__init__() depend on setup being indented 4 spaces and stmt
68*cda5da8dSAndroid Build Coastguard Worker# being indented 8 spaces.
69*cda5da8dSAndroid Build Coastguard Workertemplate = """
70*cda5da8dSAndroid Build Coastguard Workerdef inner(_it, _timer{init}):
71*cda5da8dSAndroid Build Coastguard Worker    {setup}
72*cda5da8dSAndroid Build Coastguard Worker    _t0 = _timer()
73*cda5da8dSAndroid Build Coastguard Worker    for _i in _it:
74*cda5da8dSAndroid Build Coastguard Worker        {stmt}
75*cda5da8dSAndroid Build Coastguard Worker        pass
76*cda5da8dSAndroid Build Coastguard Worker    _t1 = _timer()
77*cda5da8dSAndroid Build Coastguard Worker    return _t1 - _t0
78*cda5da8dSAndroid Build Coastguard Worker"""
79*cda5da8dSAndroid Build Coastguard Worker
80*cda5da8dSAndroid Build Coastguard Workerdef reindent(src, indent):
81*cda5da8dSAndroid Build Coastguard Worker    """Helper to reindent a multi-line statement."""
82*cda5da8dSAndroid Build Coastguard Worker    return src.replace("\n", "\n" + " "*indent)
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Workerclass Timer:
85*cda5da8dSAndroid Build Coastguard Worker    """Class for timing execution speed of small code snippets.
86*cda5da8dSAndroid Build Coastguard Worker
87*cda5da8dSAndroid Build Coastguard Worker    The constructor takes a statement to be timed, an additional
88*cda5da8dSAndroid Build Coastguard Worker    statement used for setup, and a timer function.  Both statements
89*cda5da8dSAndroid Build Coastguard Worker    default to 'pass'; the timer function is platform-dependent (see
90*cda5da8dSAndroid Build Coastguard Worker    module doc string).  If 'globals' is specified, the code will be
91*cda5da8dSAndroid Build Coastguard Worker    executed within that namespace (as opposed to inside timeit's
92*cda5da8dSAndroid Build Coastguard Worker    namespace).
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Worker    To measure the execution time of the first statement, use the
95*cda5da8dSAndroid Build Coastguard Worker    timeit() method.  The repeat() method is a convenience to call
96*cda5da8dSAndroid Build Coastguard Worker    timeit() multiple times and return a list of results.
97*cda5da8dSAndroid Build Coastguard Worker
98*cda5da8dSAndroid Build Coastguard Worker    The statements may contain newlines, as long as they don't contain
99*cda5da8dSAndroid Build Coastguard Worker    multi-line string literals.
100*cda5da8dSAndroid Build Coastguard Worker    """
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, stmt="pass", setup="pass", timer=default_timer,
103*cda5da8dSAndroid Build Coastguard Worker                 globals=None):
104*cda5da8dSAndroid Build Coastguard Worker        """Constructor.  See class doc string."""
105*cda5da8dSAndroid Build Coastguard Worker        self.timer = timer
106*cda5da8dSAndroid Build Coastguard Worker        local_ns = {}
107*cda5da8dSAndroid Build Coastguard Worker        global_ns = _globals() if globals is None else globals
108*cda5da8dSAndroid Build Coastguard Worker        init = ''
109*cda5da8dSAndroid Build Coastguard Worker        if isinstance(setup, str):
110*cda5da8dSAndroid Build Coastguard Worker            # Check that the code can be compiled outside a function
111*cda5da8dSAndroid Build Coastguard Worker            compile(setup, dummy_src_name, "exec")
112*cda5da8dSAndroid Build Coastguard Worker            stmtprefix = setup + '\n'
113*cda5da8dSAndroid Build Coastguard Worker            setup = reindent(setup, 4)
114*cda5da8dSAndroid Build Coastguard Worker        elif callable(setup):
115*cda5da8dSAndroid Build Coastguard Worker            local_ns['_setup'] = setup
116*cda5da8dSAndroid Build Coastguard Worker            init += ', _setup=_setup'
117*cda5da8dSAndroid Build Coastguard Worker            stmtprefix = ''
118*cda5da8dSAndroid Build Coastguard Worker            setup = '_setup()'
119*cda5da8dSAndroid Build Coastguard Worker        else:
120*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("setup is neither a string nor callable")
121*cda5da8dSAndroid Build Coastguard Worker        if isinstance(stmt, str):
122*cda5da8dSAndroid Build Coastguard Worker            # Check that the code can be compiled outside a function
123*cda5da8dSAndroid Build Coastguard Worker            compile(stmtprefix + stmt, dummy_src_name, "exec")
124*cda5da8dSAndroid Build Coastguard Worker            stmt = reindent(stmt, 8)
125*cda5da8dSAndroid Build Coastguard Worker        elif callable(stmt):
126*cda5da8dSAndroid Build Coastguard Worker            local_ns['_stmt'] = stmt
127*cda5da8dSAndroid Build Coastguard Worker            init += ', _stmt=_stmt'
128*cda5da8dSAndroid Build Coastguard Worker            stmt = '_stmt()'
129*cda5da8dSAndroid Build Coastguard Worker        else:
130*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("stmt is neither a string nor callable")
131*cda5da8dSAndroid Build Coastguard Worker        src = template.format(stmt=stmt, setup=setup, init=init)
132*cda5da8dSAndroid Build Coastguard Worker        self.src = src  # Save for traceback display
133*cda5da8dSAndroid Build Coastguard Worker        code = compile(src, dummy_src_name, "exec")
134*cda5da8dSAndroid Build Coastguard Worker        exec(code, global_ns, local_ns)
135*cda5da8dSAndroid Build Coastguard Worker        self.inner = local_ns["inner"]
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker    def print_exc(self, file=None):
138*cda5da8dSAndroid Build Coastguard Worker        """Helper to print a traceback from the timed code.
139*cda5da8dSAndroid Build Coastguard Worker
140*cda5da8dSAndroid Build Coastguard Worker        Typical use:
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Worker            t = Timer(...)       # outside the try/except
143*cda5da8dSAndroid Build Coastguard Worker            try:
144*cda5da8dSAndroid Build Coastguard Worker                t.timeit(...)    # or t.repeat(...)
145*cda5da8dSAndroid Build Coastguard Worker            except:
146*cda5da8dSAndroid Build Coastguard Worker                t.print_exc()
147*cda5da8dSAndroid Build Coastguard Worker
148*cda5da8dSAndroid Build Coastguard Worker        The advantage over the standard traceback is that source lines
149*cda5da8dSAndroid Build Coastguard Worker        in the compiled template will be displayed.
150*cda5da8dSAndroid Build Coastguard Worker
151*cda5da8dSAndroid Build Coastguard Worker        The optional file argument directs where the traceback is
152*cda5da8dSAndroid Build Coastguard Worker        sent; it defaults to sys.stderr.
153*cda5da8dSAndroid Build Coastguard Worker        """
154*cda5da8dSAndroid Build Coastguard Worker        import linecache, traceback
155*cda5da8dSAndroid Build Coastguard Worker        if self.src is not None:
156*cda5da8dSAndroid Build Coastguard Worker            linecache.cache[dummy_src_name] = (len(self.src),
157*cda5da8dSAndroid Build Coastguard Worker                                               None,
158*cda5da8dSAndroid Build Coastguard Worker                                               self.src.split("\n"),
159*cda5da8dSAndroid Build Coastguard Worker                                               dummy_src_name)
160*cda5da8dSAndroid Build Coastguard Worker        # else the source is already stored somewhere else
161*cda5da8dSAndroid Build Coastguard Worker
162*cda5da8dSAndroid Build Coastguard Worker        traceback.print_exc(file=file)
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Worker    def timeit(self, number=default_number):
165*cda5da8dSAndroid Build Coastguard Worker        """Time 'number' executions of the main statement.
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Worker        To be precise, this executes the setup statement once, and
168*cda5da8dSAndroid Build Coastguard Worker        then returns the time it takes to execute the main statement
169*cda5da8dSAndroid Build Coastguard Worker        a number of times, as a float measured in seconds.  The
170*cda5da8dSAndroid Build Coastguard Worker        argument is the number of times through the loop, defaulting
171*cda5da8dSAndroid Build Coastguard Worker        to one million.  The main statement, the setup statement and
172*cda5da8dSAndroid Build Coastguard Worker        the timer function to be used are passed to the constructor.
173*cda5da8dSAndroid Build Coastguard Worker        """
174*cda5da8dSAndroid Build Coastguard Worker        it = itertools.repeat(None, number)
175*cda5da8dSAndroid Build Coastguard Worker        gcold = gc.isenabled()
176*cda5da8dSAndroid Build Coastguard Worker        gc.disable()
177*cda5da8dSAndroid Build Coastguard Worker        try:
178*cda5da8dSAndroid Build Coastguard Worker            timing = self.inner(it, self.timer)
179*cda5da8dSAndroid Build Coastguard Worker        finally:
180*cda5da8dSAndroid Build Coastguard Worker            if gcold:
181*cda5da8dSAndroid Build Coastguard Worker                gc.enable()
182*cda5da8dSAndroid Build Coastguard Worker        return timing
183*cda5da8dSAndroid Build Coastguard Worker
184*cda5da8dSAndroid Build Coastguard Worker    def repeat(self, repeat=default_repeat, number=default_number):
185*cda5da8dSAndroid Build Coastguard Worker        """Call timeit() a few times.
186*cda5da8dSAndroid Build Coastguard Worker
187*cda5da8dSAndroid Build Coastguard Worker        This is a convenience function that calls the timeit()
188*cda5da8dSAndroid Build Coastguard Worker        repeatedly, returning a list of results.  The first argument
189*cda5da8dSAndroid Build Coastguard Worker        specifies how many times to call timeit(), defaulting to 5;
190*cda5da8dSAndroid Build Coastguard Worker        the second argument specifies the timer argument, defaulting
191*cda5da8dSAndroid Build Coastguard Worker        to one million.
192*cda5da8dSAndroid Build Coastguard Worker
193*cda5da8dSAndroid Build Coastguard Worker        Note: it's tempting to calculate mean and standard deviation
194*cda5da8dSAndroid Build Coastguard Worker        from the result vector and report these.  However, this is not
195*cda5da8dSAndroid Build Coastguard Worker        very useful.  In a typical case, the lowest value gives a
196*cda5da8dSAndroid Build Coastguard Worker        lower bound for how fast your machine can run the given code
197*cda5da8dSAndroid Build Coastguard Worker        snippet; higher values in the result vector are typically not
198*cda5da8dSAndroid Build Coastguard Worker        caused by variability in Python's speed, but by other
199*cda5da8dSAndroid Build Coastguard Worker        processes interfering with your timing accuracy.  So the min()
200*cda5da8dSAndroid Build Coastguard Worker        of the result is probably the only number you should be
201*cda5da8dSAndroid Build Coastguard Worker        interested in.  After that, you should look at the entire
202*cda5da8dSAndroid Build Coastguard Worker        vector and apply common sense rather than statistics.
203*cda5da8dSAndroid Build Coastguard Worker        """
204*cda5da8dSAndroid Build Coastguard Worker        r = []
205*cda5da8dSAndroid Build Coastguard Worker        for i in range(repeat):
206*cda5da8dSAndroid Build Coastguard Worker            t = self.timeit(number)
207*cda5da8dSAndroid Build Coastguard Worker            r.append(t)
208*cda5da8dSAndroid Build Coastguard Worker        return r
209*cda5da8dSAndroid Build Coastguard Worker
210*cda5da8dSAndroid Build Coastguard Worker    def autorange(self, callback=None):
211*cda5da8dSAndroid Build Coastguard Worker        """Return the number of loops and time taken so that total time >= 0.2.
212*cda5da8dSAndroid Build Coastguard Worker
213*cda5da8dSAndroid Build Coastguard Worker        Calls the timeit method with increasing numbers from the sequence
214*cda5da8dSAndroid Build Coastguard Worker        1, 2, 5, 10, 20, 50, ... until the time taken is at least 0.2
215*cda5da8dSAndroid Build Coastguard Worker        second.  Returns (number, time_taken).
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Worker        If *callback* is given and is not None, it will be called after
218*cda5da8dSAndroid Build Coastguard Worker        each trial with two arguments: ``callback(number, time_taken)``.
219*cda5da8dSAndroid Build Coastguard Worker        """
220*cda5da8dSAndroid Build Coastguard Worker        i = 1
221*cda5da8dSAndroid Build Coastguard Worker        while True:
222*cda5da8dSAndroid Build Coastguard Worker            for j in 1, 2, 5:
223*cda5da8dSAndroid Build Coastguard Worker                number = i * j
224*cda5da8dSAndroid Build Coastguard Worker                time_taken = self.timeit(number)
225*cda5da8dSAndroid Build Coastguard Worker                if callback:
226*cda5da8dSAndroid Build Coastguard Worker                    callback(number, time_taken)
227*cda5da8dSAndroid Build Coastguard Worker                if time_taken >= 0.2:
228*cda5da8dSAndroid Build Coastguard Worker                    return (number, time_taken)
229*cda5da8dSAndroid Build Coastguard Worker            i *= 10
230*cda5da8dSAndroid Build Coastguard Worker
231*cda5da8dSAndroid Build Coastguard Workerdef timeit(stmt="pass", setup="pass", timer=default_timer,
232*cda5da8dSAndroid Build Coastguard Worker           number=default_number, globals=None):
233*cda5da8dSAndroid Build Coastguard Worker    """Convenience function to create Timer object and call timeit method."""
234*cda5da8dSAndroid Build Coastguard Worker    return Timer(stmt, setup, timer, globals).timeit(number)
235*cda5da8dSAndroid Build Coastguard Worker
236*cda5da8dSAndroid Build Coastguard Workerdef repeat(stmt="pass", setup="pass", timer=default_timer,
237*cda5da8dSAndroid Build Coastguard Worker           repeat=default_repeat, number=default_number, globals=None):
238*cda5da8dSAndroid Build Coastguard Worker    """Convenience function to create Timer object and call repeat method."""
239*cda5da8dSAndroid Build Coastguard Worker    return Timer(stmt, setup, timer, globals).repeat(repeat, number)
240*cda5da8dSAndroid Build Coastguard Worker
241*cda5da8dSAndroid Build Coastguard Workerdef main(args=None, *, _wrap_timer=None):
242*cda5da8dSAndroid Build Coastguard Worker    """Main program, used when run as a script.
243*cda5da8dSAndroid Build Coastguard Worker
244*cda5da8dSAndroid Build Coastguard Worker    The optional 'args' argument specifies the command line to be parsed,
245*cda5da8dSAndroid Build Coastguard Worker    defaulting to sys.argv[1:].
246*cda5da8dSAndroid Build Coastguard Worker
247*cda5da8dSAndroid Build Coastguard Worker    The return value is an exit code to be passed to sys.exit(); it
248*cda5da8dSAndroid Build Coastguard Worker    may be None to indicate success.
249*cda5da8dSAndroid Build Coastguard Worker
250*cda5da8dSAndroid Build Coastguard Worker    When an exception happens during timing, a traceback is printed to
251*cda5da8dSAndroid Build Coastguard Worker    stderr and the return value is 1.  Exceptions at other times
252*cda5da8dSAndroid Build Coastguard Worker    (including the template compilation) are not caught.
253*cda5da8dSAndroid Build Coastguard Worker
254*cda5da8dSAndroid Build Coastguard Worker    '_wrap_timer' is an internal interface used for unit testing.  If it
255*cda5da8dSAndroid Build Coastguard Worker    is not None, it must be a callable that accepts a timer function
256*cda5da8dSAndroid Build Coastguard Worker    and returns another timer function (used for unit testing).
257*cda5da8dSAndroid Build Coastguard Worker    """
258*cda5da8dSAndroid Build Coastguard Worker    if args is None:
259*cda5da8dSAndroid Build Coastguard Worker        args = sys.argv[1:]
260*cda5da8dSAndroid Build Coastguard Worker    import getopt
261*cda5da8dSAndroid Build Coastguard Worker    try:
262*cda5da8dSAndroid Build Coastguard Worker        opts, args = getopt.getopt(args, "n:u:s:r:tcpvh",
263*cda5da8dSAndroid Build Coastguard Worker                                   ["number=", "setup=", "repeat=",
264*cda5da8dSAndroid Build Coastguard Worker                                    "time", "clock", "process",
265*cda5da8dSAndroid Build Coastguard Worker                                    "verbose", "unit=", "help"])
266*cda5da8dSAndroid Build Coastguard Worker    except getopt.error as err:
267*cda5da8dSAndroid Build Coastguard Worker        print(err)
268*cda5da8dSAndroid Build Coastguard Worker        print("use -h/--help for command line help")
269*cda5da8dSAndroid Build Coastguard Worker        return 2
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Worker    timer = default_timer
272*cda5da8dSAndroid Build Coastguard Worker    stmt = "\n".join(args) or "pass"
273*cda5da8dSAndroid Build Coastguard Worker    number = 0 # auto-determine
274*cda5da8dSAndroid Build Coastguard Worker    setup = []
275*cda5da8dSAndroid Build Coastguard Worker    repeat = default_repeat
276*cda5da8dSAndroid Build Coastguard Worker    verbose = 0
277*cda5da8dSAndroid Build Coastguard Worker    time_unit = None
278*cda5da8dSAndroid Build Coastguard Worker    units = {"nsec": 1e-9, "usec": 1e-6, "msec": 1e-3, "sec": 1.0}
279*cda5da8dSAndroid Build Coastguard Worker    precision = 3
280*cda5da8dSAndroid Build Coastguard Worker    for o, a in opts:
281*cda5da8dSAndroid Build Coastguard Worker        if o in ("-n", "--number"):
282*cda5da8dSAndroid Build Coastguard Worker            number = int(a)
283*cda5da8dSAndroid Build Coastguard Worker        if o in ("-s", "--setup"):
284*cda5da8dSAndroid Build Coastguard Worker            setup.append(a)
285*cda5da8dSAndroid Build Coastguard Worker        if o in ("-u", "--unit"):
286*cda5da8dSAndroid Build Coastguard Worker            if a in units:
287*cda5da8dSAndroid Build Coastguard Worker                time_unit = a
288*cda5da8dSAndroid Build Coastguard Worker            else:
289*cda5da8dSAndroid Build Coastguard Worker                print("Unrecognized unit. Please select nsec, usec, msec, or sec.",
290*cda5da8dSAndroid Build Coastguard Worker                    file=sys.stderr)
291*cda5da8dSAndroid Build Coastguard Worker                return 2
292*cda5da8dSAndroid Build Coastguard Worker        if o in ("-r", "--repeat"):
293*cda5da8dSAndroid Build Coastguard Worker            repeat = int(a)
294*cda5da8dSAndroid Build Coastguard Worker            if repeat <= 0:
295*cda5da8dSAndroid Build Coastguard Worker                repeat = 1
296*cda5da8dSAndroid Build Coastguard Worker        if o in ("-p", "--process"):
297*cda5da8dSAndroid Build Coastguard Worker            timer = time.process_time
298*cda5da8dSAndroid Build Coastguard Worker        if o in ("-v", "--verbose"):
299*cda5da8dSAndroid Build Coastguard Worker            if verbose:
300*cda5da8dSAndroid Build Coastguard Worker                precision += 1
301*cda5da8dSAndroid Build Coastguard Worker            verbose += 1
302*cda5da8dSAndroid Build Coastguard Worker        if o in ("-h", "--help"):
303*cda5da8dSAndroid Build Coastguard Worker            print(__doc__, end=' ')
304*cda5da8dSAndroid Build Coastguard Worker            return 0
305*cda5da8dSAndroid Build Coastguard Worker    setup = "\n".join(setup) or "pass"
306*cda5da8dSAndroid Build Coastguard Worker
307*cda5da8dSAndroid Build Coastguard Worker    # Include the current directory, so that local imports work (sys.path
308*cda5da8dSAndroid Build Coastguard Worker    # contains the directory of this script, rather than the current
309*cda5da8dSAndroid Build Coastguard Worker    # directory)
310*cda5da8dSAndroid Build Coastguard Worker    import os
311*cda5da8dSAndroid Build Coastguard Worker    sys.path.insert(0, os.curdir)
312*cda5da8dSAndroid Build Coastguard Worker    if _wrap_timer is not None:
313*cda5da8dSAndroid Build Coastguard Worker        timer = _wrap_timer(timer)
314*cda5da8dSAndroid Build Coastguard Worker
315*cda5da8dSAndroid Build Coastguard Worker    t = Timer(stmt, setup, timer)
316*cda5da8dSAndroid Build Coastguard Worker    if number == 0:
317*cda5da8dSAndroid Build Coastguard Worker        # determine number so that 0.2 <= total time < 2.0
318*cda5da8dSAndroid Build Coastguard Worker        callback = None
319*cda5da8dSAndroid Build Coastguard Worker        if verbose:
320*cda5da8dSAndroid Build Coastguard Worker            def callback(number, time_taken):
321*cda5da8dSAndroid Build Coastguard Worker                msg = "{num} loop{s} -> {secs:.{prec}g} secs"
322*cda5da8dSAndroid Build Coastguard Worker                plural = (number != 1)
323*cda5da8dSAndroid Build Coastguard Worker                print(msg.format(num=number, s='s' if plural else '',
324*cda5da8dSAndroid Build Coastguard Worker                                  secs=time_taken, prec=precision))
325*cda5da8dSAndroid Build Coastguard Worker        try:
326*cda5da8dSAndroid Build Coastguard Worker            number, _ = t.autorange(callback)
327*cda5da8dSAndroid Build Coastguard Worker        except:
328*cda5da8dSAndroid Build Coastguard Worker            t.print_exc()
329*cda5da8dSAndroid Build Coastguard Worker            return 1
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker        if verbose:
332*cda5da8dSAndroid Build Coastguard Worker            print()
333*cda5da8dSAndroid Build Coastguard Worker
334*cda5da8dSAndroid Build Coastguard Worker    try:
335*cda5da8dSAndroid Build Coastguard Worker        raw_timings = t.repeat(repeat, number)
336*cda5da8dSAndroid Build Coastguard Worker    except:
337*cda5da8dSAndroid Build Coastguard Worker        t.print_exc()
338*cda5da8dSAndroid Build Coastguard Worker        return 1
339*cda5da8dSAndroid Build Coastguard Worker
340*cda5da8dSAndroid Build Coastguard Worker    def format_time(dt):
341*cda5da8dSAndroid Build Coastguard Worker        unit = time_unit
342*cda5da8dSAndroid Build Coastguard Worker
343*cda5da8dSAndroid Build Coastguard Worker        if unit is not None:
344*cda5da8dSAndroid Build Coastguard Worker            scale = units[unit]
345*cda5da8dSAndroid Build Coastguard Worker        else:
346*cda5da8dSAndroid Build Coastguard Worker            scales = [(scale, unit) for unit, scale in units.items()]
347*cda5da8dSAndroid Build Coastguard Worker            scales.sort(reverse=True)
348*cda5da8dSAndroid Build Coastguard Worker            for scale, unit in scales:
349*cda5da8dSAndroid Build Coastguard Worker                if dt >= scale:
350*cda5da8dSAndroid Build Coastguard Worker                    break
351*cda5da8dSAndroid Build Coastguard Worker
352*cda5da8dSAndroid Build Coastguard Worker        return "%.*g %s" % (precision, dt / scale, unit)
353*cda5da8dSAndroid Build Coastguard Worker
354*cda5da8dSAndroid Build Coastguard Worker    if verbose:
355*cda5da8dSAndroid Build Coastguard Worker        print("raw times: %s" % ", ".join(map(format_time, raw_timings)))
356*cda5da8dSAndroid Build Coastguard Worker        print()
357*cda5da8dSAndroid Build Coastguard Worker    timings = [dt / number for dt in raw_timings]
358*cda5da8dSAndroid Build Coastguard Worker
359*cda5da8dSAndroid Build Coastguard Worker    best = min(timings)
360*cda5da8dSAndroid Build Coastguard Worker    print("%d loop%s, best of %d: %s per loop"
361*cda5da8dSAndroid Build Coastguard Worker          % (number, 's' if number != 1 else '',
362*cda5da8dSAndroid Build Coastguard Worker             repeat, format_time(best)))
363*cda5da8dSAndroid Build Coastguard Worker
364*cda5da8dSAndroid Build Coastguard Worker    best = min(timings)
365*cda5da8dSAndroid Build Coastguard Worker    worst = max(timings)
366*cda5da8dSAndroid Build Coastguard Worker    if worst >= best * 4:
367*cda5da8dSAndroid Build Coastguard Worker        import warnings
368*cda5da8dSAndroid Build Coastguard Worker        warnings.warn_explicit("The test results are likely unreliable. "
369*cda5da8dSAndroid Build Coastguard Worker                               "The worst time (%s) was more than four times "
370*cda5da8dSAndroid Build Coastguard Worker                               "slower than the best time (%s)."
371*cda5da8dSAndroid Build Coastguard Worker                               % (format_time(worst), format_time(best)),
372*cda5da8dSAndroid Build Coastguard Worker                               UserWarning, '', 0)
373*cda5da8dSAndroid Build Coastguard Worker    return None
374*cda5da8dSAndroid Build Coastguard Worker
375*cda5da8dSAndroid Build Coastguard Workerif __name__ == "__main__":
376*cda5da8dSAndroid Build Coastguard Worker    sys.exit(main())
377