blob: f8d20251faa892765b8fccd7cb3380b58a366205 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
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
7#
8# See profile.doc for more information
9
Guido van Rossum54f22ed2000-02-04 15:10:34 +000010"""Class for profiling Python code."""
Guido van Rossumb6775db1994-08-01 11:34:53 +000011
12# Copyright 1994, by InfoSeek Corporation, all rights reserved.
13# Written by James Roskind
Tim Peters2344fae2001-01-15 00:50:52 +000014#
Guido van Rossumb6775db1994-08-01 11:34:53 +000015# Permission to use, copy, modify, and distribute this Python software
16# and its associated documentation for any purpose (subject to the
17# restriction in the following sentence) without fee is hereby granted,
18# provided that the above copyright notice appears in all copies, and
19# that both that copyright notice and this permission notice appear in
20# supporting documentation, and that the name of InfoSeek not be used in
21# advertising or publicity pertaining to distribution of the software
22# without specific, written prior permission. This permission is
23# explicitly restricted to the copying and modification of the software
24# to remain in Python, compiled Python, or other languages (such as C)
25# wherein the modified or derived code is exclusively imported into a
26# Python module.
Tim Peters2344fae2001-01-15 00:50:52 +000027#
Guido van Rossumb6775db1994-08-01 11:34:53 +000028# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
29# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
30# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
31# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
32# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
33# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
34# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35
36
Guido van Rossum81762581992-04-21 15:36:23 +000037
38import sys
Guido van Rossum4e160981992-09-02 20:43:20 +000039import os
Guido van Rossumb6775db1994-08-01 11:34:53 +000040import time
Guido van Rossum4e160981992-09-02 20:43:20 +000041import marshal
Guido van Rossum81762581992-04-21 15:36:23 +000042
Skip Montanaroc62c81e2001-02-12 02:00:42 +000043__all__ = ["run","help","Profile"]
Guido van Rossum81762581992-04-21 15:36:23 +000044
Tim Peters2344fae2001-01-15 00:50:52 +000045# Sample timer for use with
Guido van Rossumb6775db1994-08-01 11:34:53 +000046#i_count = 0
47#def integer_timer():
Tim Peters2344fae2001-01-15 00:50:52 +000048# global i_count
49# i_count = i_count + 1
50# return i_count
Guido van Rossumb6775db1994-08-01 11:34:53 +000051#itimes = integer_timer # replace with C coded timer returning integers
Guido van Rossum81762581992-04-21 15:36:23 +000052
Guido van Rossumb6775db1994-08-01 11:34:53 +000053#**************************************************************************
54# The following are the static member functions for the profiler class
55# Note that an instance of Profile() is *not* needed to call them.
56#**************************************************************************
Guido van Rossum81762581992-04-21 15:36:23 +000057
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000058def run(statement, filename=None):
59 """Run statement under profiler optionally saving results in filename
Guido van Rossum4e160981992-09-02 20:43:20 +000060
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000061 This function takes a single argument that can be passed to the
62 "exec" statement, and an optional file name. In all cases this
63 routine attempts to "exec" its first argument and gather profiling
64 statistics from the execution. If no file name is present, then this
65 function automatically prints a simple profiling report, sorted by the
66 standard name string (file/line/function-name) that is presented in
67 each line.
68 """
Tim Peters2344fae2001-01-15 00:50:52 +000069 prof = Profile()
70 try:
71 prof = prof.run(statement)
72 except SystemExit:
73 pass
Jeremy Hyltonadcf8a02001-03-14 20:01:19 +000074 if filename is not None:
75 prof.dump_stats(filename)
Tim Peters2344fae2001-01-15 00:50:52 +000076 else:
77 return prof.print_stats()
Guido van Rossume61fa0a1993-10-22 13:56:35 +000078
79# print help
80def help():
Tim Peters2344fae2001-01-15 00:50:52 +000081 for dirname in sys.path:
82 fullname = os.path.join(dirname, 'profile.doc')
83 if os.path.exists(fullname):
Fred Drakeee836442001-12-05 22:27:47 +000084 sts = os.system('${PAGER-more} ' + fullname)
Tim Peters2344fae2001-01-15 00:50:52 +000085 if sts: print '*** Pager exit status:', sts
86 break
87 else:
88 print 'Sorry, can\'t find the help file "profile.doc"',
Fred Drakeee836442001-12-05 22:27:47 +000089 print 'along the Python search path.'
Guido van Rossumb6775db1994-08-01 11:34:53 +000090
91
Fred Drakeedb5ffb2001-06-08 04:25:24 +000092if os.name == "mac":
Jack Jansen1bdcadd2001-06-19 20:11:36 +000093 import MacOS
Fred Drakeedb5ffb2001-06-08 04:25:24 +000094 def _get_time_mac(timer=MacOS.GetTicks):
95 return timer() / 60.0
96
97if hasattr(os, "times"):
98 def _get_time_times(timer=os.times):
99 t = timer()
100 return t[0] + t[1]
101
102
Guido van Rossumb6775db1994-08-01 11:34:53 +0000103class Profile:
Tim Peters2344fae2001-01-15 00:50:52 +0000104 """Profiler class.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000105
Tim Peters2344fae2001-01-15 00:50:52 +0000106 self.cur is always a tuple. Each such tuple corresponds to a stack
107 frame that is currently active (self.cur[-2]). The following are the
108 definitions of its members. We use this external "parallel stack" to
109 avoid contaminating the program that we are profiling. (old profiler
110 used to write into the frames local dictionary!!) Derived classes
111 can change the definition of some entries, as long as they leave
Tim Petersdf5cfd82001-10-05 23:15:10 +0000112 [-2:] intact (frame and previous tuple). In case an internal error is
113 detected, the -3 element is used as the function name.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000114
Tim Petersdf5cfd82001-10-05 23:15:10 +0000115 [ 0] = Time that needs to be charged to the parent frame's function.
116 It is used so that a function call will not have to access the
117 timing data for the parent frame.
118 [ 1] = Total time spent in this frame's function, excluding time in
Tim Peters8d061ed2001-10-07 08:35:44 +0000119 subfunctions (this latter is tallied in cur[2]).
Tim Petersfb163782001-10-07 08:49:02 +0000120 [ 2] = Total time spent in subfunctions, excluding time executing the
Tim Peters8d061ed2001-10-07 08:35:44 +0000121 frame's function (this latter is tallied in cur[1]).
Tim Petersdf5cfd82001-10-05 23:15:10 +0000122 [-3] = Name of the function that corresponds to this frame.
Tim Peters8d061ed2001-10-07 08:35:44 +0000123 [-2] = Actual frame that we correspond to (used to sync exception handling).
124 [-1] = Our parent 6-tuple (corresponds to frame.f_back).
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000125
Tim Peters2344fae2001-01-15 00:50:52 +0000126 Timing data for each function is stored as a 5-tuple in the dictionary
Tim Petersdf5cfd82001-10-05 23:15:10 +0000127 self.timings[]. The index is always the name stored in self.cur[-3].
Tim Peters2344fae2001-01-15 00:50:52 +0000128 The following are the definitions of the members:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000129
Tim Peters2344fae2001-01-15 00:50:52 +0000130 [0] = The number of times this function was called, not counting direct
131 or indirect recursion,
132 [1] = Number of times this function appears on the stack, minus one
133 [2] = Total time spent internal to this function
134 [3] = Cumulative time that this function was present on the stack. In
135 non-recursive functions, this is the total execution time from start
136 to finish of each invocation of a function, including time spent in
137 all subfunctions.
Tim Peters6e221492001-10-07 04:02:36 +0000138 [4] = A dictionary indicating for each function name, the number of times
Tim Peters2344fae2001-01-15 00:50:52 +0000139 it was called by us.
140 """
Guido van Rossumb6775db1994-08-01 11:34:53 +0000141
Tim Peters659a6032001-10-09 20:51:19 +0000142 bias = 0 # calibration constant
143
144 def __init__(self, timer=None, bias=None):
Tim Peters2344fae2001-01-15 00:50:52 +0000145 self.timings = {}
146 self.cur = None
147 self.cmd = ""
Guido van Rossumb6775db1994-08-01 11:34:53 +0000148
Tim Peters659a6032001-10-09 20:51:19 +0000149 if bias is None:
150 bias = self.bias
151 self.bias = bias # Materialize in local dict for lookup speed.
152
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000153 if timer is None:
Tim Peters2344fae2001-01-15 00:50:52 +0000154 if os.name == 'mac':
Tim Peters2344fae2001-01-15 00:50:52 +0000155 self.timer = MacOS.GetTicks
156 self.dispatcher = self.trace_dispatch_mac
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000157 self.get_time = _get_time_mac
Tim Peters2344fae2001-01-15 00:50:52 +0000158 elif hasattr(time, 'clock'):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000159 self.timer = self.get_time = time.clock
Tim Peters2344fae2001-01-15 00:50:52 +0000160 self.dispatcher = self.trace_dispatch_i
161 elif hasattr(os, 'times'):
162 self.timer = os.times
163 self.dispatcher = self.trace_dispatch
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000164 self.get_time = _get_time_times
Tim Peters2344fae2001-01-15 00:50:52 +0000165 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000166 self.timer = self.get_time = time.time
Tim Peters2344fae2001-01-15 00:50:52 +0000167 self.dispatcher = self.trace_dispatch_i
168 else:
169 self.timer = timer
170 t = self.timer() # test out timer function
171 try:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000172 length = len(t)
173 except TypeError:
174 self.get_time = timer
175 self.dispatcher = self.trace_dispatch_i
176 else:
177 if length == 2:
Tim Peters2344fae2001-01-15 00:50:52 +0000178 self.dispatcher = self.trace_dispatch
179 else:
180 self.dispatcher = self.trace_dispatch_l
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000181 # This get_time() implementation needs to be defined
182 # here to capture the passed-in timer in the parameter
183 # list (for performance). Note that we can't assume
184 # the timer() result contains two values in all
185 # cases.
Guido van Rossume4deb952001-08-09 21:22:15 +0000186 import operator
Raymond Hettinger97aa32b2003-10-22 16:49:01 +0000187 def get_time_timer(timer=timer, sum=sum):
188 return sum(timer())
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000189 self.get_time = get_time_timer
Tim Peters2344fae2001-01-15 00:50:52 +0000190 self.t = self.get_time()
191 self.simulate_call('profiler')
Guido van Rossumb6775db1994-08-01 11:34:53 +0000192
Tim Peters2344fae2001-01-15 00:50:52 +0000193 # Heavily optimized dispatch routine for os.times() timer
Guido van Rossumb6775db1994-08-01 11:34:53 +0000194
Tim Peters2344fae2001-01-15 00:50:52 +0000195 def trace_dispatch(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000196 timer = self.timer
197 t = timer()
Tim Peters659a6032001-10-09 20:51:19 +0000198 t = t[0] + t[1] - self.t - self.bias
Tim Peters2344fae2001-01-15 00:50:52 +0000199
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000200 if self.dispatch[event](self, frame,t):
201 t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000202 self.t = t[0] + t[1]
203 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000204 r = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000205 self.t = r[0] + r[1] - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000206
Tim Peters6e221492001-10-07 04:02:36 +0000207 # Dispatch routine for best timer program (return = scalar, fastest if
208 # an integer but float works too -- and time.clock() relies on that).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000209
Tim Peters2344fae2001-01-15 00:50:52 +0000210 def trace_dispatch_i(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000211 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000212 t = timer() - self.t - self.bias
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000213 if self.dispatch[event](self, frame,t):
214 self.t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000215 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000216 self.t = timer() - t # put back unrecorded delta
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000217
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000218 # Dispatch routine for macintosh (timer returns time in ticks of
219 # 1/60th second)
Tim Peters2344fae2001-01-15 00:50:52 +0000220
221 def trace_dispatch_mac(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000222 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000223 t = timer()/60.0 - self.t - self.bias
224 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000225 self.t = timer()/60.0
Tim Peters2344fae2001-01-15 00:50:52 +0000226 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000227 self.t = timer()/60.0 - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000228
Tim Peters2344fae2001-01-15 00:50:52 +0000229 # SLOW generic dispatch routine for timer returning lists of numbers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000230
Tim Peters2344fae2001-01-15 00:50:52 +0000231 def trace_dispatch_l(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000232 get_time = self.get_time
Tim Peters659a6032001-10-09 20:51:19 +0000233 t = get_time() - self.t - self.bias
Guido van Rossumb6775db1994-08-01 11:34:53 +0000234
Tim Peters659a6032001-10-09 20:51:19 +0000235 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000236 self.t = get_time()
Tim Peters2344fae2001-01-15 00:50:52 +0000237 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000238 self.t = get_time() - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000239
Tim Peters8d061ed2001-10-07 08:35:44 +0000240 # In the event handlers, the first 3 elements of self.cur are unpacked
241 # into vrbls w/ 3-letter names. The last two characters are meant to be
242 # mnemonic:
243 # _pt self.cur[0] "parent time" time to be charged to parent frame
244 # _it self.cur[1] "internal time" time spent directly in the function
245 # _et self.cur[2] "external time" time spent in subfunctions
Guido van Rossumb6775db1994-08-01 11:34:53 +0000246
Tim Peters2344fae2001-01-15 00:50:52 +0000247 def trace_dispatch_exception(self, frame, t):
Tim Peters8d061ed2001-10-07 08:35:44 +0000248 rpt, rit, ret, rfn, rframe, rcur = self.cur
Fred Drakea0bc9992001-10-03 21:12:32 +0000249 if (rframe is not frame) and rcur:
Tim Peters2344fae2001-01-15 00:50:52 +0000250 return self.trace_dispatch_return(rframe, t)
Tim Peters8d061ed2001-10-07 08:35:44 +0000251 self.cur = rpt, rit+t, ret, rfn, rframe, rcur
Guido van Rossumf137f752001-10-04 00:58:24 +0000252 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000253
254
Tim Peters2344fae2001-01-15 00:50:52 +0000255 def trace_dispatch_call(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000256 if self.cur and frame.f_back is not self.cur[-2]:
Tim Peters8d061ed2001-10-07 08:35:44 +0000257 rpt, rit, ret, rfn, rframe, rcur = self.cur
Guido van Rossumf137f752001-10-04 00:58:24 +0000258 if not isinstance(rframe, Profile.fake_frame):
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000259 assert rframe.f_back is frame.f_back, ("Bad call", rfn,
260 rframe, rframe.f_back,
261 frame, frame.f_back)
Guido van Rossumf137f752001-10-04 00:58:24 +0000262 self.trace_dispatch_return(rframe, 0)
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000263 assert (self.cur is None or \
264 frame.f_back is self.cur[-2]), ("Bad call",
265 self.cur[-3])
Tim Peters2344fae2001-01-15 00:50:52 +0000266 fcode = frame.f_code
267 fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
268 self.cur = (t, 0, 0, fn, frame, self.cur)
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000269 timings = self.timings
Raymond Hettinger54f02222002-06-01 14:18:47 +0000270 if fn in timings:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000271 cc, ns, tt, ct, callers = timings[fn]
272 timings[fn] = cc, ns + 1, tt, ct, callers
Tim Peters2344fae2001-01-15 00:50:52 +0000273 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000274 timings[fn] = 0, 0, 0, 0, {}
Tim Peters2344fae2001-01-15 00:50:52 +0000275 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000276
Tim Peters2344fae2001-01-15 00:50:52 +0000277 def trace_dispatch_return(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000278 if frame is not self.cur[-2]:
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000279 assert frame is self.cur[-2].f_back, ("Bad return", self.cur[-3])
280 self.trace_dispatch_return(self.cur[-2], 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000281
Tim Peters8d061ed2001-10-07 08:35:44 +0000282 # Prefix "r" means part of the Returning or exiting frame.
283 # Prefix "p" means part of the Previous or Parent or older frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000284
Tim Peters8d061ed2001-10-07 08:35:44 +0000285 rpt, rit, ret, rfn, frame, rcur = self.cur
286 rit = rit + t
287 frame_total = rit + ret
Guido van Rossumb6775db1994-08-01 11:34:53 +0000288
Tim Peters8d061ed2001-10-07 08:35:44 +0000289 ppt, pit, pet, pfn, pframe, pcur = rcur
290 self.cur = ppt, pit + rpt, pet + frame_total, pfn, pframe, pcur
Guido van Rossumb6775db1994-08-01 11:34:53 +0000291
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000292 timings = self.timings
293 cc, ns, tt, ct, callers = timings[rfn]
Tim Peters2344fae2001-01-15 00:50:52 +0000294 if not ns:
Tim Peters8d061ed2001-10-07 08:35:44 +0000295 # This is the only occurrence of the function on the stack.
296 # Else this is a (directly or indirectly) recursive call, and
297 # its cumulative time will get updated when the topmost call to
298 # it returns.
299 ct = ct + frame_total
Tim Peters2344fae2001-01-15 00:50:52 +0000300 cc = cc + 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000301
Raymond Hettinger54f02222002-06-01 14:18:47 +0000302 if pfn in callers:
Tim Peters2344fae2001-01-15 00:50:52 +0000303 callers[pfn] = callers[pfn] + 1 # hack: gather more
304 # stats such as the amount of time added to ct courtesy
305 # of this specific call, and the contribution to cc
306 # courtesy of this call.
307 else:
308 callers[pfn] = 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000309
310 timings[rfn] = cc, ns - 1, tt + rit, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000311
Tim Peters2344fae2001-01-15 00:50:52 +0000312 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000313
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000314
315 dispatch = {
316 "call": trace_dispatch_call,
317 "exception": trace_dispatch_exception,
318 "return": trace_dispatch_return,
319 }
320
321
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000322 # The next few functions play with self.cmd. By carefully preloading
Tim Peters2344fae2001-01-15 00:50:52 +0000323 # our parallel stack, we can force the profiled result to include
324 # an arbitrary string as the name of the calling function.
325 # We use self.cmd as that string, and the resulting stats look
326 # very nice :-).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000327
Tim Peters2344fae2001-01-15 00:50:52 +0000328 def set_cmd(self, cmd):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000329 if self.cur[-1]: return # already set
Tim Peters2344fae2001-01-15 00:50:52 +0000330 self.cmd = cmd
331 self.simulate_call(cmd)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000332
Tim Peters2344fae2001-01-15 00:50:52 +0000333 class fake_code:
334 def __init__(self, filename, line, name):
335 self.co_filename = filename
336 self.co_line = line
337 self.co_name = name
338 self.co_firstlineno = 0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000339
Tim Peters2344fae2001-01-15 00:50:52 +0000340 def __repr__(self):
341 return repr((self.co_filename, self.co_line, self.co_name))
Guido van Rossumb6775db1994-08-01 11:34:53 +0000342
Tim Peters2344fae2001-01-15 00:50:52 +0000343 class fake_frame:
344 def __init__(self, code, prior):
345 self.f_code = code
346 self.f_back = prior
Guido van Rossumb6775db1994-08-01 11:34:53 +0000347
Tim Peters2344fae2001-01-15 00:50:52 +0000348 def simulate_call(self, name):
349 code = self.fake_code('profile', 0, name)
350 if self.cur:
Tim Petersdf5cfd82001-10-05 23:15:10 +0000351 pframe = self.cur[-2]
Tim Peters2344fae2001-01-15 00:50:52 +0000352 else:
353 pframe = None
354 frame = self.fake_frame(code, pframe)
Fred Draked10ed8b2001-10-17 01:49:50 +0000355 self.dispatch['call'](self, frame, 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000356
Tim Peters2344fae2001-01-15 00:50:52 +0000357 # collect stats from pending stack, including getting final
358 # timings for self.cmd frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000359
Tim Peters2344fae2001-01-15 00:50:52 +0000360 def simulate_cmd_complete(self):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000361 get_time = self.get_time
362 t = get_time() - self.t
Tim Petersdf5cfd82001-10-05 23:15:10 +0000363 while self.cur[-1]:
Tim Peters2344fae2001-01-15 00:50:52 +0000364 # We *can* cause assertion errors here if
365 # dispatch_trace_return checks for a frame match!
Fred Draked10ed8b2001-10-17 01:49:50 +0000366 self.dispatch['return'](self, self.cur[-2], t)
Tim Peters2344fae2001-01-15 00:50:52 +0000367 t = 0
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000368 self.t = get_time() - t
Guido van Rossumb6775db1994-08-01 11:34:53 +0000369
370
Tim Peters2344fae2001-01-15 00:50:52 +0000371 def print_stats(self):
372 import pstats
373 pstats.Stats(self).strip_dirs().sort_stats(-1). \
374 print_stats()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000375
Tim Peters2344fae2001-01-15 00:50:52 +0000376 def dump_stats(self, file):
377 f = open(file, 'wb')
378 self.create_stats()
379 marshal.dump(self.stats, f)
380 f.close()
381
382 def create_stats(self):
383 self.simulate_cmd_complete()
384 self.snapshot_stats()
385
386 def snapshot_stats(self):
387 self.stats = {}
Raymond Hettingere0d49722002-06-02 18:55:56 +0000388 for func, (cc, ns, tt, ct, callers) in self.timings.iteritems():
Tim Peters2344fae2001-01-15 00:50:52 +0000389 callers = callers.copy()
390 nc = 0
Raymond Hettingere0d49722002-06-02 18:55:56 +0000391 for callcnt in callers.itervalues():
392 nc += callcnt
Tim Peters2344fae2001-01-15 00:50:52 +0000393 self.stats[func] = cc, nc, tt, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000394
395
Tim Peters2344fae2001-01-15 00:50:52 +0000396 # The following two methods can be called by clients to use
397 # a profiler to profile a statement, given as a string.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000398
Tim Peters2344fae2001-01-15 00:50:52 +0000399 def run(self, cmd):
400 import __main__
401 dict = __main__.__dict__
402 return self.runctx(cmd, dict, dict)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000403
Tim Peters2344fae2001-01-15 00:50:52 +0000404 def runctx(self, cmd, globals, locals):
405 self.set_cmd(cmd)
406 sys.setprofile(self.dispatcher)
407 try:
408 exec cmd in globals, locals
409 finally:
410 sys.setprofile(None)
411 return self
Guido van Rossumb6775db1994-08-01 11:34:53 +0000412
Tim Peters2344fae2001-01-15 00:50:52 +0000413 # This method is more useful to profile a single function call.
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000414 def runcall(self, func, *args, **kw):
Tim Peters2344fae2001-01-15 00:50:52 +0000415 self.set_cmd(`func`)
416 sys.setprofile(self.dispatcher)
417 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +0000418 return func(*args, **kw)
Tim Peters2344fae2001-01-15 00:50:52 +0000419 finally:
420 sys.setprofile(None)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000421
Tim Peters2344fae2001-01-15 00:50:52 +0000422
423 #******************************************************************
424 # The following calculates the overhead for using a profiler. The
425 # problem is that it takes a fair amount of time for the profiler
426 # to stop the stopwatch (from the time it receives an event).
427 # Similarly, there is a delay from the time that the profiler
428 # re-starts the stopwatch before the user's code really gets to
429 # continue. The following code tries to measure the difference on
Tim Peters659a6032001-10-09 20:51:19 +0000430 # a per-event basis.
431 #
432 # Note that this difference is only significant if there are a lot of
Tim Peters2344fae2001-01-15 00:50:52 +0000433 # events, and relatively little user code per event. For example,
434 # code with small functions will typically benefit from having the
435 # profiler calibrated for the current platform. This *could* be
436 # done on the fly during init() time, but it is not worth the
437 # effort. Also note that if too large a value specified, then
438 # execution time on some functions will actually appear as a
439 # negative number. It is *normal* for some functions (with very
440 # low call counts) to have such negative stats, even if the
441 # calibration figure is "correct."
442 #
443 # One alternative to profile-time calibration adjustments (i.e.,
444 # adding in the magic little delta during each event) is to track
445 # more carefully the number of events (and cumulatively, the number
446 # of events during sub functions) that are seen. If this were
447 # done, then the arithmetic could be done after the fact (i.e., at
448 # display time). Currently, we track only call/return events.
449 # These values can be deduced by examining the callees and callers
450 # vectors for each functions. Hence we *can* almost correct the
451 # internal time figure at print time (note that we currently don't
452 # track exception event processing counts). Unfortunately, there
453 # is currently no similar information for cumulative sub-function
454 # time. It would not be hard to "get all this info" at profiler
455 # time. Specifically, we would have to extend the tuples to keep
456 # counts of this in each frame, and then extend the defs of timing
457 # tuples to include the significant two figures. I'm a bit fearful
458 # that this additional feature will slow the heavily optimized
459 # event/time ratio (i.e., the profiler would run slower, fur a very
460 # low "value added" feature.)
Tim Peters2344fae2001-01-15 00:50:52 +0000461 #**************************************************************
462
Tim Peterscce092d2001-10-09 05:31:56 +0000463 def calibrate(self, m, verbose=0):
Tim Peters659a6032001-10-09 20:51:19 +0000464 if self.__class__ is not Profile:
465 raise TypeError("Subclasses must override .calibrate().")
466
467 saved_bias = self.bias
468 self.bias = 0
469 try:
Tim Peterse13cc922001-10-09 21:01:31 +0000470 return self._calibrate_inner(m, verbose)
Tim Peters659a6032001-10-09 20:51:19 +0000471 finally:
472 self.bias = saved_bias
473
Tim Peterse13cc922001-10-09 21:01:31 +0000474 def _calibrate_inner(self, m, verbose):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000475 get_time = self.get_time
Tim Peters2344fae2001-01-15 00:50:52 +0000476
Tim Peterscce092d2001-10-09 05:31:56 +0000477 # Set up a test case to be run with and without profiling. Include
478 # lots of calls, because we're trying to quantify stopwatch overhead.
479 # Do not raise any exceptions, though, because we want to know
480 # exactly how many profile events are generated (one call event, +
481 # one return event, per Python-level call).
Tim Peters2344fae2001-01-15 00:50:52 +0000482
Tim Peterscce092d2001-10-09 05:31:56 +0000483 def f1(n):
484 for i in range(n):
485 x = 1
Tim Peters2344fae2001-01-15 00:50:52 +0000486
Tim Peterscce092d2001-10-09 05:31:56 +0000487 def f(m, f1=f1):
488 for i in range(m):
489 f1(100)
Tim Peters2344fae2001-01-15 00:50:52 +0000490
Tim Peterscce092d2001-10-09 05:31:56 +0000491 f(m) # warm up the cache
492
493 # elapsed_noprofile <- time f(m) takes without profiling.
494 t0 = get_time()
495 f(m)
496 t1 = get_time()
497 elapsed_noprofile = t1 - t0
498 if verbose:
499 print "elapsed time without profiling =", elapsed_noprofile
500
501 # elapsed_profile <- time f(m) takes with profiling. The difference
502 # is profiling overhead, only some of which the profiler subtracts
503 # out on its own.
504 p = Profile()
505 t0 = get_time()
506 p.runctx('f(m)', globals(), locals())
507 t1 = get_time()
508 elapsed_profile = t1 - t0
509 if verbose:
510 print "elapsed time with profiling =", elapsed_profile
511
512 # reported_time <- "CPU seconds" the profiler charged to f and f1.
513 total_calls = 0.0
514 reported_time = 0.0
515 for (filename, line, funcname), (cc, ns, tt, ct, callers) in \
516 p.timings.items():
517 if funcname in ("f", "f1"):
518 total_calls += cc
519 reported_time += tt
520
521 if verbose:
522 print "'CPU seconds' profiler reported =", reported_time
523 print "total # calls =", total_calls
524 if total_calls != m + 1:
525 raise ValueError("internal error: total calls = %d" % total_calls)
526
527 # reported_time - elapsed_noprofile = overhead the profiler wasn't
528 # able to measure. Divide by twice the number of calls (since there
529 # are two profiler events per call in this test) to get the hidden
530 # overhead per event.
531 mean = (reported_time - elapsed_noprofile) / 2.0 / total_calls
532 if verbose:
533 print "mean stopwatch overhead per profile event =", mean
534 return mean
Guido van Rossumb6775db1994-08-01 11:34:53 +0000535
Guido van Rossumb6775db1994-08-01 11:34:53 +0000536#****************************************************************************
537def Stats(*args):
Tim Peters2344fae2001-01-15 00:50:52 +0000538 print 'Report generating functions are in the "pstats" module\a'
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000539
540
541# When invoked as main program, invoke the profiler on a script
542if __name__ == '__main__':
Tim Peters2344fae2001-01-15 00:50:52 +0000543 if not sys.argv[1:]:
544 print "usage: profile.py scriptfile [arg] ..."
545 sys.exit(2)
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000546
Tim Peters2344fae2001-01-15 00:50:52 +0000547 filename = sys.argv[1] # Get script filename
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000548
Tim Peters2344fae2001-01-15 00:50:52 +0000549 del sys.argv[0] # Hide "profile.py" from argument list
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000550
Tim Peters2344fae2001-01-15 00:50:52 +0000551 # Insert script directory in front of module search path
552 sys.path.insert(0, os.path.dirname(filename))
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000553
Tim Peters2344fae2001-01-15 00:50:52 +0000554 run('execfile(' + `filename` + ')')