Last active
February 24, 2020 18:01
-
-
Save andreberg/5691839 to your computer and use it in GitHub Desktop.
[Benchmark Decorator] Prints the time a function take to execute per call and cumulative total. Works with Python 2.7 and Python 3. #python #python3 #benchmark #decorator
This file contains 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
# -*- coding: utf-8 -*- | |
# | |
# Created by André Berg on Jun 2, 2013. | |
# Copyright 2013 Berg Media. All rights reserved. | |
# | |
from functools import wraps, partial | |
def benchmark(func=None, prec=3, unit='auto', name_width=0, time_width=8): | |
""" | |
A decorator that prints the time a function takes | |
to execute per call and cumulative total. | |
Accepts the following keyword arguments: | |
`unit` str time unit for display. one of `[auto, us, ms, s, m]`. | |
`prec` int radix point precision. | |
`name_width` int width of the right-aligned function name field. | |
`time_width` int width of the right-aligned time value field. | |
For convenience you can also set attributes on the benchmark | |
function itself with the same name as the keyword arguments | |
and the value of those will be used instead. This saves you | |
from having to call the decorator with the same arguments each | |
time you use it. Just set, for example, `benchmark.prec = 5` | |
before you use the decorator for the first time. | |
""" | |
import time | |
if hasattr(benchmark, 'prec'): | |
prec = getattr(benchmark, 'prec') | |
if hasattr(benchmark, 'unit'): | |
unit = getattr(benchmark, 'unit') | |
if hasattr(benchmark, 'name_width'): | |
name_width = getattr(benchmark, 'name_width') | |
if hasattr(benchmark, 'time_width'): | |
time_width = getattr(benchmark, 'time_width') | |
if func is None: | |
return partial(benchmark, prec=prec, unit=unit, | |
name_width=name_width, time_width=time_width) | |
@wraps(func) | |
def wrapper(*args, **kwargs): # IGNORE:W0613 | |
def _get_unit_mult(val, unit): | |
multipliers = {'us': 1000000.0, 'ms': 1000.0, 's': 1.0, 'm': (1.0 / 60.0)} | |
if unit in multipliers: | |
mult = multipliers[unit] | |
else: # auto | |
if val >= 60.0: | |
unit = "m" | |
elif val >= 1.0: | |
unit = "s" | |
elif val <= 0.001: | |
unit = "us" | |
else: | |
unit = "ms" | |
mult = multipliers[unit] | |
return (unit, mult) | |
t = time.clock() | |
res = func(*args, **kwargs) | |
td = (time.clock() - t) | |
wrapper.total += td | |
wrapper.count += 1 | |
tt = wrapper.total | |
cn = wrapper.count | |
tdu, tdm = _get_unit_mult(td, unit) | |
ttu, ttm = _get_unit_mult(tt, unit) | |
td *= tdm | |
tt *= ttm | |
print(" -> {0:>{8}}() @ {1:>03}: {3:>{7}.{2}f} {4:>2}, total: {5:>{7}.{2}f} {6:>2}" | |
.format(func.__name__, cn, prec, td, tdu, tt, ttu, time_width, name_width)) | |
return res | |
wrapper.total = 0 | |
wrapper.count = 0 | |
return wrapper | |
if __name__ == '__main__': | |
@benchmark | |
def bla(n, m): | |
return n ** m | |
for i in range(15): | |
bla(i, i ** 6) | |
# sample output: | |
# -> bla() @ 001: 6.000 us, total: 6.000 us | |
# -> bla() @ 002: 3.000 us, total: 9.000 us | |
# -> bla() @ 003: 12.000 us, total: 21.000 us | |
# -> bla() @ 004: 7.000 us, total: 28.000 us | |
# -> bla() @ 005: 33.000 us, total: 61.000 us | |
# -> bla() @ 006: 330.000 us, total: 391.000 us | |
# -> bla() @ 007: 1.921 ms, total: 2.312 ms | |
# -> bla() @ 008: 10.941 ms, total: 13.253 ms | |
# -> bla() @ 009: 4.479 ms, total: 17.732 ms | |
# -> bla() @ 010: 148.302 ms, total: 166.034 ms | |
# -> bla() @ 011: 377.794 ms, total: 543.828 ms | |
# -> bla() @ 012: 1.133 s, total: 1.677 s | |
# -> bla() @ 013: 1.754 s, total: 3.431 s | |
# -> bla() @ 014: 6.063 s, total: 9.494 s | |
# -> bla() @ 015: 11.817 s, total: 21.311 s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@andreberg: can you MIT license this?