This recipe explains how to check that a given function does not run slower than a given pystone rate. It first calculates the pystone ratio on your box.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # by Tarek Ziadé
# let's use pystone instead of seconds here
# (from Stephan Richter idea)
from test import pystone
import time
# TOLERANCE in Pystones
kPS = 1000
TOLERANCE = 0.5*kPS
class DurationError(AssertionError): pass
def local_pystone():
return pystone.pystones(loops=pystone.LOOPS)
def timedtest(max_num_pystones, current_pystone=local_pystone()):
""" decorator timedtest """
if not isinstance(max_num_pystones, float):
max_num_pystones = float(max_num_pystones)
def _timedtest(function):
def wrapper(*args, **kw):
start_time = time.time()
try:
return function(*args, **kw)
finally:
total_time = time.time() - start_time
if total_time == 0:
pystone_total_time = 0
else:
pystone_rate = current_pystone[0] / current_pystone[1]
pystone_total_time = total_time / pystone_rate
if pystone_total_time > (max_num_pystones + TOLERANCE):
raise DurationError((('Test too long (%.2f Ps, '
'need at most %.2f Ps)')
% (pystone_total_time,
max_num_pystones)))
return wrapper
return _timedtest
This decorator is not to use in production code, and would rather
fit in functional or unit tests. This make performance tests portable to any box and fits performance regression tests you would want to run in unit tests.
For example, in this test we want to be sure test_critical() does not last more than 2kPS:
>>> import unittest
>>> class MesTests(unittest.TestCase):
... @timedtest(2*kPS)
... def test_critical(self):
... a =''
... for i in range(50000):
... a = a + 'x' * 200
>>> suite = unittest.makeSuite(MesTests)
>>> unittest.TextTestRunner().run(suite)
<unittest._TextTestResult run=1 errors=0 failures=0>
|
DurationError is an AssertionError so it is reported as a failure in tests.
local_pystone() is separated so you can call it once for many tests,and give it in the second argument of the decorator.
TOLERANCE is used to prevent failures for a busy CPU. (it's faster than using a 3-times test like hotshot does)