Add profiled decorator and a tool to show profiler results.

The goal here is to make it easier to do ad hoc profiling on
our codebase, particularly by running tests.

(imported from commit 71da06feb3a369dec8dc4d8391f7f40e4c2d02ff)
This commit is contained in:
Steve Howell 2013-07-02 11:30:04 -04:00
parent cff0096f3b
commit 741929008b
3 changed files with 52 additions and 1 deletions

24
tools/show-profile-results.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
import sys
import pstats
'''
This is a helper script to make it easy to show profile
results after using a Python decorator. It's meant to be
a simple example that you can hack on, or better yet, you
can find more advanced tools for showing profiler results.
'''
try:
fn = sys.argv[1]
except:
print '''
Please supply a filename. (If you use the profiled decorator,
the file will have a suffix of ".profile".)
'''
sys.exit(1)
p = pstats.Stats(fn)
p.strip_dirs().sort_stats('cumulative').print_stats(25)
p.strip_dirs().sort_stats('time').print_stats(25)

View File

@ -19,6 +19,7 @@ from zephyr.lib.rate_limiter import incr_ratelimit, is_ratelimited, \
from functools import wraps
import base64
import logging
import cProfile
class _RespondAsynchronously(object):
pass
@ -416,3 +417,29 @@ def rate_limit(domain='all'):
return func(request, *args, **kwargs)
return wrapped_func
return wrapper
def profiled(func):
"""
This decorator should obviously be used only in a dev environment.
It works best when surrounding a function that you expect to be
called once. One strategy is to write a test case in zephyr/tests.py
and wrap the test case with the profiled decorator.
You can run a single test case like this:
# edit zephyr/tests.py and place @profiled above the test case below
./tools/test-backend zephyr.RateLimitTests.test_ratelimit_decrease
Then view the results like this:
./tools/show-profile-results.py test_ratelimit_decrease.profile
"""
@wraps(func)
def wrapped_func(*args, **kwargs):
fn = func.__name__ + ".profile"
prof = cProfile.Profile()
retval = prof.runcall(func, *args, **kwargs)
prof.dump_stats(fn)
return retval
return wrapped_func

View File

@ -10,7 +10,7 @@ from zephyr.models import Message, UserProfile, Stream, Recipient, Subscription,
get_display_recipient, Realm, Client, \
PreregistrationUser, UserMessage
from zephyr.tornadoviews import json_get_updates, api_get_messages
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError, profiled
from zephyr.lib.initial_password import initial_password
from zephyr.lib.actions import do_send_message, gather_subscriptions, \
create_stream_if_needed, do_add_subscription