~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lsprof.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 15:46:03 UTC
  • mfrom: (4985.3.21 update)
  • mto: This revision was merged to the branch mainline in revision 5021.
  • Revision ID: v.ladeuil+lp@free.fr-20100210154603-k4no1gvfuqpzrw7p
Update performs two merges in a more logical order but stop on conflicts

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
17
    """Run a function profile.
31
 
    
 
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
 
32
23
    :return: The functions return value and a stats object.
33
24
    """
34
 
    global _g_threadmap
35
 
    p = Profiler()
36
 
    p.enable(subcalls=True)
37
 
    threading.setprofile(_thread_profile)
38
 
    # Note: The except clause is needed below so that profiling data still
39
 
    # gets dumped even when exceptions are encountered. The except clause code
40
 
    # is taken straight from run_bzr_catch_errrors() in commands.py and ought
41
 
    # to be kept in sync with it.
 
25
    profiler = BzrProfiler()
 
26
    profiler.start()
42
27
    try:
43
 
        try:
44
 
            ret = f(*args, **kwds)
45
 
        except (KeyboardInterrupt, Exception), e:
46
 
            import bzrlib.trace
47
 
            bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
48
 
            ret = 3
 
28
        ret = f(*args, **kwds)
49
29
    finally:
50
 
        p.disable()
51
 
        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():
52
67
            pp.disable()
53
68
        threading.setprofile(None)
54
 
    
55
 
    threads = {}
56
 
    for tid, pp in _g_threadmap.items():
57
 
        threads[tid] = Stats(pp.getstats(), {})
58
 
    _g_threadmap = {}
59
 
    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)
60
84
 
61
85
 
62
86
class Stats(object):
156
180
 
157
181
    This code is taken from http://ddaa.net/blog/python/lsprof-calltree
158
182
    with the changes made by J.P. Calderone and Itamar applied. Note that
159
 
    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
160
184
    object is actually an external code object (with a filename, etc.) or
161
185
    a Python built-in.
162
186
    """
166
190
        self.out_file = None
167
191
 
168
192
    def output(self, out_file):
169
 
        self.out_file = out_file        
 
193
        self.out_file = out_file
170
194
        out_file.write('events: Ticks\n')
171
195
        self._print_summary()
172
196
        for entry in self.data: