1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | Lib/cProfile.py
#! /usr/bin/env python """Python interface for the 'lsprof' profiler. Compatible with the 'profile' module. """ __all__ = ["run", "runctx", "help", "Profile"] import _lsprof # ____________________________________________________________ # Simple interface def run(statement, filename=None, sort=-1): """Run statement under profiler optionally saving results in filename This function takes a single argument that can be passed to the "exec" statement, and an optional file name. In all cases this routine attempts to "exec" its first argument and gather profiling statistics from the execution. If no file name is present, then this function automatically prints a simple profiling report, sorted by the standard name string (file/line/function-name) that is presented in each line. """ prof = Profile() result = None try: try: prof = prof.run(statement) except SystemExit: pass finally: if filename is not None: prof.dump_stats(filename) else: result = prof.print_stats(sort) return result def runctx(statement, globals, locals, filename=None, sort=-1): """Run statement under profiler, supplying your own globals and locals, optionally saving results in filename. statement and filename have the same semantics as profile.run """ prof = Profile() result = None try: try: prof = prof.runctx(statement, globals, locals) except SystemExit: pass finally: if filename is not None: prof.dump_stats(filename) else: result = prof.print_stats(sort) return result # Backwards compatibility. def help(): print "Documentation for the profile/cProfile modules can be found " print "in the Python Library Reference, section 'The Python Profiler'." # ____________________________________________________________ class Profile(_lsprof.Profiler): """Profile(custom_timer=None, time_unit=None, subcalls=True, builtins=True) Builds a profiler object using the specified timer function. The default timer is a fast built-in one based on real time. For custom timer functions returning integers, time_unit can be a float specifying a scale (i.e. how long each integer unit is, in seconds). """ # Most of the functionality is in the base class. # This subclass only adds convenient and backward-compatible methods. def print_stats(self, sort=-1): import pstats pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats() def dump_stats(self, file): import marshal f = open(file, 'wb') self.create_stats() marshal.dump(self.stats, f) f.close() def create_stats(self): self.disable() self.snapshot_stats() def snapshot_stats(self): entries = self.getstats() self.stats = {} callersdicts = {} # call information for entry in entries: func = label(entry.code) nc = entry.callcount # ncalls column of pstats (before '/') cc = nc - entry.reccallcount # ncalls column of pstats (after '/') tt = entry.inlinetime # tottime column of pstats ct = entry.totaltime # cumtime column of pstats callers = {} callersdicts[id(entry.code)] = callers self.stats[func] = cc, nc, tt, ct, callers # subcall information for entry in entries: if entry.calls: func = label(entry.code) for subentry in entry.calls: try: callers = callersdicts[id(subentry.code)] except KeyError: continue nc = subentry.callcount cc = nc - subentry.reccallcount tt = subentry.inlinetime ct = subentry.totaltime if func in callers: prev = callers[func] nc += prev[0] cc += prev[1] tt += prev[2] ct += prev[3] callers[func] = nc, cc, tt, ct # The following two methods can be called by clients to use # a profiler to profile a statement, given as a string. def run(self, cmd): import __main__ dict = __main__.__dict__ return self.runctx(cmd, dict, dict) def runctx(self, cmd, globals, locals): self.enable() try: exec cmd in globals, locals finally: self.disable() return self # This method is more useful to profile a single function call. def runcall(self, func, *args, **kw): self.enable() try: return func(*args, **kw) finally: self.disable() # ____________________________________________________________ def label(code): if isinstance(code, str): return ('~', 0, code) # built-in functions ('~' sorts at the end) else: return (code.co_filename, code.co_firstlineno, code.co_name) # ____________________________________________________________ def main(): import os, sys from optparse import OptionParser usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..." parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('-o', '--outfile', dest="outfile", help="Save stats to <outfile>", default=None) parser.add_option('-s', '--sort', dest="sort", help="Sort order when printing to stdout, based on pstats.Stats class", default=-1) if not sys.argv[1:]: parser.print_usage() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } runctx(code, globs, None, options.outfile, options.sort) else: parser.print_usage() return parser # When invoked as main program, invoke the profiler on a script if __name__ == '__main__': main() |