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