blob: d1a869a24992306bf54b90cdfb7614e72ec8362e [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
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
Nicholas Bastin1eb4bfc2004-03-22 20:12:56 +000078def runctx(statement, globals, locals, filename=None):
79 """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:
93 return prof.print_stats()
94
Fred Drakeedb5ffb2001-06-08 04:25:24 +000095if os.name == "mac":
Jack Jansen1bdcadd2001-06-19 20:11:36 +000096 import MacOS
Fred Drakeedb5ffb2001-06-08 04:25:24 +000097 def _get_time_mac(timer=MacOS.GetTicks):
98 return timer() / 60.0
99
100if hasattr(os, "times"):
101 def _get_time_times(timer=os.times):
102 t = timer()
103 return t[0] + t[1]
104
Martin v. Löwisa4dac402005-03-03 11:39:45 +0000105# Using getrusage(3) is better than clock(3) if available:
106# on some systems (e.g. FreeBSD), getrusage has a higher resolution
107# Furthermore, on a POSIX system, returns microseconds, which
108# wrap around after 36min.
109_has_res = 0
110try:
111 import resource
112 resgetrusage = lambda: resource.getrusage(resource.RUSAGE_SELF)
113 def _get_time_resource(timer=resgetrusage):
114 t = timer()
115 return t[0] + t[1]
116 _has_res = 1
117except ImportError:
118 pass
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000119
Guido van Rossumb6775db1994-08-01 11:34:53 +0000120class Profile:
Tim Peters2344fae2001-01-15 00:50:52 +0000121 """Profiler class.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000122
Tim Peters2344fae2001-01-15 00:50:52 +0000123 self.cur is always a tuple. Each such tuple corresponds to a stack
124 frame that is currently active (self.cur[-2]). The following are the
125 definitions of its members. We use this external "parallel stack" to
126 avoid contaminating the program that we are profiling. (old profiler
127 used to write into the frames local dictionary!!) Derived classes
128 can change the definition of some entries, as long as they leave
Tim Petersdf5cfd82001-10-05 23:15:10 +0000129 [-2:] intact (frame and previous tuple). In case an internal error is
130 detected, the -3 element is used as the function name.
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000131
Tim Petersdf5cfd82001-10-05 23:15:10 +0000132 [ 0] = Time that needs to be charged to the parent frame's function.
133 It is used so that a function call will not have to access the
134 timing data for the parent frame.
135 [ 1] = Total time spent in this frame's function, excluding time in
Tim Peters8d061ed2001-10-07 08:35:44 +0000136 subfunctions (this latter is tallied in cur[2]).
Tim Petersfb163782001-10-07 08:49:02 +0000137 [ 2] = Total time spent in subfunctions, excluding time executing the
Tim Peters8d061ed2001-10-07 08:35:44 +0000138 frame's function (this latter is tallied in cur[1]).
Tim Petersdf5cfd82001-10-05 23:15:10 +0000139 [-3] = Name of the function that corresponds to this frame.
Tim Peters8d061ed2001-10-07 08:35:44 +0000140 [-2] = Actual frame that we correspond to (used to sync exception handling).
141 [-1] = Our parent 6-tuple (corresponds to frame.f_back).
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000142
Tim Peters2344fae2001-01-15 00:50:52 +0000143 Timing data for each function is stored as a 5-tuple in the dictionary
Tim Petersdf5cfd82001-10-05 23:15:10 +0000144 self.timings[]. The index is always the name stored in self.cur[-3].
Tim Peters2344fae2001-01-15 00:50:52 +0000145 The following are the definitions of the members:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000146
Tim Peters2344fae2001-01-15 00:50:52 +0000147 [0] = The number of times this function was called, not counting direct
148 or indirect recursion,
149 [1] = Number of times this function appears on the stack, minus one
150 [2] = Total time spent internal to this function
151 [3] = Cumulative time that this function was present on the stack. In
152 non-recursive functions, this is the total execution time from start
153 to finish of each invocation of a function, including time spent in
154 all subfunctions.
Tim Peters6e221492001-10-07 04:02:36 +0000155 [4] = A dictionary indicating for each function name, the number of times
Tim Peters2344fae2001-01-15 00:50:52 +0000156 it was called by us.
157 """
Guido van Rossumb6775db1994-08-01 11:34:53 +0000158
Tim Peters659a6032001-10-09 20:51:19 +0000159 bias = 0 # calibration constant
160
161 def __init__(self, timer=None, bias=None):
Tim Peters2344fae2001-01-15 00:50:52 +0000162 self.timings = {}
163 self.cur = None
164 self.cmd = ""
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000165 self.c_func_name = ""
Guido van Rossumb6775db1994-08-01 11:34:53 +0000166
Tim Peters659a6032001-10-09 20:51:19 +0000167 if bias is None:
168 bias = self.bias
169 self.bias = bias # Materialize in local dict for lookup speed.
170
Martin v. Löwisa4dac402005-03-03 11:39:45 +0000171 if not timer:
172 if _has_res:
173 self.timer = resgetrusage
174 self.dispatcher = self.trace_dispatch
175 self.get_time = _get_time_resource
176 elif os.name == 'mac':
Tim Peters2344fae2001-01-15 00:50:52 +0000177 self.timer = MacOS.GetTicks
178 self.dispatcher = self.trace_dispatch_mac
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000179 self.get_time = _get_time_mac
Tim Peters2344fae2001-01-15 00:50:52 +0000180 elif hasattr(time, 'clock'):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000181 self.timer = self.get_time = time.clock
Tim Peters2344fae2001-01-15 00:50:52 +0000182 self.dispatcher = self.trace_dispatch_i
183 elif hasattr(os, 'times'):
184 self.timer = os.times
185 self.dispatcher = self.trace_dispatch
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000186 self.get_time = _get_time_times
Tim Peters2344fae2001-01-15 00:50:52 +0000187 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000188 self.timer = self.get_time = time.time
Tim Peters2344fae2001-01-15 00:50:52 +0000189 self.dispatcher = self.trace_dispatch_i
190 else:
191 self.timer = timer
192 t = self.timer() # test out timer function
193 try:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000194 length = len(t)
195 except TypeError:
196 self.get_time = timer
197 self.dispatcher = self.trace_dispatch_i
198 else:
199 if length == 2:
Tim Peters2344fae2001-01-15 00:50:52 +0000200 self.dispatcher = self.trace_dispatch
201 else:
202 self.dispatcher = self.trace_dispatch_l
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000203 # This get_time() implementation needs to be defined
204 # here to capture the passed-in timer in the parameter
205 # list (for performance). Note that we can't assume
206 # the timer() result contains two values in all
207 # cases.
Raymond Hettinger97aa32b2003-10-22 16:49:01 +0000208 def get_time_timer(timer=timer, sum=sum):
209 return sum(timer())
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000210 self.get_time = get_time_timer
Tim Peters2344fae2001-01-15 00:50:52 +0000211 self.t = self.get_time()
212 self.simulate_call('profiler')
Guido van Rossumb6775db1994-08-01 11:34:53 +0000213
Tim Peters2344fae2001-01-15 00:50:52 +0000214 # Heavily optimized dispatch routine for os.times() timer
Guido van Rossumb6775db1994-08-01 11:34:53 +0000215
Tim Peters2344fae2001-01-15 00:50:52 +0000216 def trace_dispatch(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000217 timer = self.timer
218 t = timer()
Tim Peters659a6032001-10-09 20:51:19 +0000219 t = t[0] + t[1] - self.t - self.bias
Tim Peters2344fae2001-01-15 00:50:52 +0000220
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000221 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000222 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000223
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000224 if self.dispatch[event](self, frame,t):
225 t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000226 self.t = t[0] + t[1]
227 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000228 r = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000229 self.t = r[0] + r[1] - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000230
Tim Peters6e221492001-10-07 04:02:36 +0000231 # Dispatch routine for best timer program (return = scalar, fastest if
232 # an integer but float works too -- and time.clock() relies on that).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000233
Tim Peters2344fae2001-01-15 00:50:52 +0000234 def trace_dispatch_i(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000235 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000236 t = timer() - self.t - self.bias
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000237
238 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000239 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000240
241 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000242 self.t = timer()
Tim Peters2344fae2001-01-15 00:50:52 +0000243 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000244 self.t = timer() - t # put back unrecorded delta
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000245
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000246 # Dispatch routine for macintosh (timer returns time in ticks of
247 # 1/60th second)
Tim Peters2344fae2001-01-15 00:50:52 +0000248
249 def trace_dispatch_mac(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000250 timer = self.timer
Tim Peters659a6032001-10-09 20:51:19 +0000251 t = timer()/60.0 - self.t - self.bias
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000252
253 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000254 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000255
Tim Peters659a6032001-10-09 20:51:19 +0000256 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000257 self.t = timer()/60.0
Tim Peters2344fae2001-01-15 00:50:52 +0000258 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000259 self.t = timer()/60.0 - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000260
Tim Peters2344fae2001-01-15 00:50:52 +0000261 # SLOW generic dispatch routine for timer returning lists of numbers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000262
Tim Peters2344fae2001-01-15 00:50:52 +0000263 def trace_dispatch_l(self, frame, event, arg):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000264 get_time = self.get_time
Tim Peters659a6032001-10-09 20:51:19 +0000265 t = get_time() - self.t - self.bias
Guido van Rossumb6775db1994-08-01 11:34:53 +0000266
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000267 if event == "c_call":
Nicholas Bastin12ac3e12004-07-12 23:38:02 +0000268 self.c_func_name = arg.__name__
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000269
Tim Peters659a6032001-10-09 20:51:19 +0000270 if self.dispatch[event](self, frame, t):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000271 self.t = get_time()
Tim Peters2344fae2001-01-15 00:50:52 +0000272 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000273 self.t = get_time() - t # put back unrecorded delta
Guido van Rossumb6775db1994-08-01 11:34:53 +0000274
Tim Peters8d061ed2001-10-07 08:35:44 +0000275 # In the event handlers, the first 3 elements of self.cur are unpacked
276 # into vrbls w/ 3-letter names. The last two characters are meant to be
277 # mnemonic:
278 # _pt self.cur[0] "parent time" time to be charged to parent frame
279 # _it self.cur[1] "internal time" time spent directly in the function
280 # _et self.cur[2] "external time" time spent in subfunctions
Guido van Rossumb6775db1994-08-01 11:34:53 +0000281
Tim Peters2344fae2001-01-15 00:50:52 +0000282 def trace_dispatch_exception(self, frame, t):
Tim Peters8d061ed2001-10-07 08:35:44 +0000283 rpt, rit, ret, rfn, rframe, rcur = self.cur
Fred Drakea0bc9992001-10-03 21:12:32 +0000284 if (rframe is not frame) and rcur:
Tim Peters2344fae2001-01-15 00:50:52 +0000285 return self.trace_dispatch_return(rframe, t)
Tim Peters8d061ed2001-10-07 08:35:44 +0000286 self.cur = rpt, rit+t, ret, rfn, rframe, rcur
Guido van Rossumf137f752001-10-04 00:58:24 +0000287 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000288
289
Tim Peters2344fae2001-01-15 00:50:52 +0000290 def trace_dispatch_call(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000291 if self.cur and frame.f_back is not self.cur[-2]:
Tim Peters8d061ed2001-10-07 08:35:44 +0000292 rpt, rit, ret, rfn, rframe, rcur = self.cur
Guido van Rossumf137f752001-10-04 00:58:24 +0000293 if not isinstance(rframe, Profile.fake_frame):
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000294 assert rframe.f_back is frame.f_back, ("Bad call", rfn,
295 rframe, rframe.f_back,
296 frame, frame.f_back)
Guido van Rossumf137f752001-10-04 00:58:24 +0000297 self.trace_dispatch_return(rframe, 0)
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000298 assert (self.cur is None or \
299 frame.f_back is self.cur[-2]), ("Bad call",
300 self.cur[-3])
Tim Peters2344fae2001-01-15 00:50:52 +0000301 fcode = frame.f_code
302 fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
303 self.cur = (t, 0, 0, fn, frame, self.cur)
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000304 timings = self.timings
Raymond Hettinger54f02222002-06-01 14:18:47 +0000305 if fn in timings:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000306 cc, ns, tt, ct, callers = timings[fn]
307 timings[fn] = cc, ns + 1, tt, ct, callers
Tim Peters2344fae2001-01-15 00:50:52 +0000308 else:
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000309 timings[fn] = 0, 0, 0, 0, {}
Tim Peters2344fae2001-01-15 00:50:52 +0000310 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000311
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000312 def trace_dispatch_c_call (self, frame, t):
313 fn = ("", 0, self.c_func_name)
314 self.cur = (t, 0, 0, fn, frame, self.cur)
315 timings = self.timings
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000316 if fn in timings:
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000317 cc, ns, tt, ct, callers = timings[fn]
318 timings[fn] = cc, ns+1, tt, ct, callers
319 else:
320 timings[fn] = 0, 0, 0, 0, {}
321 return 1
322
Tim Peters2344fae2001-01-15 00:50:52 +0000323 def trace_dispatch_return(self, frame, t):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000324 if frame is not self.cur[-2]:
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000325 assert frame is self.cur[-2].f_back, ("Bad return", self.cur[-3])
326 self.trace_dispatch_return(self.cur[-2], 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000327
Tim Peters8d061ed2001-10-07 08:35:44 +0000328 # Prefix "r" means part of the Returning or exiting frame.
329 # Prefix "p" means part of the Previous or Parent or older frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000330
Tim Peters8d061ed2001-10-07 08:35:44 +0000331 rpt, rit, ret, rfn, frame, rcur = self.cur
332 rit = rit + t
333 frame_total = rit + ret
Guido van Rossumb6775db1994-08-01 11:34:53 +0000334
Tim Peters8d061ed2001-10-07 08:35:44 +0000335 ppt, pit, pet, pfn, pframe, pcur = rcur
336 self.cur = ppt, pit + rpt, pet + frame_total, pfn, pframe, pcur
Guido van Rossumb6775db1994-08-01 11:34:53 +0000337
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000338 timings = self.timings
339 cc, ns, tt, ct, callers = timings[rfn]
Tim Peters2344fae2001-01-15 00:50:52 +0000340 if not ns:
Tim Peters8d061ed2001-10-07 08:35:44 +0000341 # This is the only occurrence of the function on the stack.
342 # Else this is a (directly or indirectly) recursive call, and
343 # its cumulative time will get updated when the topmost call to
344 # it returns.
345 ct = ct + frame_total
Tim Peters2344fae2001-01-15 00:50:52 +0000346 cc = cc + 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000347
Raymond Hettinger54f02222002-06-01 14:18:47 +0000348 if pfn in callers:
Tim Peters2344fae2001-01-15 00:50:52 +0000349 callers[pfn] = callers[pfn] + 1 # hack: gather more
350 # stats such as the amount of time added to ct courtesy
351 # of this specific call, and the contribution to cc
352 # courtesy of this call.
353 else:
354 callers[pfn] = 1
Tim Peters8d061ed2001-10-07 08:35:44 +0000355
356 timings[rfn] = cc, ns - 1, tt + rit, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000357
Tim Peters2344fae2001-01-15 00:50:52 +0000358 return 1
Guido van Rossumb6775db1994-08-01 11:34:53 +0000359
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000360
361 dispatch = {
362 "call": trace_dispatch_call,
363 "exception": trace_dispatch_exception,
364 "return": trace_dispatch_return,
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000365 "c_call": trace_dispatch_c_call,
Armin Rigof8790242005-09-20 18:50:13 +0000366 "c_exception": trace_dispatch_return, # the C function returned
Nicholas Bastinc69ebe82004-03-24 21:57:10 +0000367 "c_return": trace_dispatch_return,
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000368 }
369
370
Tim Petersdb1ed2a2001-10-07 04:30:53 +0000371 # The next few functions play with self.cmd. By carefully preloading
Tim Peters2344fae2001-01-15 00:50:52 +0000372 # our parallel stack, we can force the profiled result to include
373 # an arbitrary string as the name of the calling function.
374 # We use self.cmd as that string, and the resulting stats look
375 # very nice :-).
Guido van Rossumb6775db1994-08-01 11:34:53 +0000376
Tim Peters2344fae2001-01-15 00:50:52 +0000377 def set_cmd(self, cmd):
Tim Petersdf5cfd82001-10-05 23:15:10 +0000378 if self.cur[-1]: return # already set
Tim Peters2344fae2001-01-15 00:50:52 +0000379 self.cmd = cmd
380 self.simulate_call(cmd)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000381
Tim Peters2344fae2001-01-15 00:50:52 +0000382 class fake_code:
383 def __init__(self, filename, line, name):
384 self.co_filename = filename
385 self.co_line = line
386 self.co_name = name
387 self.co_firstlineno = 0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000388
Tim Peters2344fae2001-01-15 00:50:52 +0000389 def __repr__(self):
390 return repr((self.co_filename, self.co_line, self.co_name))
Guido van Rossumb6775db1994-08-01 11:34:53 +0000391
Tim Peters2344fae2001-01-15 00:50:52 +0000392 class fake_frame:
393 def __init__(self, code, prior):
394 self.f_code = code
395 self.f_back = prior
Guido van Rossumb6775db1994-08-01 11:34:53 +0000396
Tim Peters2344fae2001-01-15 00:50:52 +0000397 def simulate_call(self, name):
398 code = self.fake_code('profile', 0, name)
399 if self.cur:
Tim Petersdf5cfd82001-10-05 23:15:10 +0000400 pframe = self.cur[-2]
Tim Peters2344fae2001-01-15 00:50:52 +0000401 else:
402 pframe = None
403 frame = self.fake_frame(code, pframe)
Fred Draked10ed8b2001-10-17 01:49:50 +0000404 self.dispatch['call'](self, frame, 0)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000405
Tim Peters2344fae2001-01-15 00:50:52 +0000406 # collect stats from pending stack, including getting final
407 # timings for self.cmd frame.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000408
Tim Peters2344fae2001-01-15 00:50:52 +0000409 def simulate_cmd_complete(self):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000410 get_time = self.get_time
411 t = get_time() - self.t
Tim Petersdf5cfd82001-10-05 23:15:10 +0000412 while self.cur[-1]:
Tim Peters2344fae2001-01-15 00:50:52 +0000413 # We *can* cause assertion errors here if
414 # dispatch_trace_return checks for a frame match!
Fred Draked10ed8b2001-10-17 01:49:50 +0000415 self.dispatch['return'](self, self.cur[-2], t)
Tim Peters2344fae2001-01-15 00:50:52 +0000416 t = 0
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000417 self.t = get_time() - t
Guido van Rossumb6775db1994-08-01 11:34:53 +0000418
419
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000420 def print_stats(self, sort=-1):
Tim Peters2344fae2001-01-15 00:50:52 +0000421 import pstats
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000422 pstats.Stats(self).strip_dirs().sort_stats(sort). \
Tim Peters2344fae2001-01-15 00:50:52 +0000423 print_stats()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000424
Tim Peters2344fae2001-01-15 00:50:52 +0000425 def dump_stats(self, file):
426 f = open(file, 'wb')
427 self.create_stats()
428 marshal.dump(self.stats, f)
429 f.close()
430
431 def create_stats(self):
432 self.simulate_cmd_complete()
433 self.snapshot_stats()
434
435 def snapshot_stats(self):
436 self.stats = {}
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000437 for func, (cc, ns, tt, ct, callers) in self.timings.items():
Tim Peters2344fae2001-01-15 00:50:52 +0000438 callers = callers.copy()
439 nc = 0
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000440 for callcnt in callers.values():
Raymond Hettingere0d49722002-06-02 18:55:56 +0000441 nc += callcnt
Tim Peters2344fae2001-01-15 00:50:52 +0000442 self.stats[func] = cc, nc, tt, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000443
444
Tim Peters2344fae2001-01-15 00:50:52 +0000445 # The following two methods can be called by clients to use
446 # a profiler to profile a statement, given as a string.
Guido van Rossumb6775db1994-08-01 11:34:53 +0000447
Tim Peters2344fae2001-01-15 00:50:52 +0000448 def run(self, cmd):
449 import __main__
450 dict = __main__.__dict__
451 return self.runctx(cmd, dict, dict)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000452
Tim Peters2344fae2001-01-15 00:50:52 +0000453 def runctx(self, cmd, globals, locals):
454 self.set_cmd(cmd)
455 sys.setprofile(self.dispatcher)
456 try:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000457 exec(cmd, globals, locals)
Tim Peters2344fae2001-01-15 00:50:52 +0000458 finally:
459 sys.setprofile(None)
460 return self
Guido van Rossumb6775db1994-08-01 11:34:53 +0000461
Tim Peters2344fae2001-01-15 00:50:52 +0000462 # This method is more useful to profile a single function call.
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000463 def runcall(self, func, *args, **kw):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000464 self.set_cmd(repr(func))
Tim Peters2344fae2001-01-15 00:50:52 +0000465 sys.setprofile(self.dispatcher)
466 try:
Guido van Rossum68468eb2003-02-27 20:14:51 +0000467 return func(*args, **kw)
Tim Peters2344fae2001-01-15 00:50:52 +0000468 finally:
469 sys.setprofile(None)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000470
Tim Peters2344fae2001-01-15 00:50:52 +0000471
472 #******************************************************************
473 # The following calculates the overhead for using a profiler. The
474 # problem is that it takes a fair amount of time for the profiler
475 # to stop the stopwatch (from the time it receives an event).
476 # Similarly, there is a delay from the time that the profiler
477 # re-starts the stopwatch before the user's code really gets to
478 # continue. The following code tries to measure the difference on
Tim Peters659a6032001-10-09 20:51:19 +0000479 # a per-event basis.
480 #
481 # Note that this difference is only significant if there are a lot of
Tim Peters2344fae2001-01-15 00:50:52 +0000482 # events, and relatively little user code per event. For example,
483 # code with small functions will typically benefit from having the
484 # profiler calibrated for the current platform. This *could* be
485 # done on the fly during init() time, but it is not worth the
486 # effort. Also note that if too large a value specified, then
487 # execution time on some functions will actually appear as a
488 # negative number. It is *normal* for some functions (with very
489 # low call counts) to have such negative stats, even if the
490 # calibration figure is "correct."
491 #
492 # One alternative to profile-time calibration adjustments (i.e.,
493 # adding in the magic little delta during each event) is to track
494 # more carefully the number of events (and cumulatively, the number
495 # of events during sub functions) that are seen. If this were
496 # done, then the arithmetic could be done after the fact (i.e., at
497 # display time). Currently, we track only call/return events.
498 # These values can be deduced by examining the callees and callers
499 # vectors for each functions. Hence we *can* almost correct the
500 # internal time figure at print time (note that we currently don't
501 # track exception event processing counts). Unfortunately, there
502 # is currently no similar information for cumulative sub-function
503 # time. It would not be hard to "get all this info" at profiler
504 # time. Specifically, we would have to extend the tuples to keep
505 # counts of this in each frame, and then extend the defs of timing
506 # tuples to include the significant two figures. I'm a bit fearful
507 # that this additional feature will slow the heavily optimized
508 # event/time ratio (i.e., the profiler would run slower, fur a very
509 # low "value added" feature.)
Tim Peters2344fae2001-01-15 00:50:52 +0000510 #**************************************************************
511
Tim Peterscce092d2001-10-09 05:31:56 +0000512 def calibrate(self, m, verbose=0):
Tim Peters659a6032001-10-09 20:51:19 +0000513 if self.__class__ is not Profile:
514 raise TypeError("Subclasses must override .calibrate().")
515
516 saved_bias = self.bias
517 self.bias = 0
518 try:
Tim Peterse13cc922001-10-09 21:01:31 +0000519 return self._calibrate_inner(m, verbose)
Tim Peters659a6032001-10-09 20:51:19 +0000520 finally:
521 self.bias = saved_bias
522
Tim Peterse13cc922001-10-09 21:01:31 +0000523 def _calibrate_inner(self, m, verbose):
Fred Drakeedb5ffb2001-06-08 04:25:24 +0000524 get_time = self.get_time
Tim Peters2344fae2001-01-15 00:50:52 +0000525
Tim Peterscce092d2001-10-09 05:31:56 +0000526 # Set up a test case to be run with and without profiling. Include
527 # lots of calls, because we're trying to quantify stopwatch overhead.
528 # Do not raise any exceptions, though, because we want to know
529 # exactly how many profile events are generated (one call event, +
530 # one return event, per Python-level call).
Tim Peters2344fae2001-01-15 00:50:52 +0000531
Tim Peterscce092d2001-10-09 05:31:56 +0000532 def f1(n):
533 for i in range(n):
534 x = 1
Tim Peters2344fae2001-01-15 00:50:52 +0000535
Tim Peterscce092d2001-10-09 05:31:56 +0000536 def f(m, f1=f1):
537 for i in range(m):
538 f1(100)
Tim Peters2344fae2001-01-15 00:50:52 +0000539
Tim Peterscce092d2001-10-09 05:31:56 +0000540 f(m) # warm up the cache
541
542 # elapsed_noprofile <- time f(m) takes without profiling.
543 t0 = get_time()
544 f(m)
545 t1 = get_time()
546 elapsed_noprofile = t1 - t0
547 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000548 print("elapsed time without profiling =", elapsed_noprofile)
Tim Peterscce092d2001-10-09 05:31:56 +0000549
550 # elapsed_profile <- time f(m) takes with profiling. The difference
551 # is profiling overhead, only some of which the profiler subtracts
552 # out on its own.
553 p = Profile()
554 t0 = get_time()
555 p.runctx('f(m)', globals(), locals())
556 t1 = get_time()
557 elapsed_profile = t1 - t0
558 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000559 print("elapsed time with profiling =", elapsed_profile)
Tim Peterscce092d2001-10-09 05:31:56 +0000560
561 # reported_time <- "CPU seconds" the profiler charged to f and f1.
562 total_calls = 0.0
563 reported_time = 0.0
564 for (filename, line, funcname), (cc, ns, tt, ct, callers) in \
565 p.timings.items():
566 if funcname in ("f", "f1"):
567 total_calls += cc
568 reported_time += tt
569
570 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000571 print("'CPU seconds' profiler reported =", reported_time)
572 print("total # calls =", total_calls)
Tim Peterscce092d2001-10-09 05:31:56 +0000573 if total_calls != m + 1:
574 raise ValueError("internal error: total calls = %d" % total_calls)
575
576 # reported_time - elapsed_noprofile = overhead the profiler wasn't
577 # able to measure. Divide by twice the number of calls (since there
578 # are two profiler events per call in this test) to get the hidden
579 # overhead per event.
580 mean = (reported_time - elapsed_noprofile) / 2.0 / total_calls
581 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000582 print("mean stopwatch overhead per profile event =", mean)
Tim Peterscce092d2001-10-09 05:31:56 +0000583 return mean
Guido van Rossumb6775db1994-08-01 11:34:53 +0000584
Guido van Rossumb6775db1994-08-01 11:34:53 +0000585#****************************************************************************
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000586
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000587def main():
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000588 usage = "profile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000589 parser = OptionParser(usage=usage)
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000590 parser.allow_interspersed_args = False
Tim Peters4e0e1b62004-07-07 20:54:48 +0000591 parser.add_option('-o', '--outfile', dest="outfile",
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000592 help="Save stats to <outfile>", default=None)
593 parser.add_option('-s', '--sort', dest="sort",
594 help="Sort order when printing to stdout, based on pstats.Stats class", default=-1)
Tim Petersb497c102005-01-10 16:48:37 +0000595
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000596 if not sys.argv[1:]:
597 parser.print_usage()
598 sys.exit(2)
Tim Petersb497c102005-01-10 16:48:37 +0000599
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000600 (options, args) = parser.parse_args()
601 sys.argv[:] = args
Tim Petersb497c102005-01-10 16:48:37 +0000602
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000603 if (len(sys.argv) > 0):
604 sys.path.insert(0, os.path.dirname(sys.argv[0]))
Neal Norwitz01688022007-08-12 00:43:29 +0000605 fp = open(sys.argv[0])
606 try:
607 script = fp.read()
608 finally:
609 fp.close()
610 run('exec(%r)' % script, options.outfile, options.sort)
Nicholas Bastin824b1b22004-03-23 18:44:39 +0000611 else:
Johannes Gijsbers2abe7852005-01-09 01:58:02 +0000612 parser.print_usage()
613 return parser
614
615# When invoked as main program, invoke the profiler on a script
616if __name__ == '__main__':
617 main()