Source code for minibench.benchmark

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import time
import sys

from collections import namedtuple

from .utils import humanize

DEFAULT_TIMES = 5


if sys.platform == "win32":
    # On Windows, the best timer is time.clock()
    timer = time.clock
else:
    # On most other platforms the best timer is time.time()
    timer = time.time

#: Store a single method execution result
RunResult = namedtuple('RunResult', ('duration', 'success', 'result'))


class Result(object):
    ''' Store an aggregated result for a single method'''
    def __init__(self):
        self.total = 0
        self.has_success = False
        self.has_errors = False
        self.error = None


[docs]class Benchmark(object): '''Base class for all benchmark suites''' times = DEFAULT_TIMES def __init__(self, times=None, prefix="bench_", debug=False, before=None, before_each=None, after=None, after_each=None, **kwargs): self.times = times or self.times self.results = {} self.debug = debug self._prefix = prefix self._before = before or self._noop self._before_each = before_each or self._noop self._after = after or self._noop self._after_each = after_each or self._noop @property def label(self): '''A human readable label''' if self.__doc__ and self.__doc__.strip(): return self.__doc__.strip().splitlines()[0] return humanize(self.__class__.__name__)
[docs] def label_for(self, name): '''Get a human readable label for a method given its name''' method = getattr(self, name) if method.__doc__ and method.__doc__.strip(): return method.__doc__.strip().splitlines()[0] return humanize(name.replace(self._prefix, ''))
def _noop(self, *args, **kwargs): pass
[docs] def before_class(self): '''Hook called before each class''' pass
[docs] def before(self): '''Hook called once before each method''' pass
[docs] def before_each(self): '''Hook called before each method''' pass
[docs] def after_each(self): '''Hook called after each method once''' pass
[docs] def after(self): '''Hook called once after each method''' pass
[docs] def after_class(self): '''Hook called after each class''' pass
def _collect(self): return [test for test in dir(self) if test.startswith(self._prefix)] def _run_one(self, func): self.before_each() tick = timer() success = True try: result = func() except Exception as e: success = False result = e duration = timer() - tick self.after_each() return RunResult(duration, success, result)
[docs] def run(self): ''' Collect all tests to run and run them. Each method will be run :attr:`Benchmark.times`. ''' tests = self._collect() if not tests: return self.times self.before_class() for test in tests: func = getattr(self, test) results = self.results[test] = Result() self._before(self, test) self.before() for i in range(self.times): self._before_each(self, test, i) result = self._run_one(func) results.total += result.duration if result.success: results.has_success = True else: results.has_errors = True self._after_each(self, test, i) if self.debug and not result.success: results.error = result.result break self.after() self._after(self, test) self.after_class()