|
1 | | -"""Python interface for the 'lsprof' profiler. |
2 | | - Compatible with the 'profile' module. |
3 | | -""" |
4 | | - |
5 | | -__all__ = ["run", "runctx", "Profile"] |
6 | | - |
7 | | -import _lsprof |
8 | | -import importlib.machinery |
9 | | -import importlib.util |
10 | | -import io |
11 | | -import profile as _pyprofile |
12 | | - |
13 | | -# ____________________________________________________________ |
14 | | -# Simple interface |
15 | | - |
16 | | -def run(statement, filename=None, sort=-1): |
17 | | - return _pyprofile._Utils(Profile).run(statement, filename, sort) |
18 | | - |
19 | | -def runctx(statement, globals, locals, filename=None, sort=-1): |
20 | | - return _pyprofile._Utils(Profile).runctx(statement, globals, locals, |
21 | | - filename, sort) |
22 | | - |
23 | | -run.__doc__ = _pyprofile.run.__doc__ |
24 | | -runctx.__doc__ = _pyprofile.runctx.__doc__ |
25 | | - |
26 | | -# ____________________________________________________________ |
27 | | - |
28 | | -class Profile(_lsprof.Profiler): |
29 | | - """Profile(timer=None, timeunit=None, subcalls=True, builtins=True) |
30 | | -
|
31 | | - Builds a profiler object using the specified timer function. |
32 | | - The default timer is a fast built-in one based on real time. |
33 | | - For custom timer functions returning integers, timeunit can |
34 | | - be a float specifying a scale (i.e. how long each integer unit |
35 | | - is, in seconds). |
36 | | - """ |
37 | | - |
38 | | - # Most of the functionality is in the base class. |
39 | | - # This subclass only adds convenient and backward-compatible methods. |
40 | | - |
41 | | - def print_stats(self, sort=-1): |
42 | | - import pstats |
43 | | - if not isinstance(sort, tuple): |
44 | | - sort = (sort,) |
45 | | - pstats.Stats(self).strip_dirs().sort_stats(*sort).print_stats() |
46 | | - |
47 | | - def dump_stats(self, file): |
48 | | - import marshal |
49 | | - with open(file, 'wb') as f: |
50 | | - self.create_stats() |
51 | | - marshal.dump(self.stats, f) |
52 | | - |
53 | | - def create_stats(self): |
54 | | - self.disable() |
55 | | - self.snapshot_stats() |
| 1 | +"""Compatibility wrapper for cProfile module. |
56 | 2 |
|
57 | | - def snapshot_stats(self): |
58 | | - entries = self.getstats() |
59 | | - self.stats = {} |
60 | | - callersdicts = {} |
61 | | - # call information |
62 | | - for entry in entries: |
63 | | - func = label(entry.code) |
64 | | - nc = entry.callcount # ncalls column of pstats (before '/') |
65 | | - cc = nc - entry.reccallcount # ncalls column of pstats (after '/') |
66 | | - tt = entry.inlinetime # tottime column of pstats |
67 | | - ct = entry.totaltime # cumtime column of pstats |
68 | | - callers = {} |
69 | | - callersdicts[id(entry.code)] = callers |
70 | | - self.stats[func] = cc, nc, tt, ct, callers |
71 | | - # subcall information |
72 | | - for entry in entries: |
73 | | - if entry.calls: |
74 | | - func = label(entry.code) |
75 | | - for subentry in entry.calls: |
76 | | - try: |
77 | | - callers = callersdicts[id(subentry.code)] |
78 | | - except KeyError: |
79 | | - continue |
80 | | - nc = subentry.callcount |
81 | | - cc = nc - subentry.reccallcount |
82 | | - tt = subentry.inlinetime |
83 | | - ct = subentry.totaltime |
84 | | - if func in callers: |
85 | | - prev = callers[func] |
86 | | - nc += prev[0] |
87 | | - cc += prev[1] |
88 | | - tt += prev[2] |
89 | | - ct += prev[3] |
90 | | - callers[func] = nc, cc, tt, ct |
91 | | - |
92 | | - # The following two methods can be called by clients to use |
93 | | - # a profiler to profile a statement, given as a string. |
94 | | - |
95 | | - def run(self, cmd): |
96 | | - import __main__ |
97 | | - dict = __main__.__dict__ |
98 | | - return self.runctx(cmd, dict, dict) |
99 | | - |
100 | | - def runctx(self, cmd, globals, locals): |
101 | | - self.enable() |
102 | | - try: |
103 | | - exec(cmd, globals, locals) |
104 | | - finally: |
105 | | - self.disable() |
106 | | - return self |
107 | | - |
108 | | - # This method is more useful to profile a single function call. |
109 | | - def runcall(self, func, /, *args, **kw): |
110 | | - self.enable() |
111 | | - try: |
112 | | - return func(*args, **kw) |
113 | | - finally: |
114 | | - self.disable() |
115 | | - |
116 | | - def __enter__(self): |
117 | | - self.enable() |
118 | | - return self |
119 | | - |
120 | | - def __exit__(self, *exc_info): |
121 | | - self.disable() |
122 | | - |
123 | | -# ____________________________________________________________ |
| 3 | +This module maintains backward compatibility by importing from the new |
| 4 | +profiling.tracing module. |
| 5 | +""" |
124 | 6 |
|
125 | | -def label(code): |
126 | | - if isinstance(code, str): |
127 | | - return ('~', 0, code) # built-in functions ('~' sorts at the end) |
128 | | - else: |
129 | | - return (code.co_filename, code.co_firstlineno, code.co_name) |
| 7 | +from profiling.tracing import run, runctx, Profile |
130 | 8 |
|
131 | | -# ____________________________________________________________ |
| 9 | +__all__ = ["run", "runctx", "Profile"] |
132 | 10 |
|
133 | | -def main(): |
134 | | - import os |
| 11 | +if __name__ == "__main__": |
135 | 12 | import sys |
136 | | - import runpy |
137 | | - import pstats |
138 | | - from optparse import OptionParser |
139 | | - usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..." |
140 | | - parser = OptionParser(usage=usage) |
141 | | - parser.allow_interspersed_args = False |
142 | | - parser.add_option('-o', '--outfile', dest="outfile", |
143 | | - help="Save stats to <outfile>", default=None) |
144 | | - parser.add_option('-s', '--sort', dest="sort", |
145 | | - help="Sort order when printing to stdout, based on pstats.Stats class", |
146 | | - default=2, |
147 | | - choices=sorted(pstats.Stats.sort_arg_dict_default)) |
148 | | - parser.add_option('-m', dest="module", action="store_true", |
149 | | - help="Profile a library module", default=False) |
150 | | - |
151 | | - if not sys.argv[1:]: |
152 | | - parser.print_usage() |
153 | | - sys.exit(2) |
154 | | - |
155 | | - (options, args) = parser.parse_args() |
156 | | - sys.argv[:] = args |
157 | | - |
158 | | - # The script that we're profiling may chdir, so capture the absolute path |
159 | | - # to the output file at startup. |
160 | | - if options.outfile is not None: |
161 | | - options.outfile = os.path.abspath(options.outfile) |
162 | | - |
163 | | - if len(args) > 0: |
164 | | - if options.module: |
165 | | - code = "run_module(modname, run_name='__main__')" |
166 | | - globs = { |
167 | | - 'run_module': runpy.run_module, |
168 | | - 'modname': args[0] |
169 | | - } |
170 | | - else: |
171 | | - progname = args[0] |
172 | | - sys.path.insert(0, os.path.dirname(progname)) |
173 | | - with io.open_code(progname) as fp: |
174 | | - code = compile(fp.read(), progname, 'exec') |
175 | | - spec = importlib.machinery.ModuleSpec(name='__main__', loader=None, |
176 | | - origin=progname) |
177 | | - module = importlib.util.module_from_spec(spec) |
178 | | - # Set __main__ so that importing __main__ in the profiled code will |
179 | | - # return the same namespace that the code is executing under. |
180 | | - sys.modules['__main__'] = module |
181 | | - # Ensure that we're using the same __dict__ instance as the module |
182 | | - # for the global variables so that updates to globals are reflected |
183 | | - # in the module's namespace. |
184 | | - globs = module.__dict__ |
185 | | - globs.update({ |
186 | | - '__spec__': spec, |
187 | | - '__file__': spec.origin, |
188 | | - '__name__': spec.name, |
189 | | - '__package__': None, |
190 | | - '__cached__': None, |
191 | | - }) |
192 | | - |
193 | | - try: |
194 | | - runctx(code, globs, None, options.outfile, options.sort) |
195 | | - except BrokenPipeError as exc: |
196 | | - # Prevent "Exception ignored" during interpreter shutdown. |
197 | | - sys.stdout = None |
198 | | - sys.exit(exc.errno) |
199 | | - else: |
200 | | - parser.print_usage() |
201 | | - return parser |
202 | | - |
203 | | -# When invoked as main program, invoke the profiler on a script |
204 | | -if __name__ == '__main__': |
| 13 | + from profiling.tracing.__main__ import main |
205 | 14 | main() |
0 commit comments