import functools import math import sys import timeit def TimeitWrapper(*args, **kwargs): """ This decorator @TimeitWrapper() prints the function name and execution time in seconds. :param args: :param kwargs: :return: """ def decorator(function): @functools.wraps(function) def wrapper(*args, **kwargs): start = timeit.default_timer() results = function(*args, **kwargs) end = timeit.default_timer() print('{} execution time: {:.10f} s'.format(function.__name__, end - start)) return results return wrapper return decorator class TimeitResult(object): """ from https://github.com/ipython/ipython/blob/339c0d510a1f3cb2158dd8c6e7f4ac89aa4c89d8/IPython/core/magics/execution.py#L55 Object returned by the timeit magic with info about the run. Contains the following attributes : loops: (int) number of loops done per measurement repeat: (int) number of times the measurement has been repeated best: (float) best execution time / number all_runs: (list of float) execution time of each run (in s) """ def __init__(self, loops, repeat, best, worst, all_runs, precision): self.loops = loops self.repeat = repeat self.best = best self.worst = worst self.all_runs = all_runs self._precision = precision self.timings = [dt / self.loops for dt in all_runs] @property def average(self): return math.fsum(self.timings) / len(self.timings) @property def stdev(self): mean = self.average return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 def __str__(self): pm = '+-' if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: try: u'\xb1'.encode(sys.stdout.encoding) pm = u'\xb1' except: pass return "min:{best} max:{worst} mean:{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format( pm=pm, runs=self.repeat, loops=self.loops, loop_plural="" if self.loops == 1 else "s", run_plural="" if self.repeat == 1 else "s", mean=format_time(self.average, self._precision), std=format_time(self.stdev, self._precision), best=format_time(self.best, self._precision), worst=format_time(self.worst, self._precision), ) def _repr_pretty_(self, p, cycle): unic = self.__str__() p.text(u'') class FPSResult(object): """ base https://github.com/ipython/ipython/blob/339c0d510a1f3cb2158dd8c6e7f4ac89aa4c89d8/IPython/core/magics/execution.py#L55 """ def __init__(self, loops, repeat, best, worst, all_runs, precision): self.loops = loops self.repeat = repeat self.best = 1 / best self.worst = 1 / worst self.all_runs = all_runs self._precision = precision self.fps = [1 / dt for dt in all_runs] self.unit = "fps" @property def average(self): return math.fsum(self.fps) / len(self.fps) @property def stdev(self): mean = self.average return (math.fsum([(x - mean) ** 2 for x in self.fps]) / len(self.fps)) ** 0.5 def __str__(self): pm = '+-' if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: try: u'\xb1'.encode(sys.stdout.encoding) pm = u'\xb1' except: pass return "min:{best} max:{worst} mean:{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format( pm=pm, runs=self.repeat, loops=self.loops, loop_plural="" if self.loops == 1 else "s", run_plural="" if self.repeat == 1 else "s", mean="%.*g%s" % (self._precision, self.average, self.unit), std="%.*g%s" % (self._precision, self.stdev, self.unit), best="%.*g%s" % (self._precision, self.best, self.unit), worst="%.*g%s" % (self._precision, self.worst, self.unit), ) def _repr_pretty_(self, p, cycle): unic = self.__str__() p.text(u'') def format_time(timespan, precision=3): """ https://github.com/ipython/ipython/blob/339c0d510a1f3cb2158dd8c6e7f4ac89aa4c89d8/IPython/core/magics/execution.py#L1473 Formats the timespan in a human readable form """ if timespan >= 60.0: # we have more than a minute, format that in a human readable form # Idea from http://snipplr.com/view/5713/ parts = [("d", 60 * 60 * 24), ("h", 60 * 60), ("min", 60), ("s", 1)] time = [] leftover = timespan for suffix, length in parts: value = int(leftover / length) if value > 0: leftover = leftover % length time.append(u'%s%s' % (str(value), suffix)) if leftover < 1: break return " ".join(time) # Unfortunately the unicode 'micro' symbol can cause problems in # certain terminals. # See bug: https://bugs.launchpad.net/ipython/+bug/348466 # Try to prevent crashes by being more secure than it needs to # E.g. eclipse is able to print a ยต, but has no sys.stdout.encoding set. units = [u"s", u"ms", u'us', "ns"] # the save value if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: try: u'\xb5'.encode(sys.stdout.encoding) units = [u"s", u"ms", u'\xb5s', "ns"] except: pass scaling = [1, 1e3, 1e6, 1e9] if timespan > 0.0: order = min(-int(math.floor(math.log10(timespan)) // 3), 3) else: order = 3 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])