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>
|