~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: 2006-08-17 07:52:09 UTC
  • mfrom: (1910.3.4 trivial)
  • Revision ID: pqm@pqm.ubuntu.com-20060817075209-e85a1f9e05ff8b87
(andrew) Trivial fixes to NotImplemented errors.

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