Skip to content

Commit

Permalink
Merge d23f30b into 40b76b4
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Sep 30, 2016
2 parents 40b76b4 + d23f30b commit 87b5bc7
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ matrix:
fast_finish: true
script:
- PYTHONPATH=".travis" coverage run .travis/cover.py -c 1 -n 100 .travis/$ENV.conf --btrees -r 2 --test-reps 1
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then PYTHONPATH=".travis" coverage run .travis/cover.py -c 2 -n 100 .travis/$ENV.conf --threads --gevent -r 2; fi
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then PYTHONPATH=".travis" coverage run .travis/cover.py -c 2 -n 100 .travis/$ENV.conf --threads --gevent -r 2 --leaks; fi
- if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then PYTHONPATH=".travis" coverage run .travis/cover.py -c 2 -n 100 .travis/$ENV.conf --threads -r 2; fi
after_success:
- coverage combine
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
- The reported numbers should be more stable, thanks to running
individual tests more times (via the ``--test-reps`` option) and
taking the mean instead of the min.
- Add ``--leaks`` to use `objgraph <>`_ to show any leaking objects at
the end of each test repetition. Most useful to storage and ZODB developers.

0.5 (2012-09-08)
================
Expand Down
5 changes: 5 additions & 0 deletions doc/zodbshootout.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ The ``zodbshootout`` script accepts the following options.

.. versionadded:: 0.6

* ``--leaks`` prints a summary of possibly leaking objects after each
test repetition. This is useful for storage and ZODB developers.

.. versionadded:: 0.6

You should write a configuration file that models your intended
database and network configuration. Running ``zodbshootout`` may reveal
configuration optimizations that would significantly increase your
Expand Down
9 changes: 8 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os

install_requires = [
'objgraph',
'setuptools',
'ZODB',
'ZEO'
Expand Down Expand Up @@ -57,7 +58,13 @@ def read_file(*path):
'oracle': ['relstorage[oracle]'],
':python_version == "2.7"': [
'statistics'
]
],
":python_full_version < '2.7.9'": [
# We must pin old versions prior to 2.7.9 because ZEO
# 5 only runs on versions with good SSL support.
'ZODB >= 4.4.2, <5.0',
'ZEO >= 4.2.0, <5.0'
],
},
classifiers=[
"Programming Language :: Python :: 2.7",
Expand Down
43 changes: 42 additions & 1 deletion src/zodbshootout/_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,32 @@ def itervalues(d):
</schema>
"""

def _make_leak_check(options):
if not options.leaks:
return lambda: None, lambda: None

if PY3:
SIO = StringIO
else:
from io import BytesIO as SIO

import objgraph
import gc
def prep_leaks():
gc.collect()
objgraph.show_growth(file=SIO())

def show_leaks():
gc.collect()
gc.collect()
sio = SIO()
objgraph.show_growth(file=sio)
if sio.getvalue():
print(" Memory Growth")
for line in sio.getvalue().split('\n'):
print(" ", line)

return prep_leaks, show_leaks

def align_columns(rows):
"""Format a list of rows as CSV with aligned columns.
Expand Down Expand Up @@ -108,6 +134,7 @@ def run_with_options(options):
repetitions = options.repetitions
if profile_dir and not os.path.exists(profile_dir):
os.makedirs(profile_dir)
prep_leaks, show_leaks = _make_leak_check(options)

schema = ZConfig.loadSchemaFile(StringIO(schema_xml))
config, _handler = ZConfig.loadConfigFile(schema, conf_fn)
Expand Down Expand Up @@ -175,12 +202,18 @@ def make_factory(db_conf):
for rep in range(repetitions):
if options.threads == 'shared':
_db, db_factory = make_factory(db)
db_close = _db.close
__db_close = _db.close
def db_close():
#import pprint; pprint.pprint(_db._storage._cache.clients_local_first[0].stats())
__db_close()

_db.close = lambda: None
_db.pack = lambda: None
else:
db_factory = db.open
db_close = lambda: None
# After the DB is opened, so modules, etc, are imported.
prep_leaks()
for attempt in range(max_attempts):
msg = ' Running %d/%d...' % (rep + 1, repetitions)
if attempt > 0:
Expand Down Expand Up @@ -209,6 +242,14 @@ def make_factory(db_conf):
for i in range(6):
results[key + (i,)].append(times[i])

# Clear the things we created before checking for leaks
del db_factory
del db_close
# in case it wasn't defined
_db = None
__db_close = None
show_leaks()

# The finally clause causes test results to print even if the tests
# stop early.
finally:
Expand Down
15 changes: 11 additions & 4 deletions src/zodbshootout/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def main(argv=None):
argv = sys.argv[1:]

parser = argparse.ArgumentParser()
prof_group = parser.add_argument_group("Profiling", "Control over profiling the database")
obj_group = parser.add_argument_group("Objects", "Control the objects put in ZODB")
con_group = parser.add_argument_group("Concurrency", "Control over concurrency")
rep_group = parser.add_argument_group("Repetitions", "Control over test repetitions")
Expand Down Expand Up @@ -56,10 +57,6 @@ def main(argv=None):
action="append",
help="Concurrency levels to use. Default is 2. Use this option as many times as you want."
)
parser.add_argument(
"-p", "--profile", dest="profile_dir", default="",
help="Profile all tests and output results to the specified directory",
)
obj_group.add_argument(
"--btrees", nargs="?", const="IO", default=False,
choices=['IO', 'OO'],
Expand Down Expand Up @@ -89,6 +86,16 @@ def main(argv=None):
"--gevent", action="store_true", default=False,
help="Monkey-patch the system with gevent before running. Implies --threads (if not given).")

prof_group.add_argument(
"-p", "--profile", dest="profile_dir", default="",
help="Profile all tests and output results to the specified directory",
)

prof_group.add_argument(
"-l", "--leaks", dest='leaks', action='store_true', default=False,
help="Check for object leaks after every repetition. This only makes sense with --threads"
)

parser.add_argument("config_file", type=argparse.FileType())

options = parser.parse_args(argv)
Expand Down
1 change: 1 addition & 0 deletions src/zodbshootout/speedtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def fdata():
data += next(datagen)
return data

_random_data(100) # call once for the sake of leak checks

WriteTimes = namedtuple('WriteTimes', ['add_time', 'update_time'])
ReadTimes = namedtuple('ReadTimes', ['warm_time', 'cold_time', 'hot_time', 'steamin_time'])
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ deps =
coverage
mock
zope.testing
statistics
commands =
coverage run -m zodbshootout.main -c 1 -n 100 .travis/file.conf
python -m zodbshootout.main -c 1 -n 100 --leaks .travis/file.conf

0 comments on commit 87b5bc7

Please sign in to comment.