~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lsprof.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-03-11 13:47:06 UTC
  • mfrom: (5051.3.16 use-branch-open)
  • Revision ID: pqm@pqm.ubuntu.com-20100311134706-kaerqhx3lf7xn6rh
(Jelmer) Pass colocated branch names further down the call stack.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
__all__ = ['profile', 'Stats']
15
15
 
16
 
_g_threadmap = {}
17
 
 
18
 
 
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
22
 
    global _g_threadmap
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)
27
 
 
28
 
 
29
16
def profile(f, *args, **kwds):
30
 
    """XXX docstring"""
31
 
    global _g_threadmap
32
 
    p = Profiler()
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.
 
18
 
 
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.
 
22
 
 
23
    :return: The functions return value and a stats object.
 
24
    """
 
25
    profiler = BzrProfiler()
 
26
    profiler.start()
39
27
    try:
40
 
        try:
41
 
            ret = f(*args, **kwds)
42
 
        except (KeyboardInterrupt, Exception), e:
43
 
            import bzrlib.trace
44
 
            bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
45
 
            ret = 3
 
28
        ret = f(*args, **kwds)
46
29
    finally:
47
 
        p.disable()
48
 
        for pp in _g_threadmap.values():
 
30
        stats = profiler.stop()
 
31
    return ret, stats
 
32
 
 
33
 
 
34
class BzrProfiler(object):
 
35
    """Bzr utility wrapper around Profiler.
 
36
    
 
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.
 
40
 
 
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.
 
44
    """
 
45
 
 
46
    def start(self):
 
47
        """Start profiling.
 
48
        
 
49
        This hooks into threading and will record all calls made until
 
50
        stop() is called.
 
51
        """
 
52
        self._g_threadmap = {}
 
53
        self.p = Profiler()
 
54
        self.p.enable(subcalls=True)
 
55
        threading.setprofile(self._thread_profile)
 
56
 
 
57
    def stop(self):
 
58
        """Stop profiling.
 
59
 
 
60
        This unhooks from threading and cleans up the profiler, returning
 
61
        the gathered Stats object.
 
62
 
 
63
        :return: A bzrlib.lsprof.Stats object.
 
64
        """
 
65
        self.p.disable()
 
66
        for pp in self._g_threadmap.values():
49
67
            pp.disable()
50
68
        threading.setprofile(None)
51
 
    
52
 
    threads = {}
53
 
    for tid, pp in _g_threadmap.items():
54
 
        threads[tid] = Stats(pp.getstats(), {})
55
 
    _g_threadmap = {}
56
 
    return ret, Stats(p.getstats(), threads)
 
69
        p = self.p
 
70
        self.p = None
 
71
        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)
 
76
 
 
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)
57
84
 
58
85
 
59
86
class Stats(object):
153
180
 
154
181
    This code is taken from http://ddaa.net/blog/python/lsprof-calltree
155
182
    with the changes made by J.P. Calderone and Itamar applied. Note that
156
 
    isinstance(code, str) needs to be used at times to determine if the code 
 
183
    isinstance(code, str) needs to be used at times to determine if the code
157
184
    object is actually an external code object (with a filename, etc.) or
158
185
    a Python built-in.
159
186
    """
163
190
        self.out_file = None
164
191
 
165
192
    def output(self, out_file):
166
 
        self.out_file = out_file        
 
193
        self.out_file = out_file
167
194
        out_file.write('events: Ticks\n')
168
195
        self._print_summary()
169
196
        for entry in self.data: