14
14
__all__ = ['profile', 'Stats']
19
def _thread_profile(f, *args, **kwds):
20
# we lose the first profile point for a new thread in order to trampoline
21
# a new Profile object into place
23
thr = thread.get_ident()
24
_g_threadmap[thr] = p = Profiler()
25
# this overrides our sys.setprofile hook:
26
p.enable(subcalls=True, builtins=True)
29
16
def profile(f, *args, **kwds):
33
p.enable(subcalls=True)
34
threading.setprofile(_thread_profile)
35
# Note: The except clause is needed below so that profiling data still
36
# gets dumped even when exceptions are encountered. The except clause code
37
# is taken straight from run_bzr_catch_errrors() in commands.py and ought
38
# to be kept in sync with it.
17
"""Run a function profile.
19
Exceptions are not caught: If you need stats even when exceptions are to be
20
raised, pass in a closure that will catch the exceptions and transform them
21
appropriately for your driver function.
23
:return: The functions return value and a stats object.
25
profiler = BzrProfiler()
41
ret = f(*args, **kwds)
42
except (KeyboardInterrupt, Exception), e:
44
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
28
ret = f(*args, **kwds)
48
for pp in _g_threadmap.values():
30
stats = profiler.stop()
34
class BzrProfiler(object):
35
"""Bzr utility wrapper around Profiler.
37
For most uses the module level 'profile()' function will be suitable.
38
However profiling when a simple wrapped function isn't available may
39
be easier to accomplish using this class.
41
To use it, create a BzrProfiler and call start() on it. Some arbitrary
42
time later call stop() to stop profiling and retrieve the statistics
43
from the code executed in the interim.
49
This hooks into threading and will record all calls made until
52
self._g_threadmap = {}
54
self.p.enable(subcalls=True)
55
threading.setprofile(self._thread_profile)
60
This unhooks from threading and cleans up the profiler, returning
61
the gathered Stats object.
63
:return: A bzrlib.lsprof.Stats object.
66
for pp in self._g_threadmap.values():
50
68
threading.setprofile(None)
53
for tid, pp in _g_threadmap.items():
54
threads[tid] = Stats(pp.getstats(), {})
56
return ret, Stats(p.getstats(), threads)
72
for tid, pp in self._g_threadmap.items():
73
threads[tid] = Stats(pp.getstats(), {})
74
self._g_threadmap = None
75
return Stats(p.getstats(), threads)
77
def _thread_profile(self, f, *args, **kwds):
78
# we lose the first profile point for a new thread in order to
79
# trampoline a new Profile object into place
80
thr = thread.get_ident()
81
self._g_threadmap[thr] = p = Profiler()
82
# this overrides our sys.setprofile hook:
83
p.enable(subcalls=True, builtins=True)
59
86
class Stats(object):