blob: c1f8f5bc3adced67d064a1023fb09b71748375cd [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
10
11# Copyright 1994, by InfoSeek Corporation, all rights reserved.
12# Written by James Roskind
13#
14# Permission to use, copy, modify, and distribute this Python software
15# and its associated documentation for any purpose (subject to the
16# restriction in the following sentence) without fee is hereby granted,
17# provided that the above copyright notice appears in all copies, and
18# that both that copyright notice and this permission notice appear in
19# supporting documentation, and that the name of InfoSeek not be used in
20# advertising or publicity pertaining to distribution of the software
21# without specific, written prior permission. This permission is
22# explicitly restricted to the copying and modification of the software
23# to remain in Python, compiled Python, or other languages (such as C)
24# wherein the modified or derived code is exclusively imported into a
25# Python module.
26#
27# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
28# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
29# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
30# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
31# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
32# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
33# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34
35
Guido van Rossum81762581992-04-21 15:36:23 +000036
37import sys
Guido van Rossum4e160981992-09-02 20:43:20 +000038import os
Guido van Rossumb6775db1994-08-01 11:34:53 +000039import time
Guido van Rossum4e160981992-09-02 20:43:20 +000040import marshal
Guido van Rossum81762581992-04-21 15:36:23 +000041
Guido van Rossum81762581992-04-21 15:36:23 +000042
Guido van Rossumb6775db1994-08-01 11:34:53 +000043# Sample timer for use with
44#i_count = 0
45#def integer_timer():
46# global i_count
47# i_count = i_count + 1
48# return i_count
49#itimes = integer_timer # replace with C coded timer returning integers
Guido van Rossum81762581992-04-21 15:36:23 +000050
Guido van Rossumb6775db1994-08-01 11:34:53 +000051#**************************************************************************
52# The following are the static member functions for the profiler class
53# Note that an instance of Profile() is *not* needed to call them.
54#**************************************************************************
Guido van Rossum81762581992-04-21 15:36:23 +000055
Guido van Rossum4e160981992-09-02 20:43:20 +000056
57# simplified user interface
58def run(statement, *args):
Guido van Rossum7bc817d1993-12-17 15:25:27 +000059 prof = Profile()
Guido van Rossum4e160981992-09-02 20:43:20 +000060 try:
Guido van Rossumb6775db1994-08-01 11:34:53 +000061 prof = prof.run(statement)
Guido van Rossum4e160981992-09-02 20:43:20 +000062 except SystemExit:
63 pass
Guido van Rossumb6775db1994-08-01 11:34:53 +000064 if args:
Guido van Rossum4e160981992-09-02 20:43:20 +000065 prof.dump_stats(args[0])
Guido van Rossumb6775db1994-08-01 11:34:53 +000066 else:
67 return prof.print_stats()
Guido van Rossume61fa0a1993-10-22 13:56:35 +000068
69# print help
70def help():
71 for dirname in sys.path:
72 fullname = os.path.join(dirname, 'profile.doc')
73 if os.path.exists(fullname):
74 sts = os.system('${PAGER-more} '+fullname)
75 if sts: print '*** Pager exit status:', sts
76 break
77 else:
78 print 'Sorry, can\'t find the help file "profile.doc"',
79 print 'along the Python search path'
Guido van Rossumb6775db1994-08-01 11:34:53 +000080
81
82#**************************************************************************
83# class Profile documentation:
84#**************************************************************************
85# self.cur is always a tuple. Each such tuple corresponds to a stack
86# frame that is currently active (self.cur[-2]). The following are the
87# definitions of its members. We use this external "parallel stack" to
88# avoid contaminating the program that we are profiling. (old profiler
89# used to write into the frames local dictionary!!) Derived classes
90# can change the definition of some entries, as long as they leave
91# [-2:] intact.
92#
93# [ 0] = Time that needs to be charged to the parent frame's function. It is
94# used so that a function call will not have to access the timing data
95# for the parents frame.
96# [ 1] = Total time spent in this frame's function, excluding time in
97# subfunctions
98# [ 2] = Cumulative time spent in this frame's function, including time in
99# all subfunctions to this frame.
100# [-3] = Name of the function that corresonds to this frame.
101# [-2] = Actual frame that we correspond to (used to sync exception handling)
102# [-1] = Our parent 6-tuple (corresonds to frame.f_back)
103#**************************************************************************
104# Timing data for each function is stored as a 5-tuple in the dictionary
105# self.timings[]. The index is always the name stored in self.cur[4].
106# The following are the definitions of the members:
107#
108# [0] = The number of times this function was called, not counting direct
109# or indirect recursion,
110# [1] = Number of times this function appears on the stack, minus one
111# [2] = Total time spent internal to this function
112# [3] = Cumulative time that this function was present on the stack. In
113# non-recursive functions, this is the total execution time from start
114# to finish of each invocation of a function, including time spent in
115# all subfunctions.
116# [5] = A dictionary indicating for each function name, the number of times
117# it was called by us.
118#**************************************************************************
Guido van Rossumb6775db1994-08-01 11:34:53 +0000119class Profile:
120
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000121 def __init__(self, timer=None):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000122 self.timings = {}
123 self.cur = None
124 self.cmd = ""
125
126 self.dispatch = { \
127 'call' : self.trace_dispatch_call, \
128 'return' : self.trace_dispatch_return, \
129 'exception': self.trace_dispatch_exception, \
130 }
131
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000132 if not timer:
Guido van Rossum96c07fe1998-03-17 14:46:43 +0000133 if os.name == 'mac':
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000134 import MacOS
135 self.timer = MacOS.GetTicks
136 self.dispatcher = self.trace_dispatch_mac
137 self.get_time = self.get_time_mac
Guido van Rossum96c07fe1998-03-17 14:46:43 +0000138 elif hasattr(time, 'clock'):
139 self.timer = time.clock
140 self.dispatcher = self.trace_dispatch_i
141 elif hasattr(os, 'times'):
142 self.timer = os.times
143 self.dispatcher = self.trace_dispatch
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000144 else:
145 self.timer = time.time
146 self.dispatcher = self.trace_dispatch_i
Guido van Rossumb6775db1994-08-01 11:34:53 +0000147 else:
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000148 self.timer = timer
Guido van Rossumb6775db1994-08-01 11:34:53 +0000149 t = self.timer() # test out timer function
150 try:
151 if len(t) == 2:
152 self.dispatcher = self.trace_dispatch
153 else:
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000154 self.dispatcher = self.trace_dispatch_l
155 except TypeError:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000156 self.dispatcher = self.trace_dispatch_i
157 self.t = self.get_time()
158 self.simulate_call('profiler')
159
160
161 def get_time(self): # slow simulation of method to acquire time
162 t = self.timer()
163 if type(t) == type(()) or type(t) == type([]):
164 t = reduce(lambda x,y: x+y, t, 0)
165 return t
166
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000167 def get_time_mac(self):
168 return self.timer()/60.0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000169
170 # Heavily optimized dispatch routine for os.times() timer
171
172 def trace_dispatch(self, frame, event, arg):
173 t = self.timer()
174 t = t[0] + t[1] - self.t # No Calibration constant
175 # t = t[0] + t[1] - self.t - .00053 # Calibration constant
176
177 if self.dispatch[event](frame,t):
178 t = self.timer()
179 self.t = t[0] + t[1]
180 else:
181 r = self.timer()
182 self.t = r[0] + r[1] - t # put back unrecorded delta
183 return
184
185
186
187 # Dispatch routine for best timer program (return = scalar integer)
188
189 def trace_dispatch_i(self, frame, event, arg):
190 t = self.timer() - self.t # - 1 # Integer calibration constant
191 if self.dispatch[event](frame,t):
192 self.t = self.timer()
193 else:
194 self.t = self.timer() - t # put back unrecorded delta
195 return
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000196
197 # Dispatch routine for macintosh (timer returns time in ticks of 1/60th second)
198
199 def trace_dispatch_mac(self, frame, event, arg):
200 t = self.timer()/60.0 - self.t # - 1 # Integer calibration constant
201 if self.dispatch[event](frame,t):
202 self.t = self.timer()/60.0
203 else:
204 self.t = self.timer()/60.0 - t # put back unrecorded delta
205 return
Guido van Rossumb6775db1994-08-01 11:34:53 +0000206
207
208 # SLOW generic dispatch rountine for timer returning lists of numbers
209
210 def trace_dispatch_l(self, frame, event, arg):
211 t = self.get_time() - self.t
212
213 if self.dispatch[event](frame,t):
214 self.t = self.get_time()
215 else:
216 self.t = self.get_time()-t # put back unrecorded delta
217 return
218
219
220 def trace_dispatch_exception(self, frame, t):
221 rt, rtt, rct, rfn, rframe, rcur = self.cur
222 if (not rframe is frame) and rcur:
223 return self.trace_dispatch_return(rframe, t)
224 return 0
225
226
227 def trace_dispatch_call(self, frame, t):
Guido van Rossumb0a94c01998-09-21 16:52:44 +0000228 fcode = frame.f_code
229 fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000230 self.cur = (t, 0, 0, fn, frame, self.cur)
231 if self.timings.has_key(fn):
232 cc, ns, tt, ct, callers = self.timings[fn]
233 self.timings[fn] = cc, ns + 1, tt, ct, callers
234 else:
235 self.timings[fn] = 0, 0, 0, 0, {}
236 return 1
237
238 def trace_dispatch_return(self, frame, t):
239 # if not frame is self.cur[-2]: raise "Bad return", self.cur[3]
240
241 # Prefix "r" means part of the Returning or exiting frame
242 # Prefix "p" means part of the Previous or older frame
243
244 rt, rtt, rct, rfn, frame, rcur = self.cur
245 rtt = rtt + t
246 sft = rtt + rct
247
248 pt, ptt, pct, pfn, pframe, pcur = rcur
249 self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
250
251 cc, ns, tt, ct, callers = self.timings[rfn]
252 if not ns:
253 ct = ct + sft
254 cc = cc + 1
255 if callers.has_key(pfn):
256 callers[pfn] = callers[pfn] + 1 # hack: gather more
257 # stats such as the amount of time added to ct courtesy
258 # of this specific call, and the contribution to cc
259 # courtesy of this call.
260 else:
261 callers[pfn] = 1
262 self.timings[rfn] = cc, ns - 1, tt+rtt, ct, callers
263
264 return 1
265
266 # The next few function play with self.cmd. By carefully preloading
Guido van Rossum138bdaf1999-05-03 18:13:29 +0000267 # our parallel stack, we can force the profiled result to include
Guido van Rossumb6775db1994-08-01 11:34:53 +0000268 # an arbitrary string as the name of the calling function.
269 # We use self.cmd as that string, and the resulting stats look
270 # very nice :-).
271
272 def set_cmd(self, cmd):
273 if self.cur[-1]: return # already set
274 self.cmd = cmd
275 self.simulate_call(cmd)
276
277 class fake_code:
278 def __init__(self, filename, line, name):
279 self.co_filename = filename
280 self.co_line = line
281 self.co_name = name
Guido van Rossumb0a94c01998-09-21 16:52:44 +0000282 self.co_firstlineno = 0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000283
284 def __repr__(self):
Guido van Rossumb0a94c01998-09-21 16:52:44 +0000285 return repr((self.co_filename, self.co_line, self.co_name))
Guido van Rossumb6775db1994-08-01 11:34:53 +0000286
287 class fake_frame:
288 def __init__(self, code, prior):
289 self.f_code = code
290 self.f_back = prior
291
292 def simulate_call(self, name):
293 code = self.fake_code('profile', 0, name)
294 if self.cur:
295 pframe = self.cur[-2]
296 else:
297 pframe = None
298 frame = self.fake_frame(code, pframe)
299 a = self.dispatch['call'](frame, 0)
300 return
301
302 # collect stats from pending stack, including getting final
303 # timings for self.cmd frame.
304
305 def simulate_cmd_complete(self):
306 t = self.get_time() - self.t
307 while self.cur[-1]:
308 # We *can* cause assertion errors here if
309 # dispatch_trace_return checks for a frame match!
310 a = self.dispatch['return'](self.cur[-2], t)
311 t = 0
312 self.t = self.get_time() - t
313
314
315 def print_stats(self):
316 import pstats
317 pstats.Stats(self).strip_dirs().sort_stats(-1). \
318 print_stats()
319
320 def dump_stats(self, file):
Guido van Rossumcbf3dd51997-10-08 15:23:02 +0000321 f = open(file, 'wb')
Guido van Rossumb6775db1994-08-01 11:34:53 +0000322 self.create_stats()
323 marshal.dump(self.stats, f)
324 f.close()
325
326 def create_stats(self):
327 self.simulate_cmd_complete()
328 self.snapshot_stats()
329
330 def snapshot_stats(self):
331 self.stats = {}
332 for func in self.timings.keys():
333 cc, ns, tt, ct, callers = self.timings[func]
Guido van Rossum4ecd85a1998-09-21 17:40:47 +0000334 callers = callers.copy()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000335 nc = 0
336 for func_caller in callers.keys():
Guido van Rossumb6775db1994-08-01 11:34:53 +0000337 nc = nc + callers[func_caller]
Guido van Rossum4ecd85a1998-09-21 17:40:47 +0000338 self.stats[func] = cc, nc, tt, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000339
340
341 # The following two methods can be called by clients to use
342 # a profiler to profile a statement, given as a string.
343
344 def run(self, cmd):
345 import __main__
346 dict = __main__.__dict__
Guido van Rossum6cb84f31996-05-28 23:00:42 +0000347 return self.runctx(cmd, dict, dict)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000348
349 def runctx(self, cmd, globals, locals):
350 self.set_cmd(cmd)
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000351 sys.setprofile(self.dispatcher)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000352 try:
Guido van Rossum9c3241d1995-08-10 19:46:50 +0000353 exec cmd in globals, locals
Guido van Rossumb6775db1994-08-01 11:34:53 +0000354 finally:
355 sys.setprofile(None)
Guido van Rossum6cb84f31996-05-28 23:00:42 +0000356 return self
Guido van Rossumb6775db1994-08-01 11:34:53 +0000357
358 # This method is more useful to profile a single function call.
359 def runcall(self, func, *args):
Guido van Rossum8afa8241995-06-22 18:52:35 +0000360 self.set_cmd(`func`)
Guido van Rossum4f399fb1995-09-30 16:48:54 +0000361 sys.setprofile(self.dispatcher)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000362 try:
Guido van Rossum6cb84f31996-05-28 23:00:42 +0000363 return apply(func, args)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000364 finally:
365 sys.setprofile(None)
Guido van Rossumb6775db1994-08-01 11:34:53 +0000366
367
Guido van Rossum8ca84201998-03-26 20:56:10 +0000368 #******************************************************************
Guido van Rossumb6775db1994-08-01 11:34:53 +0000369 # The following calculates the overhead for using a profiler. The
370 # problem is that it takes a fair amount of time for the profiler
371 # to stop the stopwatch (from the time it recieves an event).
372 # Similarly, there is a delay from the time that the profiler
373 # re-starts the stopwatch before the user's code really gets to
374 # continue. The following code tries to measure the difference on
375 # a per-event basis. The result can the be placed in the
376 # Profile.dispatch_event() routine for the given platform. Note
377 # that this difference is only significant if there are a lot of
378 # events, and relatively little user code per event. For example,
379 # code with small functions will typically benefit from having the
380 # profiler calibrated for the current platform. This *could* be
381 # done on the fly during init() time, but it is not worth the
382 # effort. Also note that if too large a value specified, then
383 # execution time on some functions will actually appear as a
384 # negative number. It is *normal* for some functions (with very
385 # low call counts) to have such negative stats, even if the
386 # calibration figure is "correct."
387 #
388 # One alternative to profile-time calibration adjustments (i.e.,
389 # adding in the magic little delta during each event) is to track
390 # more carefully the number of events (and cumulatively, the number
391 # of events during sub functions) that are seen. If this were
392 # done, then the arithmetic could be done after the fact (i.e., at
393 # display time). Currintly, we track only call/return events.
394 # These values can be deduced by examining the callees and callers
395 # vectors for each functions. Hence we *can* almost correct the
396 # internal time figure at print time (note that we currently don't
397 # track exception event processing counts). Unfortunately, there
398 # is currently no similar information for cumulative sub-function
399 # time. It would not be hard to "get all this info" at profiler
400 # time. Specifically, we would have to extend the tuples to keep
401 # counts of this in each frame, and then extend the defs of timing
402 # tuples to include the significant two figures. I'm a bit fearful
403 # that this additional feature will slow the heavily optimized
404 # event/time ratio (i.e., the profiler would run slower, fur a very
405 # low "value added" feature.)
406 #
407 # Plugging in the calibration constant doesn't slow down the
408 # profiler very much, and the accuracy goes way up.
409 #**************************************************************
410
Guido van Rossum8ca84201998-03-26 20:56:10 +0000411 def calibrate(self, m):
412 # Modified by Tim Peters
Guido van Rossumb6775db1994-08-01 11:34:53 +0000413 n = m
Guido van Rossum8ca84201998-03-26 20:56:10 +0000414 s = self.get_time()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000415 while n:
416 self.simple()
417 n = n - 1
Guido van Rossum8ca84201998-03-26 20:56:10 +0000418 f = self.get_time()
419 my_simple = f - s
Guido van Rossumb6775db1994-08-01 11:34:53 +0000420 #print "Simple =", my_simple,
421
422 n = m
Guido van Rossum8ca84201998-03-26 20:56:10 +0000423 s = self.get_time()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000424 while n:
425 self.instrumented()
426 n = n - 1
Guido van Rossum8ca84201998-03-26 20:56:10 +0000427 f = self.get_time()
428 my_inst = f - s
Guido van Rossumb6775db1994-08-01 11:34:53 +0000429 # print "Instrumented =", my_inst
430 avg_cost = (my_inst - my_simple)/m
431 #print "Delta/call =", avg_cost, "(profiler fixup constant)"
432 return avg_cost
433
434 # simulate a program with no profiler activity
Guido van Rossum8ca84201998-03-26 20:56:10 +0000435 def simple(self):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000436 a = 1
437 pass
438
439 # simulate a program with call/return event processing
Guido van Rossum8ca84201998-03-26 20:56:10 +0000440 def instrumented(self):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000441 a = 1
442 self.profiler_simulation(a, a, a)
443
444 # simulate an event processing activity (from user's perspective)
445 def profiler_simulation(self, x, y, z):
446 t = self.timer()
Guido van Rossume3f8a641998-09-21 14:52:22 +0000447 ## t = t[0] + t[1]
Guido van Rossumb6775db1994-08-01 11:34:53 +0000448 self.ut = t
449
450
451
452#****************************************************************************
453# OldProfile class documentation
454#****************************************************************************
455#
456# The following derived profiler simulates the old style profile, providing
457# errant results on recursive functions. The reason for the usefulnes of this
458# profiler is that it runs faster (i.e., less overhead). It still creates
459# all the caller stats, and is quite useful when there is *no* recursion
460# in the user's code.
461#
462# This code also shows how easy it is to create a modified profiler.
463#****************************************************************************
464class OldProfile(Profile):
465 def trace_dispatch_exception(self, frame, t):
466 rt, rtt, rct, rfn, rframe, rcur = self.cur
467 if rcur and not rframe is frame:
468 return self.trace_dispatch_return(rframe, t)
469 return 0
470
471 def trace_dispatch_call(self, frame, t):
472 fn = `frame.f_code`
473
474 self.cur = (t, 0, 0, fn, frame, self.cur)
475 if self.timings.has_key(fn):
476 tt, ct, callers = self.timings[fn]
477 self.timings[fn] = tt, ct, callers
478 else:
479 self.timings[fn] = 0, 0, {}
480 return 1
481
482 def trace_dispatch_return(self, frame, t):
483 rt, rtt, rct, rfn, frame, rcur = self.cur
484 rtt = rtt + t
485 sft = rtt + rct
486
487 pt, ptt, pct, pfn, pframe, pcur = rcur
488 self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
489
490 tt, ct, callers = self.timings[rfn]
491 if callers.has_key(pfn):
492 callers[pfn] = callers[pfn] + 1
493 else:
494 callers[pfn] = 1
495 self.timings[rfn] = tt+rtt, ct + sft, callers
496
497 return 1
498
499
500 def snapshot_stats(self):
501 self.stats = {}
502 for func in self.timings.keys():
503 tt, ct, callers = self.timings[func]
Guido van Rossum4ecd85a1998-09-21 17:40:47 +0000504 callers = callers.copy()
Guido van Rossumb6775db1994-08-01 11:34:53 +0000505 nc = 0
506 for func_caller in callers.keys():
Guido van Rossumb6775db1994-08-01 11:34:53 +0000507 nc = nc + callers[func_caller]
Guido van Rossum4ecd85a1998-09-21 17:40:47 +0000508 self.stats[func] = nc, nc, tt, ct, callers
Guido van Rossumb6775db1994-08-01 11:34:53 +0000509
510
511
512#****************************************************************************
513# HotProfile class documentation
514#****************************************************************************
515#
516# This profiler is the fastest derived profile example. It does not
517# calculate caller-callee relationships, and does not calculate cumulative
518# time under a function. It only calculates time spent in a function, so
519# it runs very quickly (re: very low overhead)
520#****************************************************************************
521class HotProfile(Profile):
522 def trace_dispatch_exception(self, frame, t):
523 rt, rtt, rfn, rframe, rcur = self.cur
524 if rcur and not rframe is frame:
525 return self.trace_dispatch_return(rframe, t)
526 return 0
527
528 def trace_dispatch_call(self, frame, t):
529 self.cur = (t, 0, frame, self.cur)
530 return 1
531
532 def trace_dispatch_return(self, frame, t):
533 rt, rtt, frame, rcur = self.cur
534
535 rfn = `frame.f_code`
536
537 pt, ptt, pframe, pcur = rcur
538 self.cur = pt, ptt+rt, pframe, pcur
539
540 if self.timings.has_key(rfn):
541 nc, tt = self.timings[rfn]
542 self.timings[rfn] = nc + 1, rt + rtt + tt
543 else:
544 self.timings[rfn] = 1, rt + rtt
545
546 return 1
547
548
549 def snapshot_stats(self):
550 self.stats = {}
551 for func in self.timings.keys():
552 nc, tt = self.timings[func]
Guido van Rossum4ecd85a1998-09-21 17:40:47 +0000553 self.stats[func] = nc, nc, tt, 0, {}
Guido van Rossumb6775db1994-08-01 11:34:53 +0000554
555
556
557#****************************************************************************
558def Stats(*args):
559 print 'Report generating functions are in the "pstats" module\a'
Guido van Rossumcc778eb1996-10-01 02:55:54 +0000560
561
562# When invoked as main program, invoke the profiler on a script
563if __name__ == '__main__':
564 import sys
565 import os
566 if not sys.argv[1:]:
567 print "usage: profile.py scriptfile [arg] ..."
568 sys.exit(2)
569
570 filename = sys.argv[1] # Get script filename
571
572 del sys.argv[0] # Hide "profile.py" from argument list
573
574 # Insert script directory in front of module search path
575 sys.path.insert(0, os.path.dirname(filename))
576
577 run('execfile(' + `filename` + ')')