From 9ad1a399e64cb407af73d41a0f0cf717e0387e93 Mon Sep 17 00:00:00 2001 From: David Read Date: Thu, 17 May 2012 16:42:39 +0100 Subject: [PATCH] [#2401]: Add CLI for time/speed profiling of requests. --- ckan/lib/cli.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ profile_tests.py | 3 ++- setup.py | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/ckan/lib/cli.py b/ckan/lib/cli.py index fadf096cf78..7b9899c6ebf 100644 --- a/ckan/lib/cli.py +++ b/ckan/lib/cli.py @@ -1144,3 +1144,65 @@ def command(self): raise NotImplementedError if self.verbose: print 'Creating %s test data: Complete!' % cmd + +class Profile(CkanCommand): + '''Code speed profiler + Provide a ckan url and it will make the request and record + how long each function call took in a file that can be read + by runsnakerun. + + Usage: + profile {url} + + e.g. profile /data/search + + The result is saved in profile.data.search + To view the profile in runsnakerun: + runsnakerun ckan.data.search.profile + + You may need to install python module: cProfile + ''' + summary = __doc__.split('\n')[0] + usage = __doc__ + max_args = 1 + min_args = 1 + + def _load_config_into_test_app(self): + from paste.deploy import loadapp + import paste.fixture + if not self.options.config: + msg = 'No config file supplied' + raise self.BadCommand(msg) + self.filename = os.path.abspath(self.options.config) + if not os.path.exists(self.filename): + raise AssertionError('Config filename %r does not exist.' % self.filename) + fileConfig(self.filename) + + wsgiapp = loadapp('config:' + self.filename) + self.app = paste.fixture.TestApp(wsgiapp) + + def command(self): + self._load_config_into_test_app() + + import paste.fixture + import cProfile + import re + + url = self.args[0] + + def profile_url(url): + try: + res = self.app.get(url, status=[200], extra_environ={'REMOTE_USER': 'visitor'}) + except paste.fixture.AppError: + print 'App error: ', url.strip() + except KeyboardInterrupt: + raise + except: + import traceback + traceback.print_exc() + print 'Unknown error: ', url.strip() + + output_filename = 'ckan%s.profile' % re.sub('[/?]', '.', url.replace('/', '.')) + profile_command = "profile_url('%s')" % url + cProfile.runctx(profile_command, globals(), locals(), filename=output_filename) + print 'Written profile to: %s' % output_filename diff --git a/profile_tests.py b/profile_tests.py index de653e536d0..463fc620675 100644 --- a/profile_tests.py +++ b/profile_tests.py @@ -1,4 +1,5 @@ +# Runs all the tests and save a speed profile to ckan.tests.profile import nose import cProfile command = """nose.main(argv=['--ckan','--with-pylons=test-core.ini', 'ckan/tests', '-x', '-v'])""" -cProfile.runctx( command, globals(), locals(), filename="ckan.profile" ) +cProfile.runctx( command, globals(), locals(), filename="ckan.tests.profile" ) diff --git a/setup.py b/setup.py index 0aec4622e29..b43b8d66b59 100644 --- a/setup.py +++ b/setup.py @@ -73,6 +73,7 @@ rdf-export = ckan.lib.cli:RDFExport tracking = ckan.lib.cli:Tracking plugin-info = ckan.lib.cli:PluginInfo + profile = ckan.lib.cli:Profile [console_scripts] ckan-admin = bin.ckan_admin:Command