"""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 not name 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