Created
April 3, 2019 11:01
-
-
Save pmav99/48fe32958f2446e11057026219d2a17e to your computer and use it in GitHub Desktop.
Python timer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #! /usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| """ | |
| Just some classes that help benchmark execution speed. | |
| Timer : A context manager | |
| AutoTimer: A self-adjusting timer. It replicates the behavior of the timeit module. | |
| """ | |
| from __future__ import division | |
| from __future__ import print_function | |
| import gc | |
| import timeit | |
| __all__ = ["Timer", "AutoTimer"] | |
| def format_timing(timing, number_of_loops=1): | |
| """ | |
| Return timing + unit | |
| Input | |
| ===== | |
| timing : The timing in seconds. | |
| number_of_loops: The number of loops that were required to get this timing value. | |
| It defaults to 1. | |
| """ | |
| usec = timing * 1e6 / number_of_loops | |
| if usec < 1000: | |
| return usec, "usec" | |
| else: | |
| msec = usec / 1000 | |
| if msec < 1000: | |
| return msec, "msec" | |
| else: | |
| return timing, "sec" | |
| class Timer(object): | |
| """ | |
| A context manager that can be used to benchmark blocks of code (function calls etc). | |
| Usage | |
| ===== | |
| It should be used to code blocks of code that take "significant" time to be executed | |
| (e.g. milli-seconds). It is not suitable for micro-benchmarks because it introduces | |
| some overhead. | |
| Example | |
| ======= | |
| >>> with Timer() as t: | |
| >>> # whatever ... | |
| See also | |
| ======== | |
| Something like this may end up in the Standard library: http://bugs.python.org/issue19495 | |
| """ | |
| def __init__(self, timer=None, disable_gc=True, verbose=True, precision=3): | |
| if timer is None: | |
| timer = timeit.default_timer | |
| self.timer = timer | |
| self.disable_gc = disable_gc | |
| self.verbose = verbose | |
| self.precision = precision | |
| self.start = self.end = self.interval = None | |
| def __enter__(self): | |
| if self.disable_gc: | |
| self.gc_state = gc.isenabled() | |
| gc.disable() | |
| self.start = self.timer() | |
| return self | |
| def __exit__(self, *args): | |
| self.end = self.timer() | |
| if self.disable_gc and self.gc_state: | |
| gc.enable() | |
| self.seconds = self.end - self.start | |
| self.interval, self.unit = format_timing(self.seconds) | |
| if self.verbose: | |
| print('time taken: %.*g %s' % (self.precision, self.interval, self.unit)) | |
| class AutoTimer(timeit.Timer): | |
| """ | |
| An auto-adjustable Timer. It subclasses timeit.Timer and adds a new method named `auto()`. | |
| This one is suitable for micro benchmarks. It can be used with both python functions and | |
| python statements (e.g. strings) | |
| Usage | |
| ===== | |
| >>> def f(): | |
| >>> return [i**2 for i in range(int(1e2))] | |
| >>> best = AutoTimer(f).auto(verbose=True, repeat=10) | |
| >>> print(best) | |
| See also | |
| ======== | |
| There is an open bug for this one too: http://bugs.python.org/issue6422 | |
| The documentation: https://docs.python.org/3.4/library/timeit.html#timeit.Timer | |
| """ | |
| def auto(self, repeat=3, verbose=True, precision=3): | |
| """ Auto-determine how many times to execute the given statement """ | |
| # determine number of required loops so that 0.2 <= total time < 2.0 | |
| number_of_loops = 0 | |
| for i in range(1, 10): | |
| number_of_loops = 10**i | |
| try: | |
| execution_time = self.timeit(number_of_loops) | |
| except Exception: | |
| self.print_exc() | |
| return 1 | |
| if verbose: | |
| print("%d loops -> %.*g secs" % (number_of_loops, precision, execution_time)) | |
| if execution_time >= 0.2: | |
| break | |
| # now that we have determined how many times we should loop, | |
| # execute the statements as many times as we need | |
| try: | |
| r = self.repeat(repeat, number_of_loops) | |
| except Exception: | |
| self.print_exc() | |
| return 1 | |
| best = min(r) | |
| timing, unit = format_timing(best, number_of_loops) | |
| # print results | |
| if verbose: | |
| print("raw times:", " ".join(["%.*g" % (precision, x) for x in r])) | |
| print("%d loops, best of %d: %.*g %s per loop" % (number_of_loops, repeat, precision, timing, unit)) | |
| return best | |
| if __name__ == "__main__": | |
| def f(): | |
| return [i**2 for i in range(int(1e2))] | |
| best = AutoTimer(f).auto(verbose=True, repeat=10) | |
| print() | |
| print("context manager") | |
| with Timer() as t: | |
| f() | |
| __all__ = [ | |
| "Timer", | |
| "AutoTimer", | |
| ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment