[docs]classTimer(object):""" A context manager for timing things. Use it like this: with Timer("My timer"): # You can optionally give it a name # Do stuff Results are printed to stdout. You can access the runtime (in seconds) directly by instantiating the object: >>> t = Timer("My timer") >>> t.tic() >>> # Do stuff >>> print(t.toc()) Nested timers are also supported. For example, this code: >>> with Timer("a"): >>> with Timer("b"): >>> with Timer("c"): >>> f() prints the following console output: [a] Timing... [b] Timing... [c] Timing... [c] Elapsed: 100 msec [b] Elapsed: 100 msec [a] Elapsed: 100 msec """
[docs]number_running:int=0# The number of Timers currently running
[docs]deftime_function(func:Callable,repeats:int=None,desired_runtime:float=None,runtime_reduction=np.min,warmup:bool=True,)->Tuple[float,Any]:""" Runs a given callable and tells you how long it took to run, in seconds. Also returns the result of the function (if any), for good measure. Args: func: The function to run. Should take no arguments; use a lambda function or functools.partial if you need to pass arguments. repeats: The number of times to run the function. If None, runs until desired_runtime is met. desired_runtime: The desired runtime of the function, in seconds. If None, runs until repeats is met. runtime_reduction: A function that takes in a list of runtimes and returns a reduced value. For example, np.min will return the minimum runtime, np.mean will return the mean runtime, etc. Default is np.min. warmup: If True, runs the function once before starting the timer. This can be useful for functions with JIT-compilation, with internal imports, or caches. Returns: A Tuple of (time_taken, result). - time_taken is a float of the time taken to run the function, in seconds. - result is the result of the function, if any. """if(repeatsisnotNone)and(desired_runtimeisnotNone):raiseValueError("You can't specify both repeats and desired_runtime!")ifwarmup:func()deftime_function_once():start_ns=time.perf_counter_ns()result=func()return((time.perf_counter_ns()-start_ns)/1e9,result)runtimes=[]t,result=time_function_once()ift==0:t=1e-2else:runtimes.append(t)if(desired_runtimeisnotNone)and(repeatsisNone):repeats=int(desired_runtime//t)-1# print(f"Running {func.__name__} {repeats} times to get a desired runtime of {desired_runtime} seconds.")ifrepeatsisNone:repeats=0for_inrange(repeats):t,_=time_function_once()ift!=0:runtimes.append(t)iflen(runtimes)==0:runtimes=[0.0]return(runtime_reduction(runtimes),result)