summaryrefslogtreecommitdiffstats
path: root/Lib/profile.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1992-09-02 20:43:20 (GMT)
committerGuido van Rossum <guido@python.org>1992-09-02 20:43:20 (GMT)
commit4e16098ce74c645cf1d69566b6f8bc96031554b7 (patch)
tree919ce6e774608fbf5a2e4745472e9fbc445139e9 /Lib/profile.py
parent2179945eec5ab32b4aa88b9f7a9308a898cde8a5 (diff)
downloadcpython-4e16098ce74c645cf1d69566b6f8bc96031554b7.zip
cpython-4e16098ce74c645cf1d69566b6f8bc96031554b7.tar.gz
cpython-4e16098ce74c645cf1d69566b6f8bc96031554b7.tar.bz2
Added a _v21 def to FL.py and added two new input field types
Added runcall(func, *args) interfaces to profile.py, bdb.py, pdb.py, wdb.py Added new module bisect.py and used it in sched.py. Mostly cosmetic changes to profile.py (changed output format).
Diffstat (limited to 'Lib/profile.py')
-rwxr-xr-xLib/profile.py233
1 files changed, 95 insertions, 138 deletions
diff --git a/Lib/profile.py b/Lib/profile.py
index 1c7a6e2..046b70b 100755
--- a/Lib/profile.py
+++ b/Lib/profile.py
@@ -1,12 +1,16 @@
#
# Class for profiling python code.
# Author: Sjoerd Mullender
+# Hacked somewhat by: Guido van Rossum
#
# See the accompanying document profile.doc for more information.
import sys
import codehack
-import posix
+import os
+import string
+import fpformat
+import marshal
class Profile():
@@ -30,7 +34,7 @@ class Profile():
if self.profile_func.has_key(funcname):
return
self.profiling = 1
- t = posix.times()
+ t = os.times()
t = t[0] + t[1]
lineno = codehack.getlineno(frame.f_code)
filename = frame.f_code.co_filename
@@ -42,13 +46,16 @@ class Profile():
s0 = 'call: ' + key + ' depth: ' + `self.call_level` + ' time: ' + `t`
if pframe:
pkey = pframe.f_code.co_filename + ':' + \
- `codehack.getlineno(pframe.f_code)` + '(' + \
- codehack.getcodename(pframe.f_code) + ')'
+ `codehack.getlineno(pframe.f_code)` \
+ + '(' + \
+ codehack.getcodename(pframe.f_code) \
+ + ')'
if self.debug:
s1 = 'parent: ' + pkey
if pframe.f_locals.has_key('__start_time'):
st = pframe.f_locals['__start_time']
- nc, tt, ct, callers, callees = self.timings[pkey]
+ nc, tt, ct, callers, callees = \
+ self.timings[pkey]
if self.debug:
s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct`
if callers.has_key(key):
@@ -80,7 +87,8 @@ class Profile():
if self.profile_func:
if not self.profiling:
return
- if self.profile_func.has_key(codehack.getcodename(frame.f_code)):
+ if self.profile_func.has_key( \
+ codehack.getcodename(frame.f_code)):
self.profiling = 0
self.call_level = depth(frame)
self.cur_frame = frame
@@ -106,11 +114,12 @@ class Profile():
self.call_level = call_level
self.cur_frame = frame
return
- print 'profile.Profile.dispatch: unknown debugging event:', `event`
+ print 'profile.Profile.dispatch: unknown debugging event:',
+ print `event`
return
def handle_return(self, pframe, frame, s0):
- t = posix.times()
+ t = os.times()
t = t[0] + t[1]
funcname = codehack.getcodename(frame.f_code)
lineno = codehack.getlineno(frame.f_code)
@@ -128,11 +137,13 @@ class Profile():
if pframe.f_locals.has_key('__start_time') and \
self.timings.has_key(pkey):
st = pframe.f_locals['__start_time']
- nc, tt, ct, callers, callees = self.timings[pkey]
+ nc, tt, ct, callers, callees = \
+ self.timings[pkey]
if self.debug:
s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct`
s1 = s1+' after: st='+`t`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct+(t-st)`
- self.timings[pkey] = nc, tt, ct + (t - st), callers, callees
+ self.timings[pkey] = \
+ nc, tt, ct + (t - st), callers, callees
pframe.f_locals['__start_time'] = t
if self.timings.has_key(key):
nc, tt, ct, callers, callees = self.timings[key]
@@ -147,35 +158,30 @@ class Profile():
s0 = s0+' after: nc='+`nc`+' tt='+`tt+(t-st)`+' ct='+`ct+(t-st)`
print s0
print s1
- self.timings[key] = nc, tt + (t - st), ct + (t - st), callers, callees
+ self.timings[key] = \
+ nc, tt + (t - st), ct + (t - st), callers, callees
def print_stats(self):
- import string
- s = string.rjust('# calls', 8)
- s = s + ' ' + string.rjust('tot time', 8)
- s = s + ' ' + string.rjust('per call', 8)
- s = s + ' ' + string.rjust('cum time', 8)
- s = s + ' ' + string.rjust('per call', 8)
- print s + ' filename(function)'
+ # Print in reverse order by ct
+ print_title()
+ list = []
for key in self.timings.keys():
nc, tt, ct, callers, callees = self.timings[key]
if nc == 0:
continue
- s = string.rjust(`nc`, 8)
- s = s + ' ' + string.rjust(`tt`, 8)
- s = s + ' ' + string.rjust(`tt/nc`, 8)
- s = s + ' ' + string.rjust(`ct`, 8)
- s = s + ' ' + string.rjust(`ct/nc`, 8)
- print s + ' ' + key
+ list.append(ct, tt, nc, key)
+ list.sort()
+ list.reverse()
+ for ct, tt, nc, key in list:
+ print_line(nc, tt, ct, os.path.basename(key))
def dump_stats(self, file):
- import marshal
f = open(file, 'w')
marshal.dump(self.timings, f)
f.close()
- # The following two functions can be called by clients to use
- # a debugger to debug a statement, given as a string.
+ # The following two methods can be called by clients to use
+ # a profiler to profile a statement, given as a string.
def run(self, cmd):
import __main__
@@ -183,17 +189,21 @@ class Profile():
self.runctx(cmd, dict, dict)
def runctx(self, cmd, globals, locals):
-## self.reset()
sys.setprofile(self.trace_dispatch)
try:
-## try:
- exec(cmd + '\n', globals, locals)
-## except ProfQuit:
-## pass
+ exec(cmd + '\n', globals, locals)
finally:
-## self.quitting = 1
sys.setprofile(None)
- # XXX What to do if the command finishes normally?
+
+ # This method is more useful to profile a single function call.
+
+ def runcall(self, func, *args):
+ sys.setprofile(self.trace_dispatch)
+ try:
+ apply(func, args)
+ finally:
+ sys.setprofile(None)
+
def depth(frame):
d = 0
@@ -202,98 +212,8 @@ def depth(frame):
frame = frame.f_back
return d
-def run(statement, *args):
- prof = Profile().init()
- try:
- prof.run(statement)
- except SystemExit:
- pass
- if len(args) == 0:
- prof.print_stats()
- else:
- prof.dump_stats(args[0])
-
-def cv_float(val, width):
- import string
- s = `val`
- try:
- e = string.index(s, 'e')
- exp = s[e+1:]
- s = s[:e]
- width = width - len(exp) - 1
- except string.index_error:
- exp = ''
- try:
- d = string.index(s, '.')
- frac = s[d+1:]
- s = s[:d]
- width = width - len(s) - 1
- except string.index_error:
- if exp <> '':
- return s + 'e' + exp
- else:
- return s
- if width < 0:
- width = 0
- while width < len(frac):
- c = frac[width]
- frac = frac[:width]
- if ord(c) >= ord('5'):
- carry = 1
- for i in range(width-1, -1, -1):
- if frac[i] == '9':
- frac = frac[:i]
- # keep if trailing zeroes are wanted
- # + '0' + frac[i+1:width]
- else:
- frac = frac[:i] + chr(ord(frac[i])+1) + frac[i+1:width]
- carry = 0
- break
- if carry:
- for i in range(len(s)-1, -1, -1):
- if s[i] == '9':
- s = s[:i] + '0' + s[i+1:]
- if i == 0:
- # gets one wider, so
- # should shorten
- # fraction by one
- s = '1' + s
- if width > 0:
- width = width - 1
- else:
- s = s[:i] + chr(ord(s[i])+1) + s[i+1:]
- break
- # delete trailing zeroes
- for i in range(len(frac)-1, -1, -1):
- if frac[i] == '0':
- frac = frac[:i]
- else:
- break
- # build up the number
- if width > 0 and len(frac) > 0:
- s = s + '.' + frac[:width]
- if exp <> '':
- s = s + 'e' + exp
- return s
-
-def print_line(nc, tt, ct, callers, callees, key):
- import string
- s = string.rjust(cv_float(nc,8), 8)
- s = s + ' ' + string.rjust(cv_float(tt,8), 8)
- if nc == 0:
- s = s + ' '*9
- else:
- s = s + ' ' + string.rjust(cv_float(tt/nc,8), 8)
- s = s + ' ' + string.rjust(cv_float(ct,8), 8)
- if nc == 0:
- s = s + ' '*9
- else:
- s = s + ' ' + string.rjust(cv_float(ct/nc,8), 8)
- print s + ' ' + key
-
class Stats():
def init(self, file):
- import marshal
f = open(file, 'r')
self.stats = marshal.load(f)
f.close()
@@ -301,26 +221,22 @@ class Stats():
return self
def print_stats(self):
- import string
- s = string.rjust('# calls', 8)
- s = s + ' ' + string.rjust('tot time', 8)
- s = s + ' ' + string.rjust('per call', 8)
- s = s + ' ' + string.rjust('cum time', 8)
- s = s + ' ' + string.rjust('per call', 8)
- print s + ' filename(function)'
+ print_title()
if self.stats_list:
for i in range(len(self.stats_list)):
- nc, tt, ct, callers, callees, key = self.stats_list[i]
- print_line(nc, tt, ct, callers, callees, key)
+ nc, tt, ct, callers, callees, key = \
+ self.stats_list[i]
+ print_line(nc, tt, ct, key)
else:
for key in self.stats.keys():
nc, tt, ct, callers, callees = self.stats[key]
- print_line(nc, tt, ct, callers, callees, key)
+ print_line(nc, tt, ct, key)
def print_callers(self):
if self.stats_list:
for i in range(len(self.stats_list)):
- nc, tt, ct, callers, callees, key = self.stats_list[i]
+ nc, tt, ct, callers, callees, key = \
+ self.stats_list[i]
print key,
for func in callers.keys():
print func+'('+`callers[func]`+')',
@@ -336,7 +252,8 @@ class Stats():
def print_callees(self):
if self.stats_list:
for i in range(len(self.stats_list)):
- nc, tt, ct, callers, callees, key = self.stats_list[i]
+ nc, tt, ct, callers, callees, key = \
+ self.stats_list[i]
print key,
for func in callees.keys():
print func+'('+`callees[func]`+')',
@@ -375,8 +292,10 @@ class Stats():
nt = nt[:field] + t[0:1] + nt[field:]
self.stats_list.append(nt)
+ def reverse_order(self):
+ self.stats_list.reverse()
+
def strip_dirs(self):
- import os
newstats = {}
for key in self.stats.keys():
nc, tt, ct, callers, callees = self.stats[key]
@@ -391,7 +310,44 @@ class Stats():
self.stats = newstats
self.stats_list = None
-# test command
+def print_title():
+ print string.rjust('ncalls', 8),
+ print string.rjust('tottime', 8),
+ print string.rjust('percall', 8),
+ print string.rjust('cumtime', 8),
+ print string.rjust('percall', 8),
+ print 'filename:lineno(function)'
+
+def print_line(nc, tt, ct, key):
+ print string.rjust(`nc`, 8),
+ print f8(tt),
+ if nc == 0:
+ print ' '*8,
+ else:
+ print f8(tt/nc),
+ print f8(ct),
+ if nc == 0:
+ print ' '*8,
+ else:
+ print f8(ct/nc),
+ print key
+
+def f8(x):
+ return string.rjust(fpformat.fix(x, 3), 8)
+
+# simplified user interface
+def run(statement, *args):
+ prof = Profile().init()
+ try:
+ prof.run(statement)
+ except SystemExit:
+ pass
+ if len(args) == 0:
+ prof.print_stats()
+ else:
+ prof.dump_stats(args[0])
+
+# test command with debugging
def debug():
prof = Profile().init()
prof.debug = 1
@@ -401,5 +357,6 @@ def debug():
pass
prof.print_stats()
+# test command
def test():
run('import x; x.main()')