77 lines
1.9 KiB
Python
77 lines
1.9 KiB
Python
"""Simple tools for timing functions' execution, when IPython is not available. """
|
|
|
|
|
|
import timeit
|
|
import math
|
|
|
|
|
|
_scales = [1e0, 1e3, 1e6, 1e9]
|
|
_units = ['s', 'ms', '\N{GREEK SMALL LETTER MU}s', 'ns']
|
|
|
|
|
|
def timed(func, setup="pass", limit=None):
|
|
"""Adaptively measure execution time of a function. """
|
|
timer = timeit.Timer(func, setup=setup)
|
|
repeat, number = 3, 1
|
|
|
|
for i in range(1, 10):
|
|
if timer.timeit(number) >= 0.2:
|
|
break
|
|
elif limit is not None and number >= limit:
|
|
break
|
|
else:
|
|
number *= 10
|
|
|
|
time = min(timer.repeat(repeat, number)) / number
|
|
|
|
if time > 0.0:
|
|
order = min(-int(math.floor(math.log10(time)) // 3), 3)
|
|
else:
|
|
order = 3
|
|
|
|
return (number, time, time*_scales[order], _units[order])
|
|
|
|
|
|
# Code for doing inline timings of recursive algorithms.
|
|
|
|
def __do_timings():
|
|
import os
|
|
res = os.getenv('SYMPY_TIMINGS', '')
|
|
res = [x.strip() for x in res.split(',')]
|
|
return set(res)
|
|
|
|
_do_timings = __do_timings()
|
|
_timestack = None
|
|
|
|
|
|
def _print_timestack(stack, level=1):
|
|
print('-'*level, '%.2f %s%s' % (stack[2], stack[0], stack[3]))
|
|
for s in stack[1]:
|
|
_print_timestack(s, level + 1)
|
|
|
|
|
|
def timethis(name):
|
|
def decorator(func):
|
|
global _do_timings
|
|
if name not in _do_timings:
|
|
return func
|
|
|
|
def wrapper(*args, **kwargs):
|
|
from time import time
|
|
global _timestack
|
|
oldtimestack = _timestack
|
|
_timestack = [func.func_name, [], 0, args]
|
|
t1 = time()
|
|
r = func(*args, **kwargs)
|
|
t2 = time()
|
|
_timestack[2] = t2 - t1
|
|
if oldtimestack is not None:
|
|
oldtimestack[1].append(_timestack)
|
|
_timestack = oldtimestack
|
|
else:
|
|
_print_timestack(_timestack)
|
|
_timestack = None
|
|
return r
|
|
return wrapper
|
|
return decorator
|