diff options
author | Jason Kirtland <jek@discorporate.us> | 2008-01-05 21:56:22 +0000 |
---|---|---|
committer | Jason Kirtland <jek@discorporate.us> | 2008-01-05 21:56:22 +0000 |
commit | 68a9e6cb1fc53d6a989fa3ef6febcbe7ee304ebd (patch) | |
tree | 4a875c99e582f8fae423e0efe67463049040decc | |
parent | 40efd3a9c140ee199686becc08bfd7d7bb021ade (diff) | |
download | sqlalchemy-68a9e6cb1fc53d6a989fa3ef6febcbe7ee304ebd.tar.gz |
Added 'function_call_count' assertion decorator. The full-suite vs. isolated run call count discrepancy needs to be ironed out before this can be applied to zoomark.
-rw-r--r-- | test/testlib/profiling.py | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/test/testlib/profiling.py b/test/testlib/profiling.py index 947bf962e..61f6bb8f2 100644 --- a/test/testlib/profiling.py +++ b/test/testlib/profiling.py @@ -1,11 +1,11 @@ """Profiling support for unit and performance tests.""" import testbase +import os, sys from testlib.config import parser, post_configure import testlib.config -import os -__all__ = 'profiled', +__all__ = 'profiled', 'function_call_count' all_targets = set() profile_config = { 'targets': set(), @@ -19,7 +19,7 @@ def profiled(target=None, **target_opts): @profiled('label') or @profiled('label', report=True, sort=('calls',), limit=20) - + Enables profiling for a function when 'label' is targetted for profiling. Report options can be supplied, and override the global configuration and command-line options. @@ -55,7 +55,7 @@ def profiled(target=None, **target_opts): if not testlib.config.options.quiet: print "Profiled target '%s', wall time: %.2f seconds" % ( target, ended - began) - + report = target_opts.get('report', profile_config['report']) if report and testlib.config.options.verbose: sort_ = target_opts.get('sort', profile_config['sort']) @@ -76,7 +76,7 @@ def profiled(target=None, **target_opts): assert_range = assert_range.get(testlib.config.db, 'default') stats = hotshot.stats.load(filename) assert stats.total_calls >= assert_range[0] and stats.total_calls <= assert_range[1], stats.total_calls - + os.unlink(filename) return result try: @@ -85,3 +85,72 @@ def profiled(target=None, **target_opts): pass return profiled return decorator + +def function_call_count(count=None, versions={}, variance=0.05): + """Assert a target for a test case's function call count. + + count + Optional, general target function call count. + + versions + Optional, a dictionary of Python version strings to counts, + for example:: + + { '2.5.1': 110, + '2.5': 100, + '2.4': 150 } + + The best match for the current running python will be used. + If none match, 'count' will be used as the fallback. + + variance + An +/- deviation percentage, defaults to 5%. + """ + + version_info = list(sys.version_info) + py_version = '.'.join([str(v) for v in sys.version_info]) + + while version_info: + version = '.'.join([str(v) for v in version_info]) + if version in versions: + count = versions[version] + break + version_info.pop() + + if count is None: + return lambda fn: fn + + import hotshot, hotshot.stats + + def decorator(fn): + def counted(*args, **kw): + try: + filename = "%s.prof" % fn.__name__ + + prof = hotshot.Profile(filename) + prof.start() + try: + result = fn(*args, **kw) + finally: + prof.stop() + prof.close() + + stats = hotshot.stats.load(filename) + calls = stats.total_calls + deviance = int(count * variance) + if (calls < (count - deviance) or + calls > (count + deviance)): + raise AssertionError( + "Function call count %s not within %s%% " + "of expected %s. (Python version %s)" % ( + calls, variance, count, py_version)) + return result + finally: + if os.path.exists(filename): + os.unlink(filename) + try: + counted.__name__ = fn.__name__ + except: + pass + return counted + return decorator |