~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lsprof.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
# I made one modification to profile so that it returns a pair
4
4
# instead of just the Stats object
5
5
 
6
 
import cPickle
7
 
import os
8
6
import sys
9
7
import thread
10
8
import threading
11
9
from _lsprof import Profiler, profiler_entry
12
10
 
13
 
 
14
11
__all__ = ['profile', 'Stats']
15
12
 
16
13
_g_threadmap = {}
32
29
    p = Profiler()
33
30
    p.enable(subcalls=True)
34
31
    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.
39
32
    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
 
33
        ret = f(*args, **kwds)
46
34
    finally:
47
35
        p.disable()
48
36
        for pp in _g_threadmap.values():
116
104
        """Output profiling data in calltree format (for KCacheGrind)."""
117
105
        _CallTreeFilter(self.data).output(file)
118
106
 
119
 
    def save(self, filename, format=None):
120
 
        """Save profiling data to a file.
121
 
 
122
 
        :param filename: the name of the output file
123
 
        :param format: 'txt' for a text representation;
124
 
            'callgrind' for calltree format;
125
 
            otherwise a pickled Python object. A format of None indicates
126
 
            that the format to use is to be found from the filename. If
127
 
            the name starts with callgrind.out, callgrind format is used
128
 
            otherwise the format is given by the filename extension.
129
 
        """
130
 
        if format is None:
131
 
            basename = os.path.basename(filename)
132
 
            if basename.startswith('callgrind.out'):
133
 
                format = "callgrind"
134
 
            else:
135
 
                ext = os.path.splitext(filename)[1]
136
 
                if len(ext) > 1:
137
 
                    format = ext[1:]
138
 
        outfile = open(filename, 'wb')
139
 
        try:
140
 
            if format == "callgrind":
141
 
                self.calltree(outfile)
142
 
            elif format == "txt":
143
 
                self.pprint(file=outfile)
144
 
            else:
145
 
                self.freeze()
146
 
                cPickle.dump(self, outfile, 2)
147
 
        finally:
148
 
            outfile.close()
149
 
 
150
107
 
151
108
class _CallTreeFilter(object):
152
 
    """Converter of a Stats object to input suitable for KCacheGrind.
153
 
 
154
 
    This code is taken from http://ddaa.net/blog/python/lsprof-calltree
155
 
    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 
157
 
    object is actually an external code object (with a filename, etc.) or
158
 
    a Python built-in.
159
 
    """
160
109
 
161
110
    def __init__(self, data):
162
111
        self.data = data
164
113
 
165
114
    def output(self, out_file):
166
115
        self.out_file = out_file        
167
 
        out_file.write('events: Ticks\n')
 
116
        print >> out_file, 'events: Ticks'
168
117
        self._print_summary()
169
118
        for entry in self.data:
170
119
            self._entry(entry)
174
123
        for entry in self.data:
175
124
            totaltime = int(entry.totaltime * 1000)
176
125
            max_cost = max(max_cost, totaltime)
177
 
        self.out_file.write('summary: %d\n' % (max_cost,))
 
126
        print >> self.out_file, 'summary: %d' % (max_cost,)
178
127
 
179
128
    def _entry(self, entry):
180
129
        out_file = self.out_file
181
130
        code = entry.code
182
131
        inlinetime = int(entry.inlinetime * 1000)
183
 
        #out_file.write('ob=%s\n' % (code.co_filename,))
184
 
        if isinstance(code, str):
185
 
            out_file.write('fi=~\n')
186
 
        else:
187
 
            out_file.write('fi=%s\n' % (code.co_filename,))
188
 
        out_file.write('fn=%s\n' % (label(code, True),))
189
 
        if isinstance(code, str):
190
 
            out_file.write('0  %s\n' % (inlinetime,))
191
 
        else:
192
 
            out_file.write('%d %d\n' % (code.co_firstlineno, inlinetime))
 
132
        #print >> out_file, 'ob=%s' % (code.co_filename,)
 
133
        print >> out_file, 'fi=%s' % (code.co_filename,)
 
134
        print >> out_file, 'fn=%s' % (label(code, True),)
 
135
        print >> out_file, '%d %d' % (code.co_firstlineno, inlinetime)
193
136
        # recursive calls are counted in entry.calls
194
137
        if entry.calls:
195
138
            calls = entry.calls
196
139
        else:
197
140
            calls = []
198
 
        if isinstance(code, str):
199
 
            lineno = 0
200
 
        else:
201
 
            lineno = code.co_firstlineno
202
141
        for subentry in calls:
203
 
            self._subentry(lineno, subentry)
204
 
        out_file.write('\n')
 
142
            self._subentry(code.co_firstlineno, subentry)
 
143
        print >> out_file
205
144
 
206
145
    def _subentry(self, lineno, subentry):
207
146
        out_file = self.out_file
208
147
        code = subentry.code
209
148
        totaltime = int(subentry.totaltime * 1000)
210
 
        #out_file.write('cob=%s\n' % (code.co_filename,))
211
 
        out_file.write('cfn=%s\n' % (label(code, True),))
212
 
        if isinstance(code, str):
213
 
            out_file.write('cfi=~\n')
214
 
            out_file.write('calls=%d 0\n' % (subentry.callcount,))
215
 
        else:
216
 
            out_file.write('cfi=%s\n' % (code.co_filename,))
217
 
            out_file.write('calls=%d %d\n' % (
218
 
                subentry.callcount, code.co_firstlineno))
219
 
        out_file.write('%d %d\n' % (lineno, totaltime))
 
149
        #print >> out_file, 'cob=%s' % (code.co_filename,)
 
150
        print >> out_file, 'cfn=%s' % (label(code, True),)
 
151
        print >> out_file, 'cfi=%s' % (code.co_filename,)
 
152
        print >> out_file, 'calls=%d %d' % (
 
153
            subentry.callcount, code.co_firstlineno)
 
154
        print >> out_file, '%d %d' % (lineno, totaltime)
 
155
 
220
156
 
221
157
_fn2mod = {}
222
158
 
248
184
    import os
249
185
    sys.argv = sys.argv[1:]
250
186
    if not sys.argv:
251
 
        sys.stderr.write("usage: lsprof.py <script> <arguments...>\n")
 
187
        print >> sys.stderr, "usage: lsprof.py <script> <arguments...>"
252
188
        sys.exit(2)
253
189
    sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
254
190
    stats = profile(execfile, sys.argv[0], globals(), locals())