384 lines
14 KiB
Plaintext
384 lines
14 KiB
Plaintext
________________________________________________________________________
|
|
|
|
PYBENCH - A Python Benchmark Suite
|
|
________________________________________________________________________
|
|
|
|
Extendable suite of of low-level benchmarks for measuring
|
|
the performance of the Python implementation
|
|
(interpreter, compiler or VM).
|
|
|
|
pybench is a collection of tests that provides a standardized way to
|
|
measure the performance of Python implementations. It takes a very
|
|
close look at different aspects of Python programs and let's you
|
|
decide which factors are more important to you than others, rather
|
|
than wrapping everything up in one number, like the other performance
|
|
tests do (e.g. pystone which is included in the Python Standard
|
|
Library).
|
|
|
|
pybench has been used in the past by several Python developers to
|
|
track down performance bottlenecks or to demonstrate the impact of
|
|
optimizations and new features in Python.
|
|
|
|
The command line interface for pybench is the file pybench.py. Run
|
|
this script with option '--help' to get a listing of the possible
|
|
options. Without options, pybench will simply execute the benchmark
|
|
and then print out a report to stdout.
|
|
|
|
|
|
Micro-Manual
|
|
------------
|
|
|
|
Run 'pybench.py -h' to see the help screen.
|
|
Run 'pybench.py' to just let the benchmark suite do it's thing and
|
|
'pybench.py -f <file>' to have it store the results in a file too.
|
|
|
|
This is the current output of pybench.py --help:
|
|
|
|
Synopsis:
|
|
pybench.py [option] files...
|
|
|
|
Options and default settings:
|
|
-n arg number of rounds (10)
|
|
-f arg save benchmark to file arg ()
|
|
-c arg compare benchmark with the one in file arg ()
|
|
-s arg show benchmark in file arg, then exit ()
|
|
-S show statistics of benchmarks (0)
|
|
-w arg set warp factor to arg (20)
|
|
-d hide noise in compares (0)
|
|
--no-gc disable garbage collection (0)
|
|
--no-syscheck "disable" sys check interval (set to sys.maxint) (0)
|
|
-t arg tests containing substring ()
|
|
-C arg number of calibration runs (20)
|
|
-v generate verbose output
|
|
-h show this help text
|
|
--help show this help text
|
|
--debug enable debugging
|
|
--copyright show copyright
|
|
--examples show examples of usage
|
|
|
|
Version:
|
|
1.3
|
|
|
|
The normal operation is to run the suite and display the
|
|
results. Use -f to save them for later reuse or comparisms.
|
|
|
|
Examples:
|
|
|
|
python1.5 pybench.py -w 100 -f p15
|
|
python1.4 pybench.py -w 100 -f p14
|
|
python pybench.py -s p15 -c p14
|
|
|
|
|
|
License
|
|
-------
|
|
|
|
See LICENSE file.
|
|
|
|
|
|
Sample output
|
|
-------------
|
|
|
|
PYBENCH 1.3
|
|
|
|
Machine Details:
|
|
Platform ID: Linux-2.6.8-24.19-default-x86_64-with-SuSE-9.2-x86-64
|
|
Executable: /home/lemburg/projects/Python/Installation/bin/python
|
|
Python: 2.5a1.0
|
|
Compiler: GCC 3.3.4 (pre 3.3.5 20040809)
|
|
Build: Apr 9 2006 01:50:57 (#trunk)
|
|
|
|
Searching for tests...
|
|
BuiltinFunctionCalls
|
|
BuiltinMethodLookup
|
|
CompareFloats
|
|
CompareFloatsIntegers
|
|
CompareIntegers
|
|
CompareInternedStrings
|
|
CompareLongs
|
|
CompareStrings
|
|
CompareUnicode
|
|
ConcatStrings
|
|
ConcatUnicode
|
|
CreateInstances
|
|
CreateStringsWithConcat
|
|
CreateUnicodeWithConcat
|
|
DictCreation
|
|
DictWithFloatKeys
|
|
DictWithIntegerKeys
|
|
DictWithStringKeys
|
|
ForLoops
|
|
IfThenElse
|
|
ListSlicing
|
|
NestedForLoops
|
|
NormalClassAttribute
|
|
NormalInstanceAttribute
|
|
PythonFunctionCalls
|
|
PythonMethodCalls
|
|
Recursion
|
|
SecondImport
|
|
SecondPackageImport
|
|
SecondSubmoduleImport
|
|
SimpleComplexArithmetic
|
|
SimpleDictManipulation
|
|
SimpleFloatArithmetic
|
|
SimpleIntFloatArithmetic
|
|
SimpleIntegerArithmetic
|
|
SimpleListManipulation
|
|
SimpleLongArithmetic
|
|
SmallLists
|
|
SmallTuples
|
|
SpecialClassAttribute
|
|
SpecialInstanceAttribute
|
|
StringMappings
|
|
StringPredicates
|
|
StringSlicing
|
|
TryExcept
|
|
TryRaiseExcept
|
|
TupleSlicing
|
|
UnicodeMappings
|
|
UnicodePredicates
|
|
UnicodeProperties
|
|
UnicodeSlicing
|
|
|
|
Running 10 round(s) of the suite:
|
|
|
|
...
|
|
|
|
Round 10 real abs overhead
|
|
BuiltinFunctionCalls: 0.030r 0.030a 0.000o
|
|
BuiltinMethodLookup: 0.059r 0.060a 0.001o
|
|
CompareFloats: 0.050r 0.050a 0.000o
|
|
CompareFloatsIntegers: 0.050r 0.050a 0.000o
|
|
CompareIntegers: 0.070r 0.070a 0.000o
|
|
CompareInternedStrings: 0.039r 0.040a 0.001o
|
|
CompareLongs: 0.050r 0.050a 0.000o
|
|
CompareStrings: 0.060r 0.060a 0.000o
|
|
CompareUnicode: 0.060r 0.060a 0.000o
|
|
ConcatStrings: 0.040r 0.040a 0.000o
|
|
ConcatUnicode: 0.050r 0.050a 0.000o
|
|
CreateInstances: 0.050r 0.050a 0.000o
|
|
CreateStringsWithConcat: 0.029r 0.030a 0.001o
|
|
CreateUnicodeWithConcat: 0.060r 0.060a 0.000o
|
|
DictCreation: 0.040r 0.040a 0.000o
|
|
DictWithFloatKeys: 0.089r 0.090a 0.000o
|
|
DictWithIntegerKeys: 0.059r 0.060a 0.001o
|
|
DictWithStringKeys: 0.070r 0.070a 0.001o
|
|
ForLoops: 0.050r 0.050a 0.000o
|
|
IfThenElse: 0.070r 0.070a 0.000o
|
|
ListSlicing: 0.030r 0.030a 0.000o
|
|
NestedForLoops: 0.030r 0.030a 0.000o
|
|
NormalClassAttribute: 0.060r 0.060a 0.000o
|
|
NormalInstanceAttribute: 0.060r 0.060a 0.000o
|
|
PythonFunctionCalls: 0.060r 0.060a 0.000o
|
|
PythonMethodCalls: 0.050r 0.050a 0.000o
|
|
Recursion: 0.050r 0.050a 0.000o
|
|
SecondImport: 0.030r 0.030a 0.000o
|
|
SecondPackageImport: 0.030r 0.030a 0.000o
|
|
SecondSubmoduleImport: 0.040r 0.040a 0.000o
|
|
SimpleComplexArithmetic: 0.030r 0.030a 0.000o
|
|
SimpleDictManipulation: 0.040r 0.040a 0.000o
|
|
SimpleFloatArithmetic: 0.050r 0.050a 0.001o
|
|
SimpleIntFloatArithmetic: 0.060r 0.060a 0.000o
|
|
SimpleIntegerArithmetic: 0.060r 0.060a 0.000o
|
|
SimpleListManipulation: 0.030r 0.030a 0.000o
|
|
SimpleLongArithmetic: 0.030r 0.030a 0.000o
|
|
SmallLists: 0.050r 0.050a 0.000o
|
|
SmallTuples: 0.050r 0.050a 0.000o
|
|
SpecialClassAttribute: 0.060r 0.060a 0.000o
|
|
SpecialInstanceAttribute: 0.079r 0.080a 0.001o
|
|
StringMappings: 0.060r 0.060a 0.000o
|
|
StringPredicates: 0.049r 0.050a 0.001o
|
|
StringSlicing: 0.039r 0.040a 0.000o
|
|
TryExcept: 0.079r 0.080a 0.001o
|
|
TryRaiseExcept: 0.059r 0.060a 0.001o
|
|
TupleSlicing: 0.050r 0.050a 0.000o
|
|
UnicodeMappings: 0.070r 0.070a 0.001o
|
|
UnicodePredicates: 0.059r 0.060a 0.001o
|
|
UnicodeProperties: 0.059r 0.060a 0.001o
|
|
UnicodeSlicing: 0.050r 0.050a 0.000o
|
|
----------------------
|
|
Average round time: 2.937 seconds
|
|
|
|
|
|
Tests: per run per oper. overhead
|
|
------------------------------------------------------------------------
|
|
BuiltinFunctionCalls: 29.85 ms 0.23 us 0.00 ms
|
|
BuiltinMethodLookup: 66.85 ms 0.13 us 0.50 ms
|
|
CompareFloats: 43.00 ms 0.10 us 0.00 ms
|
|
CompareFloatsIntegers: 51.80 ms 0.12 us 0.00 ms
|
|
CompareIntegers: 70.70 ms 0.08 us 0.50 ms
|
|
CompareInternedStrings: 41.40 ms 0.08 us 0.50 ms
|
|
CompareLongs: 47.90 ms 0.11 us 0.00 ms
|
|
CompareStrings: 58.50 ms 0.12 us 0.50 ms
|
|
CompareUnicode: 56.55 ms 0.15 us 0.50 ms
|
|
ConcatStrings: 44.75 ms 0.30 us 0.00 ms
|
|
ConcatUnicode: 54.55 ms 0.36 us 0.50 ms
|
|
CreateInstances: 50.95 ms 1.21 us 0.00 ms
|
|
CreateStringsWithConcat: 28.85 ms 0.14 us 0.50 ms
|
|
CreateUnicodeWithConcat: 53.75 ms 0.27 us 0.00 ms
|
|
DictCreation: 41.90 ms 0.28 us 0.00 ms
|
|
DictWithFloatKeys: 88.50 ms 0.15 us 0.50 ms
|
|
DictWithIntegerKeys: 62.55 ms 0.10 us 0.50 ms
|
|
DictWithStringKeys: 60.50 ms 0.10 us 0.50 ms
|
|
ForLoops: 46.90 ms 4.69 us 0.00 ms
|
|
IfThenElse: 60.55 ms 0.09 us 0.00 ms
|
|
ListSlicing: 29.90 ms 8.54 us 0.00 ms
|
|
NestedForLoops: 33.95 ms 0.10 us 0.00 ms
|
|
NormalClassAttribute: 62.75 ms 0.10 us 0.50 ms
|
|
NormalInstanceAttribute: 61.80 ms 0.10 us 0.50 ms
|
|
PythonFunctionCalls: 60.00 ms 0.36 us 0.00 ms
|
|
PythonMethodCalls: 50.00 ms 0.67 us 0.00 ms
|
|
Recursion: 46.85 ms 3.75 us 0.00 ms
|
|
SecondImport: 35.00 ms 1.40 us 0.00 ms
|
|
SecondPackageImport: 32.00 ms 1.28 us 0.00 ms
|
|
SecondSubmoduleImport: 38.00 ms 1.52 us 0.00 ms
|
|
SimpleComplexArithmetic: 26.85 ms 0.12 us 0.00 ms
|
|
SimpleDictManipulation: 40.85 ms 0.14 us 0.00 ms
|
|
SimpleFloatArithmetic: 48.70 ms 0.09 us 0.50 ms
|
|
SimpleIntFloatArithmetic: 57.70 ms 0.09 us 0.00 ms
|
|
SimpleIntegerArithmetic: 58.75 ms 0.09 us 0.50 ms
|
|
SimpleListManipulation: 34.80 ms 0.13 us 0.00 ms
|
|
SimpleLongArithmetic: 30.95 ms 0.19 us 0.50 ms
|
|
SmallLists: 47.60 ms 0.19 us 0.00 ms
|
|
SmallTuples: 48.80 ms 0.20 us 0.50 ms
|
|
SpecialClassAttribute: 61.70 ms 0.10 us 0.00 ms
|
|
SpecialInstanceAttribute: 76.70 ms 0.13 us 0.50 ms
|
|
StringMappings: 58.70 ms 0.47 us 0.00 ms
|
|
StringPredicates: 50.00 ms 0.18 us 1.00 ms
|
|
StringSlicing: 39.65 ms 0.23 us 0.50 ms
|
|
TryExcept: 84.45 ms 0.06 us 0.50 ms
|
|
TryRaiseExcept: 61.75 ms 4.12 us 0.50 ms
|
|
TupleSlicing: 48.95 ms 0.47 us 0.00 ms
|
|
UnicodeMappings: 71.50 ms 3.97 us 0.50 ms
|
|
UnicodePredicates: 52.75 ms 0.23 us 1.00 ms
|
|
UnicodeProperties: 61.90 ms 0.31 us 1.00 ms
|
|
UnicodeSlicing: 53.75 ms 0.31 us 0.50 ms
|
|
------------------------------------------------------------------------
|
|
Average round time: 2937.00 ms
|
|
|
|
________________________________________________________________________
|
|
|
|
Writing New Tests
|
|
________________________________________________________________________
|
|
|
|
pybench tests are simple modules defining one or more pybench.Test
|
|
subclasses.
|
|
|
|
Writing a test essentially boils down to providing two methods:
|
|
.test() which runs .rounds number of .operations test operations each
|
|
and .calibrate() which does the same except that it doesn't actually
|
|
execute the operations.
|
|
|
|
|
|
Here's an example:
|
|
------------------
|
|
|
|
from pybench import Test
|
|
|
|
class IntegerCounting(Test):
|
|
|
|
# Version number of the test as float (x.yy); this is important
|
|
# for comparisons of benchmark runs - tests with unequal version
|
|
# number will not get compared.
|
|
version = 1.0
|
|
|
|
# The number of abstract operations done in each round of the
|
|
# test. An operation is the basic unit of what you want to
|
|
# measure. The benchmark will output the amount of run-time per
|
|
# operation. Note that in order to raise the measured timings
|
|
# significantly above noise level, it is often required to repeat
|
|
# sets of operations more than once per test round. The measured
|
|
# overhead per test round should be less than 1 second.
|
|
operations = 20
|
|
|
|
# Number of rounds to execute per test run. This should be
|
|
# adjusted to a figure that results in a test run-time of between
|
|
# 20-50 seconds.
|
|
rounds = 100000
|
|
|
|
def test(self):
|
|
|
|
""" Run the test.
|
|
|
|
The test needs to run self.rounds executing
|
|
self.operations number of operations each.
|
|
|
|
"""
|
|
# Init the test
|
|
a = 1
|
|
|
|
# Run test rounds
|
|
#
|
|
# NOTE: Use xrange() for all test loops unless you want to face
|
|
# a 20MB process !
|
|
#
|
|
for i in xrange(self.rounds):
|
|
|
|
# Repeat the operations per round to raise the run-time
|
|
# per operation significantly above the noise level of the
|
|
# for-loop overhead.
|
|
|
|
# Execute 20 operations (a += 1):
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
a += 1
|
|
|
|
def calibrate(self):
|
|
|
|
""" Calibrate the test.
|
|
|
|
This method should execute everything that is needed to
|
|
setup and run the test - except for the actual operations
|
|
that you intend to measure. pybench uses this method to
|
|
measure the test implementation overhead.
|
|
|
|
"""
|
|
# Init the test
|
|
a = 1
|
|
|
|
# Run test rounds (without actually doing any operation)
|
|
for i in xrange(self.rounds):
|
|
|
|
# Skip the actual execution of the operations, since we
|
|
# only want to measure the test's administration overhead.
|
|
pass
|
|
|
|
Registering a new test module
|
|
-----------------------------
|
|
|
|
To register a test module with pybench, the classes need to be
|
|
imported into the pybench.Setup module. pybench will then scan all the
|
|
symbols defined in that module for subclasses of pybench.Test and
|
|
automatically add them to the benchmark suite.
|
|
|
|
|
|
Breaking Comparability
|
|
----------------------
|
|
|
|
If a change is made to any individual test that means it is no
|
|
longer strictly comparable with previous runs, the '.version' class
|
|
variable should be updated. Therefafter, comparisons with previous
|
|
versions of the test will list as "n/a" to reflect the change.
|
|
|
|
Have fun,
|
|
--
|
|
Marc-Andre Lemburg
|
|
mal@lemburg.com
|