test: Execution profiling

Adds cprofile to the testenv:py27, as well as to falcon-bench. In the latter
case, add the '-p' switch to profile instead of run timeit. If you would like
the profiling info dumped to a data file, set the filename using '-o'.

Closes #139
This commit is contained in:
kgriffs
2013-05-15 19:11:28 -05:00
parent 352127e724
commit e3304c13c0
5 changed files with 65 additions and 20 deletions

1
.gitignore vendored
View File

@@ -26,6 +26,7 @@ pip-log.txt
.tox
nosetests.xml
htmlcov
*.dat
# Translations
*.mo

View File

@@ -5,6 +5,7 @@ from __future__ import print_function
import argparse
from collections import defaultdict
import cProfile
from decimal import Decimal
import gc
import random
@@ -30,6 +31,28 @@ def bench(name, iterations, env):
return (name, sec_per_req)
def profile(name, env, output=None):
if output:
filename = name + '-' + output
print('Profiling %s ==> %s' %(name, filename))
else:
filename = None
title = name + ' profile'
print()
print('=' * len(title))
print(title)
print('=' * len(title))
func = create_bench(name, env)
gc.collect()
code = 'for x in xrange(10000): func()'
cProfile.runctx(code, locals(), globals(),
sort='tottime', filename=filename)
def create_bench(name, env):
srmock = helpers.StartResponseMock()
@@ -121,9 +144,12 @@ def run(frameworks, repetitions, iterations):
def main():
frameworks = [
'flask', 'werkzeug', 'falcon',
'pecan', 'bottle', 'falcon-ext'
'bottle',
'falcon',
'falcon-ext',
'flask',
'pecan',
'werkzeug'
]
parser = argparse.ArgumentParser(description="Falcon benchmark runner")
@@ -131,25 +157,32 @@ def main():
choices=frameworks, dest='frameworks')
parser.add_argument('-i', '--iterations', type=int, default=50000)
parser.add_argument('-r', '--repetitions', type=int, default=3)
parser.add_argument('-p', '--profile', action='store_true')
parser.add_argument('-o', '--profile-output', type=str, default=None)
args = parser.parse_args()
if args.frameworks:
frameworks = args.frameworks
datasets = run(frameworks, args.repetitions, args.iterations)
if args.profile:
for name in frameworks:
profile(name, get_env(name), args.profile_output)
dataset = consolidate_datasets(datasets)
dataset = sorted(dataset, key=lambda r: r[1])
baseline = dataset[-1][1]
else:
datasets = run(frameworks, args.repetitions, args.iterations)
print('\nResults:\n')
dataset = consolidate_datasets(datasets)
dataset = sorted(dataset, key=lambda r: r[1])
baseline = dataset[-1][1]
for i, (name, sec_per_req) in enumerate(dataset):
req_per_sec = round_to_int(Decimal(1) / sec_per_req)
us_per_req = (sec_per_req * Decimal(10 ** 6))
factor = round_to_int(baseline / sec_per_req)
print('\nResults:\n')
print('{3}. {0:.<15s}{1:.>06,d} req/sec or {2: >3.2f} μs/req ({4}x)'.
format(name, req_per_sec, us_per_req, i + 1, factor))
for i, (name, sec_per_req) in enumerate(dataset):
req_per_sec = round_to_int(Decimal(1) / sec_per_req)
us_per_req = (sec_per_req * Decimal(10 ** 6))
factor = round_to_int(baseline / sec_per_req)
print('')
print('{3}. {0:.<15s}{1:.>06,d} req/sec or {2: >3.2f} μs/req ({4}x)'.
format(name, req_per_sec, us_per_req, i + 1, factor))
print()

View File

@@ -3,6 +3,8 @@ tag_build = dev
[nosetests]
where = falcon/tests
verbosity = 2
with-coverage = true
cover-min-percentage = 100
cover-package = falcon
@@ -11,5 +13,3 @@ cover-html-dir = htmlcov
cover-erase = true
cover-inclusive = true
cover-branches = true
verbosity = 2

View File

@@ -41,7 +41,6 @@ else:
cmdclass = {}
ext_modules = []
setup(
name='falcon',
version=VERSION,
@@ -77,8 +76,10 @@ setup(
install_requires=REQUIRES,
cmdclass=cmdclass,
ext_modules=ext_modules,
setup_requires=[],
entry_points={
'console_scripts':
['falcon-bench = falcon.cmd.bench:main']
'console_scripts': [
'falcon-bench = falcon.cmd.bench:main'
]
}
)

10
tox.ini
View File

@@ -6,6 +6,16 @@ deps = -r{toxinidir}/tools/test-requires
commands = {toxinidir}/tools/clean_cythoned.sh {toxinidir}/falcon
nosetests {posargs}
[testenv:py27]
deps = -r{toxinidir}/tools/test-requires
nose-cprof
commands = {toxinidir}/tools/clean_cythoned.sh {toxinidir}/falcon
nosetests \
--with-cprofile \
--cprofile-stats-erase \
--cprofile-stats-file=cprofile.dat \
{posargs}
[testenv:py3kwarn]
deps = py3kwarn
commands = py3kwarn falcon