blob: d6511b7124cb16929d2d75da1860b35fadcbe5b3 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
Guido van Rossum81762581992-04-21 15:36:23 +00002#
Guido van Rossumb6775db1994-08-01 11:34:53 +00003# Class for profiling python code. rev 1.0 6/2/94
Guido van Rossum81762581992-04-21 15:36:23 +00004#
Guido van Rossumb6775db1994-08-01 11:34:53 +00005# Based on prior profile module by Sjoerd Mullender...
6# which was hacked somewhat by: Guido van Rossum
Guido van Rossumb6775db1994-08-01 11:34:53 +00007
Guido van Rossum54f22ed2000-02-04 15:10:34 +00008"""Class for profiling Python code."""
Guido van Rossumb6775db1994-08-01 11:34:53 +00009
10# Copyright 1994, by InfoSeek Corporation, all rights reserved.
11# Written by James Roskind
Tim Peters2344fae2001-01-15 00:50:52 +000012#
Guido van Rossumb6775db1994-08-01 11:34:53 +000013# Permission to use, copy, modify, and distribute this Python software
14# and its associated documentation for any purpose (subject to the
15# restriction in the following sentence) without fee is hereby granted,
16# provided that the above copyright notice appears in all copies, and
17# that both that copyright notice and this permission notice appear in
18# supporting documentation, and that the name of InfoSeek not be used in
19# advertising or publicity pertaining to distribution of the software
20# without specific, written prior permission. This permission is
21# explicitly restricted to the copying and modification of the software
22# to remain in Python, compiled Python, or other languages (such as C)
23# wherein the modified or derived code is exclusively imported into a
24# Python module.
Tim Peters2344fae2001-01-15 00:50:52 +000025#
Guido van Rossumb6775db1994-08-01 11:34:53 +000026# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
27# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
28# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
29# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
30# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
31# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
32# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33
34
Guido van Rossum81762581992-04-21 15:36:23 +000035
36import sys
Guido van Rossum4e160981992-09-02 20:43:20 +000037import os
Guido van Rossumb6775db1994-08-01 11:34:53 +000038import time
Guido van Rossum4e160981992-09-02 20:43:20 +000039import marshal
Nicholas Bastin824b1b22004-03-23 18:44:39 +000040from optparse import OptionParser
Guido van Rossum81762581992-04-21 15:36:23 +000041
Georg Brandlb6b13242009-09-04 17:15:16 +000042__all__ = ["run", "runctx", "Profile"]
Guido van Rossum81762581992-04-21 15:36:23 +000043
Tim Peters2344fae2001-01-15 00:50:52 +000044# Sample timer for use with
Guido van Rossumb6775db1994-08-01 11:34:53 +000045#i_count = 0
46#def integer_timer():
Tim Peters2344fae2001-01-15 00:50:52 +000047# global i_count
48# i_count = i_count + 1
49# return i_count
Guido van Rossumb6775db1994-08-01 11:34:53 +000050#itimes = integer_timer # replace with C coded timer returning integers
Guido van Rossum81762581992-04-21 15:36:23 +000051
Guido van Rossumb6775db1994-08-01 11:34:53 +000052#**************************************************************************
53# The following are the static member functions for the profiler class
54# Note that an instance of Profile() is *not* needed to call them.
55#**************************************************************************
Guido van Rossum81762581992-04-21 15:36:23 +000056
Nicholas Bastin824b1b22004-03-23 18:44:39 +000057def run(statement, filename=None, sort=-1):
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000058 """Run statement under profiler optionally saving results in filename
Guido van Rossum4e160981992-09-02 20:43:20 +000059
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000060 This function takes a single argument that can be passed to the
61 "exec" statement, and an optional file name. In all cases this
62 routine attempts to "exec" its first argument and gather profiling
63 statistics from the execution. If no file name is present, then this
64 function automatically prints a simple profiling report, sorted by the
65 standard name string (file/line/function-name) that is presented in
66 each line.
67 """
Tim Peters2344fae2001-01-15 00:50:52 +000068 prof = Profile()
69 try:
70 prof = prof.run(statement)
71 except SystemExit:
72 pass
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000073 if filename is not None:
74 prof.dump_stats(filename)
Tim Peters2344fae2001-01-15 00:50:52 +000075 else:
Nicholas Bastin824b1b22004-03-23 18:44:39 +000076 return prof.print_stats(sort)
Guido van Rossume61fa0a1993-10-22 13:56:35 +000077
Georg Brandl8e43fbf2010-08-02 12:20:23 +000078def runctx(statement, globals, locals, filename=None, sort=-1):
Nicholas Bastin1eb4bfc2004-03-22 20:12:56 +000079 """Run statement under profiler, supplying your own globals and locals,
80 optionally saving results in filename.
81
82 statement and filename have the same semantics as profile.run
83 """
84 prof = Profile()
85 try:
86 prof = prof.runctx(statement, globals, locals)
87 except SystemExit:
88 pass
89
90 if filename is not None:
91 prof.dump_stats(filename)
92 else:
Georg Brandl8e43fbf2010-08-02 12:20:23 +000093 return prof.print_stats(sort)
Nicholas Bastin1eb4bfc2004-03-22 20:12:56 +000094
Fred Drakeedb5ffb2001-06-08 04:25:24 +000095if hasattr(os, "times"):
96 def _get_time_times(timer=os.times):
97 t = timer()
98 return t[0] + t[1]
99
Martin v. Löwisa4dac402005-03-03 11:39:45 +0000100# Using getrusage(3) is better than clock(3) if available:
101# on some systems (e.g. FreeBSD), getrusage has a higher resolution
102# Furthermore, on a POSIX system, returns microseconds, which
103# wrap around after 36min.
104_has_res = 0
105try:
106 import resource
107 resgetrusage = lambda: resource.getrusage(resource.RUSAGE_SELF)
108 def _get_time_resource(timer=resgetrusage):
109 t = timer()
110 return t[0] + t[1]
111 _has_res = 1
112except ImportError:
113 pass
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000114
Guido van Rossumb6775db1994-08-01 11:34:53 +0000115class Profile:
Tim Peters2344fae2001-01-15 00:50:52 +0000116 """Profiler class.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000117
Tim Peters2344fae2001-01-15 00:50:52 +0000118 self.cur is always a tuple. Each such tuple corresponds to a stack
119 frame that is currently active (self.cur[-2]). The following are the
120 definitions of its members. We use this external "parallel stack" to
121 avoid contaminating the program that we are profiling. (old profiler
122 used to write into the frames local dictionary!!) Derived classes
123 can change the definition of some entries, as long as they leave
Tim Petersdf5cfd82001-10-05 23:15:10 +0000124 [-2:] intact (frame and previous tuple). In case an internal error is
125 detected, the -3 element is used as the function name.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000126
Tim Petersdf5cfd82001-10-05 23:15:10 +0000127 [ 0] = Time that needs to be charged to the parent frame's function.
128 It is used so that a function call will not have to access the
129 timing data for the parent frame.
130 [ 1] = Total time spent in this frame's function, excluding time in
Tim Peters8d061ed2001-10-07 08:35:44 +0000131 subfunctions (this latter is tallied in cur[2]).
Tim Petersfb163782001-10-07 08:49:02 +0000132 [ 2] = Total time spent in subfunctions, excluding time executing the
Tim Peters8d061ed2001-10-07 08:35:44 +0000133 frame's function (this latter is tallied in cur[1]).
Tim Petersdf5cfd82001-10-05 23:15:10 +0000134 [-3] = Name of the function that corresponds to this frame.
Tim Peters8d061ed2001-10-07 08:35:44 +0000135 [-2] = Actual frame that we correspond to (used to sync exception handling).
136 [-1] = Our parent 6-tuple (corresponds to frame.f_back).
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000137
Tim Peters2344fae2001-01-15 00:50:52 +0000138 Timing data for each function is stored as a 5-tuple in the dictionary
Tim Petersdf5cfd82001-10-05 23:15:10 +0000139 self.timings[]. The index is always the name stored in self.cur[-3].
Tim Peters2344fae2001-01-15 00:50:52 +0000140 The following are the definitions of the members:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000141
Tim Peters2344fae2001-01-15 00:50:52 +0000142 [0] = The number of times this function was called, not counting direct
143 or indirect recursion,
144 [1] = Number of times this function appears on the stack, minus one
145 [2] = Total time spent internal to this function
146 [3] = Cumulative time that this function was present on the stack. In
147 non-recursive functions, this is the total execution time from start
148 to finish of each invocation of a function, including time spent in
149 all subfunctions.
Tim Peters6e221492001-10-07 04:02:36 +0000150 [4] = A dictionary indicating for each function name, the number of times
Tim Peters2344fae2001-01-15 00:50:52 +0000151 it was called by us.
152 """
Guido van Rossumb6775db1994-08-01 11:34:53 +0000153
Tim Peters659a6032001-10-09 20:51:19 +0000154 bias = 0 # calibration constant
155
156 def __init__(self, timer=None, bias=None):
Tim Peters2344fae2001-01-15 00:50:52 +0000157 self.timings = {}
158 self.cur = None
159 self.cmd = ""
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000160 self.c_func_name = ""
Guido van Rossumb6775db1994-08-01 11:34:53 +0000161
Tim Peters659a6032001-10-09 20:51:19 +0000162 if bias is None:
163 bias = self.bias
164 self.bias = bias # Materialize in local dict for lookup speed.
165
Martin v. Löwisa4dac402005-03-03 11:39:45 +0000166 if not timer:
167 if _has_res:
168 self.timer = resgetrusage
169 self.dispatcher = self.trace_dispatch
170 self.get_time = _get_time_resource
Tim Peters2344fae2001-01-15 00:50:52 +0000171 elif hasattr(time, 'clock'):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000172 self.timer = self.get_time = time.clock
Tim Peters2344fae2001-01-15 00:50:52 +0000173 self.dispatcher = self.trace_dispatch_i
174 elif hasattr(os, 'times'):
175 self.timer = os.times
176 self.dispatcher = self.trace_dispatch
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000177 self.get_time = _get_time_times
Tim Peters2344fae2001-01-15 00:50:52 +0000178 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000179 self.timer = self.get_time = time.time
Tim Peters2344fae2001-01-15 00:50:52 +0000180 self.dispatcher = self.trace_dispatch_i
181 else:
182 self.timer = timer
183 t = self.timer() # test out timer function
184 try:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000185 length = len(t)
186 except TypeError:
187 self.get_time = timer
188 self.dispatcher = self.trace_dispatch_i
189 else:
190 if length == 2:
Tim Peters2344fae2001-01-15 00:50:52 +0000191 self.dispatcher = self.trace_dispatch
192 else:
193 self.dispatcher = self.trace_dispatch_l
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000194 # This get_time() implementation needs to be defined
195 # here to capture the passed-in timer in the parameter
196 # list (for performance). Note that we can't assume
197 # the timer() result contains two values in all
198 # cases.
Raymond Hettinger97aa32b2003-10-22 16:49:01 +0000199 def get_time_timer(timer=timer, sum=sum):
200 return sum(timer())
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000201 self.get_time = get_time_timer
Tim Peters2344fae2001-01-15 00:50:52 +0000202 self.t = self.get_time()
203 self.simulate_call('profiler')
Guido van Rossumb6775db1994-08-01 11:34:53 +0000204
Tim Peters2344fae2001-01-15 00:50:52 +0000205 # Heavily optimized dispatch routine for os.times() timer
Guido van Rossumb6775db1994-08-01 11:34:53 +0000206
Tim Peters2344fae2001-01-15 00:50:52 +0000207 def trace_dispatch(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000208 timer = self.timer
209 t = timer()
Tim Peters659a6032001-10-09 20:51:19 +0000210 t = t[0] + t[1] - self.t - self.bias
Tim Peters2344fae2001-01-15 00:50:52 +0000211
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000212 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000213 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000214
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000215 if self.dispatch[event](self, frame,t):
216 t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000217 self.t = t[0] + t[1]
218 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000219 r = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000220 self.t = r[0] + r[1] - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000221
Tim Peters6e221492001-10-07 04:02:36 +0000222 # Dispatch routine for best timer program (return = scalar, fastest if
223 # an integer but float works too -- and time.clock() relies on that).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000224
Tim Peters2344fae2001-01-15 00:50:52 +0000225 def trace_dispatch_i(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000226 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000227 t = timer() - self.t - self.bias
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000228
229 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000230 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000231
232 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000233 self.t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000234 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000235 self.t = timer() - t # put back unrecorded delta
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000236
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000237 # Dispatch routine for macintosh (timer returns time in ticks of
238 # 1/60th second)
Tim Peters2344fae2001-01-15 00:50:52 +0000239
240 def trace_dispatch_mac(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000241 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000242 t = timer()/60.0 - self.t - self.bias
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000243
244 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000245 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000246
Tim Peters659a6032001-10-09 20:51:19 +0000247 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000248 self.t = timer()/60.0
Tim Peters2344fae2001-01-15 00:50:52 +0000249 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000250 self.t = timer()/60.0 - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000251
Tim Peters2344fae2001-01-15 00:50:52 +0000252 # SLOW generic dispatch routine for timer returning lists of numbers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000253
Tim Peters2344fae2001-01-15 00:50:52 +0000254 def trace_dispatch_l(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000255 get_time = self.get_time
Tim Peters659a6032001-10-09 20:51:19 +0000256 t = get_time() - self.t - self.bias
Guido van Rossumb6775db1994-08-01 11:34:53 +0000257
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000258 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000259 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000260
Tim Peters659a6032001-10-09 20:51:19 +0000261 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000262 self.t = get_time()
Tim Peters2344fae2001-01-15 00:50:52 +0000263 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000264 self.t = get_time() - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000265
Tim Peters8d061ed2001-10-07 08:35:44 +0000266 # In the event handlers, the first 3 elements of self.cur are unpacked
267 # into vrbls w/ 3-letter names. The last two characters are meant to be
268 # mnemonic:
269 # _pt self.cur[0] "parent time" time to be charged to parent frame
270 # _it self.cur[1] "internal time" time spent directly in the function
271 # _et self.cur[2] "external time" time spent in subfunctions
Guido van Rossumb6775db1994-08-01 11:34:53 +0000272
Tim Peters2344fae2001-01-15 00:50:52 +0000273 def trace_dispatch_exception(self, frame, t):
Tim Peters8d061ed2001-10-07 08:35:44 +0000274 rpt, rit, ret, rfn, rframe, rcur = self.cur
Fred Drakea0bc9992001-10-03 21:12:32 +0000275 if (rframe is not frame) and rcur:
Tim Peters2344fae2001-01-15 00:50:52 +0000276 return self.trace_dispatch_return(rframe, t)
Tim Peters8d061ed2001-10-07 08:35:44 +0000277 self.cur = rpt, rit+t, ret, rfn, rframe, rcur
Guido van Rossumf137f752001-10-04 00:58:24 +0000278 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000279
280
Tim Peters2344fae2001-01-15 00:50:52 +0000281 def trace_dispatch_call(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000282 if self.cur and frame.f_back is not self.cur[-2]:
Tim Peters8d061ed2001-10-07 08:35:44 +0000283 rpt, rit, ret, rfn, rframe, rcur = self.cur
Guido van Rossumf137f752001-10-04 00:58:24 +0000284 if not isinstance(rframe, Profile.fake_frame):
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000285 assert rframe.f_back is frame.f_back, ("Bad call", rfn,
286 rframe, rframe.f_back,
287 frame, frame.f_back)
Guido van Rossumf137f752001-10-04 00:58:24 +0000288 self.trace_dispatch_return(rframe, 0)
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000289 assert (self.cur is None or \
290 frame.f_back is self.cur[-2]), ("Bad call",
291 self.cur[-3])
Tim Peters2344fae2001-01-15 00:50:52 +0000292 fcode = frame.f_code
293 fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
294 self.cur = (t, 0, 0, fn, frame, self.cur)
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000295 timings = self.timings
Raymond Hettinger54f02222002-06-01 14:18:47 +0000296 if fn in timings:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000297 cc, ns, tt, ct, callers = timings[fn]
298 timings[fn] = cc, ns + 1, tt, ct, callers
Tim Peters2344fae2001-01-15 00:50:52 +0000299 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000300 timings[fn] = 0, 0, 0, 0, {}
Tim Peters2344fae2001-01-15 00:50:52 +0000301 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000302
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000303 def trace_dispatch_c_call (self, frame, t):
304 fn = ("", 0, self.c_func_name)
305 self.cur = (t, 0, 0, fn, frame, self.cur)
306 timings = self.timings
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000307 if fn in timings:
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000308 cc, ns, tt, ct, callers = timings[fn]
309 timings[fn] = cc, ns+1, tt, ct, callers
310 else:
311 timings[fn] = 0, 0, 0, 0, {}
312 return 1
313
Tim Peters2344fae2001-01-15 00:50:52 +0000314 def trace_dispatch_return(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000315 if frame is not self.cur[-2]:
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000316 assert frame is self.cur[-2].f_back, ("Bad return", self.cur[-3])
317 self.trace_dispatch_return(self.cur[-2], 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000318
Tim Peters8d061ed2001-10-07 08:35:44 +0000319 # Prefix "r" means part of the Returning or exiting frame.
320 # Prefix "p" means part of the Previous or Parent or older frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000321
Tim Peters8d061ed2001-10-07 08:35:44 +0000322 rpt, rit, ret, rfn, frame, rcur = self.cur
323 rit = rit + t
324 frame_total = rit + ret
Guido van Rossumb6775db1994-08-01 11:34:53 +0000325
Tim Peters8d061ed2001-10-07 08:35:44 +0000326 ppt, pit, pet, pfn, pframe, pcur = rcur
327 self.cur = ppt, pit + rpt, pet + frame_total, pfn, pframe, pcur
Guido van Rossumb6775db1994-08-01 11:34:53 +0000328
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000329 timings = self.timings
330 cc, ns, tt, ct, callers = timings[rfn]
Tim Peters2344fae2001-01-15 00:50:52 +0000331 if not ns:
Tim Peters8d061ed2001-10-07 08:35:44 +0000332 # This is the only occurrence of the function on the stack.
333 # Else this is a (directly or indirectly) recursive call, and
334 # its cumulative time will get updated when the topmost call to
335 # it returns.
336 ct = ct + frame_total
Tim Peters2344fae2001-01-15 00:50:52 +0000337 cc = cc + 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000338
Raymond Hettinger54f02222002-06-01 14:18:47 +0000339 if pfn in callers:
Tim Peters2344fae2001-01-15 00:50:52 +0000340 callers[pfn] = callers[pfn] + 1 # hack: gather more
341 # stats such as the amount of time added to ct courtesy
342 # of this specific call, and the contribution to cc
343 # courtesy of this call.
344 else:
345 callers[pfn] = 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000346
347 timings[rfn] = cc, ns - 1, tt + rit, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000348
Tim Peters2344fae2001-01-15 00:50:52 +0000349 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000350
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000351
352 dispatch = {
353 "call": trace_dispatch_call,
354 "exception": trace_dispatch_exception,
355 "return": trace_dispatch_return,
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000356 "c_call": trace_dispatch_c_call,
Armin Rigof8790242005-09-20 18:50:13 +0000357 "c_exception": trace_dispatch_return, # the C function returned
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000358 "c_return": trace_dispatch_return,
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000359 }
360
361
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000362 # The next few functions play with self.cmd. By carefully preloading
Tim Peters2344fae2001-01-15 00:50:52 +0000363 # our parallel stack, we can force the profiled result to include
364 # an arbitrary string as the name of the calling function.
365 # We use self.cmd as that string, and the resulting stats look
366 # very nice :-).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000367
Tim Peters2344fae2001-01-15 00:50:52 +0000368 def set_cmd(self, cmd):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000369 if self.cur[-1]: return # already set
Tim Peters2344fae2001-01-15 00:50:52 +0000370 self.cmd = cmd
371 self.simulate_call(cmd)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000372
Tim Peters2344fae2001-01-15 00:50:52 +0000373 class fake_code:
374 def __init__(self, filename, line, name):
375 self.co_filename = filename
376 self.co_line = line
377 self.co_name = name
378 self.co_firstlineno = 0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000379
Tim Peters2344fae2001-01-15 00:50:52 +0000380 def __repr__(self):
381 return repr((self.co_filename, self.co_line, self.co_name))
Guido van Rossumb6775db1994-08-01 11:34:53 +0000382
Tim Peters2344fae2001-01-15 00:50:52 +0000383 class fake_frame:
384 def __init__(self, code, prior):
385 self.f_code = code
386 self.f_back = prior
Guido van Rossumb6775db1994-08-01 11:34:53 +0000387
Tim Peters2344fae2001-01-15 00:50:52 +0000388 def simulate_call(self, name):
389 code = self.fake_code('profile', 0, name)
390 if self.cur:
Tim Petersdf5cfd82001-10-05 23:15:10 +0000391 pframe = self.cur[-2]
Tim Peters2344fae2001-01-15 00:50:52 +0000392 else:
393 pframe = None
394 frame = self.fake_frame(code, pframe)
Fred Draked10ed8b2001-10-17 01:49:50 +0000395 self.dispatch['call'](self, frame, 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000396
Tim Peters2344fae2001-01-15 00:50:52 +0000397 # collect stats from pending stack, including getting final
398 # timings for self.cmd frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000399
Tim Peters2344fae2001-01-15 00:50:52 +0000400 def simulate_cmd_complete(self):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000401 get_time = self.get_time
402 t = get_time() - self.t
Tim Petersdf5cfd82001-10-05 23:15:10 +0000403 while self.cur[-1]:
Tim Peters2344fae2001-01-15 00:50:52 +0000404 # We *can* cause assertion errors here if
405 # dispatch_trace_return checks for a frame match!
Fred Draked10ed8b2001-10-17 01:49:50 +0000406 self.dispatch['return'](self, self.cur[-2], t)
Tim Peters2344fae2001-01-15 00:50:52 +0000407 t = 0
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000408 self.t = get_time() - t
Guido van Rossumb6775db1994-08-01 11:34:53 +0000409
410
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000411 def print_stats(self, sort=-1):
Tim Peters2344fae2001-01-15 00:50:52 +0000412 import pstats
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000413 pstats.Stats(self).strip_dirs().sort_stats(sort). \
Tim Peters2344fae2001-01-15 00:50:52 +0000414 print_stats()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000415
Tim Peters2344fae2001-01-15 00:50:52 +0000416 def dump_stats(self, file):
417 f = open(file, 'wb')
418 self.create_stats()
419 marshal.dump(self.stats, f)
420 f.close()
421
422 def create_stats(self):
423 self.simulate_cmd_complete()
424 self.snapshot_stats()
425
426 def snapshot_stats(self):
427 self.stats = {}
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000428 for func, (cc, ns, tt, ct, callers) in self.timings.items():
Tim Peters2344fae2001-01-15 00:50:52 +0000429 callers = callers.copy()
430 nc = 0
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000431 for callcnt in callers.values():
Raymond Hettingere0d49722002-06-02 18:55:56 +0000432 nc += callcnt
Tim Peters2344fae2001-01-15 00:50:52 +0000433 self.stats[func] = cc, nc, tt, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000434
435
Tim Peters2344fae2001-01-15 00:50:52 +0000436 # The following two methods can be called by clients to use
437 # a profiler to profile a statement, given as a string.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000438
Tim Peters2344fae2001-01-15 00:50:52 +0000439 def run(self, cmd):
440 import __main__
441 dict = __main__.__dict__
442 return self.runctx(cmd, dict, dict)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000443
Tim Peters2344fae2001-01-15 00:50:52 +0000444 def runctx(self, cmd, globals, locals):
445 self.set_cmd(cmd)
446 sys.setprofile(self.dispatcher)
447 try:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000448 exec(cmd, globals, locals)
Tim Peters2344fae2001-01-15 00:50:52 +0000449 finally:
450 sys.setprofile(None)
451 return self
Guido van Rossumb6775db1994-08-01 11:34:53 +0000452
Tim Peters2344fae2001-01-15 00:50:52 +0000453 # This method is more useful to profile a single function call.
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000454 def runcall(self, func, *args, **kw):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000455 self.set_cmd(repr(func))
Tim Peters2344fae2001-01-15 00:50:52 +0000456 sys.setprofile(self.dispatcher)
457 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +0000458 return func(*args, **kw)
Tim Peters2344fae2001-01-15 00:50:52 +0000459 finally:
460 sys.setprofile(None)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000461
Tim Peters2344fae2001-01-15 00:50:52 +0000462
463 #******************************************************************
464 # The following calculates the overhead for using a profiler. The
465 # problem is that it takes a fair amount of time for the profiler
466 # to stop the stopwatch (from the time it receives an event).
467 # Similarly, there is a delay from the time that the profiler
468 # re-starts the stopwatch before the user's code really gets to
469 # continue. The following code tries to measure the difference on
Tim Peters659a6032001-10-09 20:51:19 +0000470 # a per-event basis.
471 #
472 # Note that this difference is only significant if there are a lot of
Tim Peters2344fae2001-01-15 00:50:52 +0000473 # events, and relatively little user code per event. For example,
474 # code with small functions will typically benefit from having the
475 # profiler calibrated for the current platform. This *could* be
476 # done on the fly during init() time, but it is not worth the
477 # effort. Also note that if too large a value specified, then
478 # execution time on some functions will actually appear as a
479 # negative number. It is *normal* for some functions (with very
480 # low call counts) to have such negative stats, even if the
481 # calibration figure is "correct."
482 #
483 # One alternative to profile-time calibration adjustments (i.e.,
484 # adding in the magic little delta during each event) is to track
485 # more carefully the number of events (and cumulatively, the number
486 # of events during sub functions) that are seen. If this were
487 # done, then the arithmetic could be done after the fact (i.e., at
488 # display time). Currently, we track only call/return events.
489 # These values can be deduced by examining the callees and callers
490 # vectors for each functions. Hence we *can* almost correct the
491 # internal time figure at print time (note that we currently don't
492 # track exception event processing counts). Unfortunately, there
493 # is currently no similar information for cumulative sub-function
494 # time. It would not be hard to "get all this info" at profiler
495 # time. Specifically, we would have to extend the tuples to keep
496 # counts of this in each frame, and then extend the defs of timing
497 # tuples to include the significant two figures. I'm a bit fearful
498 # that this additional feature will slow the heavily optimized
499 # event/time ratio (i.e., the profiler would run slower, fur a very
500 # low "value added" feature.)
Tim Peters2344fae2001-01-15 00:50:52 +0000501 #**************************************************************
502
Tim Peterscce092d2001-10-09 05:31:56 +0000503 def calibrate(self, m, verbose=0):
Tim Peters659a6032001-10-09 20:51:19 +0000504 if self.__class__ is not Profile:
505 raise TypeError("Subclasses must override .calibrate().")
506
507 saved_bias = self.bias
508 self.bias = 0
509 try:
Tim Peterse13cc922001-10-09 21:01:31 +0000510 return self._calibrate_inner(m, verbose)
Tim Peters659a6032001-10-09 20:51:19 +0000511 finally:
512 self.bias = saved_bias
513
Tim Peterse13cc922001-10-09 21:01:31 +0000514 def _calibrate_inner(self, m, verbose):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000515 get_time = self.get_time
Tim Peters2344fae2001-01-15 00:50:52 +0000516
Tim Peterscce092d2001-10-09 05:31:56 +0000517 # Set up a test case to be run with and without profiling. Include
518 # lots of calls, because we're trying to quantify stopwatch overhead.
519 # Do not raise any exceptions, though, because we want to know
520 # exactly how many profile events are generated (one call event, +
521 # one return event, per Python-level call).
Tim Peters2344fae2001-01-15 00:50:52 +0000522
Tim Peterscce092d2001-10-09 05:31:56 +0000523 def f1(n):
524 for i in range(n):
525 x = 1
Tim Peters2344fae2001-01-15 00:50:52 +0000526
Tim Peterscce092d2001-10-09 05:31:56 +0000527 def f(m, f1=f1):
528 for i in range(m):
529 f1(100)
Tim Peters2344fae2001-01-15 00:50:52 +0000530
Tim Peterscce092d2001-10-09 05:31:56 +0000531 f(m) # warm up the cache
532
533 # elapsed_noprofile <- time f(m) takes without profiling.
534 t0 = get_time()
535 f(m)
536 t1 = get_time()
537 elapsed_noprofile = t1 - t0
538 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000539 print("elapsed time without profiling =", elapsed_noprofile)
Tim Peterscce092d2001-10-09 05:31:56 +0000540
541 # elapsed_profile <- time f(m) takes with profiling. The difference
542 # is profiling overhead, only some of which the profiler subtracts
543 # out on its own.
544 p = Profile()
545 t0 = get_time()
546 p.runctx('f(m)', globals(), locals())
547 t1 = get_time()
548 elapsed_profile = t1 - t0
549 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000550 print("elapsed time with profiling =", elapsed_profile)
Tim Peterscce092d2001-10-09 05:31:56 +0000551
552 # reported_time <- "CPU seconds" the profiler charged to f and f1.
553 total_calls = 0.0
554 reported_time = 0.0
555 for (filename, line, funcname), (cc, ns, tt, ct, callers) in \
556 p.timings.items():
557 if funcname in ("f", "f1"):
558 total_calls += cc
559 reported_time += tt
560
561 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000562 print("'CPU seconds' profiler reported =", reported_time)
563 print("total # calls =", total_calls)
Tim Peterscce092d2001-10-09 05:31:56 +0000564 if total_calls != m + 1:
565 raise ValueError("internal error: total calls = %d" % total_calls)
566
567 # reported_time - elapsed_noprofile = overhead the profiler wasn't
568 # able to measure. Divide by twice the number of calls (since there
569 # are two profiler events per call in this test) to get the hidden
570 # overhead per event.
571 mean = (reported_time - elapsed_noprofile) / 2.0 / total_calls
572 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000573 print("mean stopwatch overhead per profile event =", mean)
Tim Peterscce092d2001-10-09 05:31:56 +0000574 return mean
Guido van Rossumb6775db1994-08-01 11:34:53 +0000575
Guido van Rossumb6775db1994-08-01 11:34:53 +0000576#****************************************************************************
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000577
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000578def main():
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000579 usage = "profile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000580 parser = OptionParser(usage=usage)
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000581 parser.allow_interspersed_args = False
Tim Peters4e0e1b62004-07-07 20:54:48 +0000582 parser.add_option('-o', '--outfile', dest="outfile",
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000583 help="Save stats to <outfile>", default=None)
584 parser.add_option('-s', '--sort', dest="sort",
Georg Brandl8e43fbf2010-08-02 12:20:23 +0000585 help="Sort order when printing to stdout, based on pstats.Stats class",
586 default=-1)
Tim Petersb497c102005-01-10 16:48:37 +0000587
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000588 if not sys.argv[1:]:
589 parser.print_usage()
590 sys.exit(2)
Tim Petersb497c102005-01-10 16:48:37 +0000591
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000592 (options, args) = parser.parse_args()
Georg Brandl8e43fbf2010-08-02 12:20:23 +0000593 sys.argv[:] = args
Tim Petersb497c102005-01-10 16:48:37 +0000594
Georg Brandl8e43fbf2010-08-02 12:20:23 +0000595 if len(args) > 0:
596 progname = args[0]
597 sys.path.insert(0, os.path.dirname(progname))
598 with open(progname, 'rb') as fp:
599 code = compile(fp.read(), progname, 'exec')
600 globs = {
601 '__file__': progname,
602 '__name__': '__main__',
603 '__package__': None,
604 '__cached__': None,
605 }
606 runctx(code, globs, None, options.outfile, options.sort)
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000607 else:
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000608 parser.print_usage()
609 return parser
610
611# When invoked as main program, invoke the profiler on a script
612if __name__ == '__main__':
613 main()