green.profile: accumulate results between runs; Thanks to Zhang Hua

https://bitbucket.org/eventlet/eventlet/issue/162/eventletgreenprofile-can-not-accumulate
This commit is contained in:
Sergey Shepelev
2014-03-10 16:39:34 +04:00
parent c458d87155
commit 7932fc4efb
2 changed files with 17 additions and 9 deletions

View File

@@ -90,3 +90,4 @@ Thanks To
* Eric Urban, fix wsgi.input 1-byte (Bitbucket #150)
* David Goetz, wsgi: Allow minimum_chunk_size to be overriden on a per request basis
* Dmitry Orlov, websocket: accept Upgrade: websocket (lowercase)
* Zhang Hua, profile: accumulate results between runs (Bitbucket #162)

View File

@@ -25,7 +25,7 @@
"""This module is API-equivalent to the standard library :mod:`profile` module but it is greenthread-aware as well as thread-aware. Use this module
to profile Eventlet-based applications in preference to either :mod:`profile` or :mod:`cProfile`.
FIXME: No testcases for this module.
FIXME: No testcases for this module.
"""
profile_orig = __import__('profile')
@@ -43,9 +43,11 @@ from eventlet import greenthread
from eventlet import patcher
thread = patcher.original('thread') # non-monkeypatched module needed
#This class provides the start() and stop() functions
class Profile(profile_orig.Profile):
base = profile_orig.Profile
def __init__(self, timer = None, bias=None):
self.current_tasklet = greenthread.getcurrent()
self.thread_id = thread.get_ident()
@@ -53,11 +55,14 @@ class Profile(profile_orig.Profile):
self.sleeping = {}
def __call__(self, *args):
"make callable, allowing an instance to be the profiler"
r = self.dispatcher(*args)
"""make callable, allowing an instance to be the profiler"""
r = self.dispatcher(*args)
def _setup(self):
self.cur, self.timings, self.current_tasklet = None, {}, greenthread.getcurrent()
self._has_setup = True
self.cur = None
self.timings = {}
self.current_tasklet = greenthread.getcurrent()
self.thread_id = thread.get_ident()
self.simulate_call("profiler")
@@ -77,14 +82,16 @@ class Profile(profile_orig.Profile):
#special cases for the original run commands, makin sure to
#clear the timer context.
def runctx(self, cmd, globals, locals):
self._setup()
if not getattr(self, "_has_setup", False):
self._setup()
try:
return profile_orig.Profile.runctx(self, cmd, globals, locals)
finally:
self.TallyTimings()
def runcall(self, func, *args, **kw):
self._setup()
if not getattr(self, "_has_setup", False):
self._setup()
try:
return profile_orig.Profile.runcall(self, func, *args, **kw)
finally:
@@ -95,7 +102,7 @@ class Profile(profile_orig.Profile):
"""A hack function to override error checking in parent class. It
allows invalid returns (where frames weren't preveiously entered into
the profiler) which can happen for all the tasklets that suddenly start
to get monitored. This means that the time will eventually be attributed
to get monitored. This means that the time will eventually be attributed
to a call high in the chain, when there is a tasklet switch
"""
if isinstance(self.cur[-2], Profile.fake_frame):
@@ -149,7 +156,6 @@ class Profile(profile_orig.Profile):
#Add automatic tasklet detection to the callbacks.
dispatch = dict([(key, ContextWrap(val)) for key,val in dispatch.iteritems()])
def TallyTimings(self):
oldtimings = self.sleeping
self.sleeping = {}
@@ -177,7 +183,6 @@ class Profile(profile_orig.Profile):
callers[k1] = callers.get(k1, 0)+v1
self.timings[k] = cc, ns, tt, ct, callers
def Unwind(self, cur, timings):
"A function to unwind a 'cur' frame and tally the results"
"see profile.trace_dispatch_return() for details"
@@ -212,6 +217,7 @@ class Profile(profile_orig.Profile):
cur = rcur
return cur
# run statements shamelessly stolen from profile.py
def run(statement, filename=None, sort=-1):
"""Run statement under profiler optionally saving results in filename
@@ -234,6 +240,7 @@ def run(statement, filename=None, sort=-1):
else:
return prof.print_stats(sort)
def runctx(statement, globals, locals, filename=None):
"""Run statement under profiler, supplying your own globals and locals,
optionally saving results in filename.