summaryrefslogtreecommitdiff
path: root/bench/bench.py
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-09-25 18:12:01 +0000
committerSteven Knight <knight@baldmt.com>2005-09-25 18:12:01 +0000
commit781ba4618da6ab099b213fef0a73960459089558 (patch)
tree8f3f2d46b0ac09fb08f7dc9d9e9729a92fa2e7d0 /bench/bench.py
parent83d2c54302835180d4f130d75cd69a92b2d7fd9b (diff)
downloadscons-781ba4618da6ab099b213fef0a73960459089558.tar.gz
Optimize is_List et al. Add a script harness and scripts for benchmarking Python code snippets.
Diffstat (limited to 'bench/bench.py')
-rw-r--r--bench/bench.py123
1 files changed, 123 insertions, 0 deletions
diff --git a/bench/bench.py b/bench/bench.py
new file mode 100644
index 00000000..3c5dd50b
--- /dev/null
+++ b/bench/bench.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# A script for timing snippets of Python code.
+#
+# By default, this script will execute a single Python file specified on
+# the command line and time any functions in a list named "FunctionList"
+# set by the Python file under test, or (by default) time any functions
+# in the file whose names begin with "Func".
+#
+# All functions are assumed to get passed the same arguments, and the
+# inputs are specified in a list named "Data," each element of which
+# is a list consisting of a tag name, a list of positional arguments,
+# and a dictionary of keyword arguments.
+#
+# Each function is expected to test a single, comparable snippet of
+# of Python code. IMPORTANT: We want to test the timing of the code
+# itself, not Python function call overhead, so every function should
+# put its code under test within the following block:
+#
+# for i in IterationList:
+#
+# This will allow (as much as possible) us to time just the code itself,
+# not Python function call overhead.
+
+import getopt
+import sys
+import time
+import types
+
+Usage = """\
+Usage: bench.py OPTIONS file.py
+ --clock Use the time.clock function
+ --func PREFIX Test functions whose names begin with PREFIX
+ -h, --help Display this help and exit
+ -i ITER, --iterations ITER Run each code snippet ITER times
+ --time Use the time.time function
+ -r RUNS, --runs RUNS Average times for RUNS invocations of
+"""
+
+# How many times each snippet of code will be (or should be) run by the
+# functions under test to gather the time (the "inner loop").
+
+Iterations = 1000
+
+# How many times we'll run each function to collect its aggregate time
+# and try to average out timing differences induced by system performance
+# (the "outer loop").
+
+Runs = 10
+
+# The prefix of the functions under test. This will be used if
+# there's no explicit list defined in FunctionList.
+
+FunctionPrefix = 'Func'
+
+# The function used to get the current time. The default of time.time is
+# good on most UNIX systems, but time.clock (selectable via the --clock
+# option) is better on Windows and some other UNIX systems.
+
+Now = time.time
+
+
+opts, args = getopt.getopt(sys.argv[1:], 'hi:r:',
+ ['clock', 'func=', 'help',
+ 'iterations=', 'time', 'runs='])
+
+for o, a in opts:
+ if o in ['--clock']:
+ Now = time.clock
+ elif o in ['--func']:
+ FunctionPrefix = a
+ elif o in ['-h', '--help']:
+ sys.stdout.write(Usage)
+ sys.exit(0)
+ elif o in ['-i', '--iterations']:
+ Iterations = int(a)
+ elif o in ['--time']:
+ Now = time.time
+ elif o in ['-r', '--runs']:
+ Runs = int(a)
+
+if len(args) != 1:
+ sys.stderr.write("bench.py: only one file argument must be specified\n")
+ sys.stderr.write(Usage)
+ sys.exit(1)
+
+
+execfile(args[0])
+
+
+try:
+ FunctionList
+except NameError:
+ function_names = filter(lambda x: x[:4] == FunctionPrefix, locals().keys())
+ function_names.sort()
+ l = map(lambda f, l=locals(): l[f], function_names)
+ FunctionList = filter(lambda f: type(f) == types.FunctionType, l)
+
+IterationList = [None] * Iterations
+
+def timer(func, *args, **kw):
+ results = []
+ for i in range(Runs):
+ start = Now()
+ apply(func, args, kw)
+ finish = Now()
+ results.append((finish - start) / Iterations)
+ return results
+
+def display(label, results):
+ total = reduce(lambda x, y: x+y, results, 0.0)
+ print " %8.3f" % ((total * 1e6) / len(results)), ':', label
+
+for func in FunctionList:
+ if func.__doc__: d = ' (' + func.__doc__ + ')'
+ else: d = ''
+ print func.__name__ + d + ':'
+
+ for label, args, kw in Data:
+ r = apply(timer, (func,)+args, kw)
+ display(label, r)