/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/lsprof.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

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 codecs
7
 
try:
8
 
    import cPickle as pickle
9
 
except ImportError:
10
 
    import pickle
11
 
import operator
 
6
from __future__ import absolute_import
 
7
 
 
8
import cPickle
12
9
import os
13
10
import sys
14
 
import _thread
 
11
import thread
15
12
import threading
16
13
from _lsprof import Profiler, profiler_entry
17
14
 
19
16
 
20
17
__all__ = ['profile', 'Stats']
21
18
 
22
 
 
23
19
def profile(f, *args, **kwds):
24
20
    """Run a function profile.
25
21
 
43
39
 
44
40
class BzrProfiler(object):
45
41
    """Bzr utility wrapper around Profiler.
46
 
 
 
42
    
47
43
    For most uses the module level 'profile()' function will be suitable.
48
44
    However profiling when a simple wrapped function isn't available may
49
45
    be easier to accomplish using this class.
55
51
    Note that profiling involves a threading.Lock around the actual profiling.
56
52
    This is needed because profiling involves global manipulation of the python
57
53
    interpreter state. As such you cannot perform multiple profiles at once.
58
 
    Trying to do so will lock out the second profiler unless the global
 
54
    Trying to do so will lock out the second profiler unless the global 
59
55
    breezy.lsprof.BzrProfiler.profiler_block is set to 0. Setting it to 0 will
60
56
    cause profiling to fail rather than blocking.
61
57
    """
68
64
 
69
65
    def start(self):
70
66
        """Start profiling.
71
 
 
 
67
        
72
68
        This hooks into threading and will record all calls made until
73
69
        stop() is called.
74
70
        """
81
77
        try:
82
78
            self.p.enable(subcalls=True)
83
79
            threading.setprofile(self._thread_profile)
84
 
        except BaseException:
 
80
        except:
85
81
            self.__class__.profiler_lock.release()
86
82
            raise
87
83
 
111
107
    def _thread_profile(self, f, *args, **kwds):
112
108
        # we lose the first profile point for a new thread in order to
113
109
        # trampoline a new Profile object into place
114
 
        thr = _thread.get_ident()
 
110
        thr = thread.get_ident()
115
111
        self._g_threadmap[thr] = p = Profiler()
116
112
        # this overrides our sys.setprofile hook:
117
113
        p.enable(subcalls=True, builtins=True)
129
125
        self.data = data
130
126
        self.threads = threads
131
127
 
132
 
    def sort(self, crit="inlinetime", reverse=True):
 
128
    def sort(self, crit="inlinetime"):
133
129
        """Sort the data by the supplied critera.
134
130
 
135
131
        :param crit: the data attribute used as the sort key."""
136
 
        if crit not in profiler_entry.__dict__ or crit == 'code':
 
132
        if crit not in profiler_entry.__dict__:
137
133
            raise ValueError("Can't sort by %s" % crit)
138
 
 
139
 
        key_func = operator.attrgetter(crit)
140
 
        self.data.sort(key=key_func, reverse=reverse)
141
 
 
 
134
        self.data.sort(lambda b, a: cmp(getattr(a, crit),
 
135
                                        getattr(b, crit)))
142
136
        for e in self.data:
143
137
            if e.calls:
144
 
                e.calls.sort(key=key_func, reverse=reverse)
 
138
                e.calls.sort(lambda b, a: cmp(getattr(a, crit),
 
139
                                              getattr(b, crit)))
145
140
 
146
141
    def pprint(self, top=None, file=None):
147
142
        """Pretty-print the data as plain text for human consumption.
157
152
            d = d[:top]
158
153
        cols = "% 12s %12s %11.4f %11.4f   %s\n"
159
154
        hcols = "% 12s %12s %12s %12s %s\n"
 
155
        cols2 = "+%12s %12s %11.4f %11.4f +  %s\n"
160
156
        file.write(hcols % ("CallCount", "Recursive", "Total(ms)",
161
157
                            "Inline(ms)", "module:lineno(function)"))
162
158
        for e in d:
208
204
                ext = os.path.splitext(filename)[1]
209
205
                if len(ext) > 1:
210
206
                    format = ext[1:]
211
 
        with open(filename, 'wb') as outfile:
 
207
        outfile = open(filename, 'wb')
 
208
        try:
212
209
            if format == "callgrind":
213
 
                # The callgrind format states it is 'ASCII based':
214
 
                # <http://valgrind.org/docs/manual/cl-format.html>
215
 
                # But includes filenames so lets ignore and use UTF-8.
216
 
                self.calltree(codecs.getwriter('utf-8')(outfile))
 
210
                self.calltree(outfile)
217
211
            elif format == "txt":
218
 
                self.pprint(file=codecs.getwriter('utf-8')(outfile))
 
212
                self.pprint(file=outfile)
219
213
            else:
220
214
                self.freeze()
221
 
                pickle.dump(self, outfile, 2)
 
215
                cPickle.dump(self, outfile, 2)
 
216
        finally:
 
217
            outfile.close()
222
218
 
223
219
 
224
220
class _CallTreeFilter(object):
253
249
        out_file = self.out_file
254
250
        code = entry.code
255
251
        inlinetime = int(entry.inlinetime * 1000)
 
252
        #out_file.write('ob=%s\n' % (code.co_filename,))
256
253
        if isinstance(code, str):
257
254
            out_file.write('fi=~\n')
258
255
        else:
279
276
        out_file = self.out_file
280
277
        code = subentry.code
281
278
        totaltime = int(subentry.totaltime * 1000)
 
279
        #out_file.write('cob=%s\n' % (code.co_filename,))
282
280
        if isinstance(code, str):
283
281
            out_file.write('cfi=~\n')
284
282
            out_file.write('cfn=%s\n' % (label(code, True),))
290
288
                subentry.callcount, code.co_firstlineno))
291
289
        out_file.write('%d %d\n' % (lineno, totaltime))
292
290
 
293
 
 
294
291
_fn2mod = {}
295
292
 
296
 
 
297
293
def label(code, calltree=False):
298
294
    if isinstance(code, str):
299
295
        return code
311
307
                mname = _fn2mod[code.co_filename] = k
312
308
                break
313
309
        else:
314
 
            mname = _fn2mod[code.co_filename] = '<%s>' % code.co_filename
 
310
            mname = _fn2mod[code.co_filename] = '<%s>'%code.co_filename
315
311
    if calltree:
316
312
        return '%s %s:%d' % (code.co_name, mname, code.co_firstlineno)
317
313
    else:
318
314
        return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
319
315
 
320
316
 
321
 
def main():
 
317
if __name__ == '__main__':
 
318
    import os
322
319
    sys.argv = sys.argv[1:]
323
320
    if not sys.argv:
324
321
        sys.stderr.write("usage: lsprof.py <script> <arguments...>\n")
325
322
        sys.exit(2)
326
 
    import runpy
327
 
    result, stats = profile(runpy.run_path, sys.argv[0], run_name='__main__')
328
 
    stats.sort()
 
323
    sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
 
324
    stats = sorted(profile(execfile, sys.argv[0], globals(), locals()))
329
325
    stats.pprint()
330
 
 
331
 
 
332
 
if __name__ == '__main__':
333
 
    main()