SCons / bench / bench.py

#!/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.
from __future__ import division

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)


exec(open(args[0], 'rU').read())


try:
    FunctionList
except NameError:
    function_names = sorted([x for x in locals().keys() if x[:4] == FunctionPrefix])
    l = [locals()[f] for f in function_names]
    FunctionList = [f for f in l if isinstance(f, types.FunctionType)]

IterationList = [None] * Iterations

def timer(func, *args, **kw):
    results = []
    for i in range(Runs):
        start = Now()
        func(*args, **kw)
        finish = Now()
        results.append((finish - start) / Iterations)
    return results

def display(label, results):
    total = 0.0
    for r in results:
        total += r
    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 = timer(func, *args, **kw)
        display(label, r)

# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.