From 4e16098ce74c645cf1d69566b6f8bc96031554b7 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 2 Sep 1992 20:43:20 +0000 Subject: 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). --- Lib/bdb.py | 37 +++++--- Lib/bisect.py | 23 +++++ Lib/irix5/FL.py | 4 + Lib/lib-stdwin/wdb.py | 5 ++ Lib/pdb.py | 3 + Lib/plat-irix5/FL.py | 4 + Lib/profile.py | 233 ++++++++++++++++++++------------------------------ Lib/sched.py | 13 +-- Lib/stdwin/wdb.py | 5 ++ 9 files changed, 167 insertions(+), 160 deletions(-) create mode 100644 Lib/bisect.py diff --git a/Lib/bdb.py b/Lib/bdb.py index 15a8023..8a722fe 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -68,7 +68,7 @@ class Bdb: # Basic Debugger return self.trace_dispatch # Normally derived classes don't override the following - # functions, but they may if they want to redefine the + # methods, but they may if they want to redefine the # definition of stopping and breakpoints. def stop_here(self, frame): @@ -93,28 +93,28 @@ class Bdb: # Basic Debugger def break_anywhere(self, frame): return self.breaks.has_key(frame.f_code.co_filename) - # Derived classes should override the user_* functions + # Derived classes should override the user_* methods # to gain control. def user_call(self, frame, argument_list): - # This function is called when there is the remote possibility + # This method is called when there is the remote possibility # that we ever need to stop in this function pass def user_line(self, frame): - # This function is called when we stop or break at this line + # This method is called when we stop or break at this line pass def user_return(self, frame, return_value): - # This function is called when a return trap is set here + # This method is called when a return trap is set here pass def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): - # This function is called if an exception occurs, + # This method is called if an exception occurs, # but only if we are to stop at or just below this level pass - # Derived classes and clients can call the following functions + # Derived classes and clients can call the following methods # to affect the stepping state. def set_step(self): @@ -147,8 +147,8 @@ class Bdb: # Basic Debugger self.quitting = 1 sys.settrace(None) - # Derived classes and clients can call the following functions - # to manipulate breakpoints. These functions return an + # Derived classes and clients can call the following methods + # to manipulate breakpoints. These methods return an # error message is something went wrong, None if all is well. # Call self.get_*break*() to see the breakpoints. @@ -196,7 +196,7 @@ class Bdb: # Basic Debugger def get_all_breaks(self): return self.breaks - # Derived classes and clients can call the following function + # Derived classes and clients can call the following method # to get a data structure representing a stack trace. def get_stack(self, f, t): @@ -234,7 +234,7 @@ class Bdb: # Basic Debugger if line: s = s + ': ' + string.strip(line) return s - # The following two functions can be called by clients to use + # The following two methods can be called by clients to use # a debugger to debug a statement, given as a string. def run(self, cmd): @@ -253,7 +253,20 @@ class Bdb: # Basic Debugger finally: self.quitting = 1 sys.settrace(None) - # XXX What to do if the command finishes normally? + + # This method is more useful to debug a single function call. + + def runcall(self, func, *args): + self.reset() + sys.settrace(self.trace_dispatch) + try: + try: + apply(func, args) + except BdbQuit: + pass + finally: + self.quitting = 1 + sys.settrace(None) # -------------------- testing -------------------- diff --git a/Lib/bisect.py b/Lib/bisect.py new file mode 100644 index 0000000..688666a --- /dev/null +++ b/Lib/bisect.py @@ -0,0 +1,23 @@ +# Bisection algorithms + + +# Insert item x in list a, and keep it sorted assuming a is sorted + +def insort(a, x): + lo, hi = 0, len(a) + while lo < hi: + mid = (lo+hi)/2 + if x < a[mid]: hi = mid + else: lo = mid+1 + a.insert(lo, x) + + +# Find the index where to insert item x in list a, assuming a is sorted + +def bisect(a, x): + lo, hi = 0, len(a) + while lo < hi: + mid = (lo+hi)/2 + if x < a[mid]: hi = mid + else: lo = mid+1 + return lo diff --git a/Lib/irix5/FL.py b/Lib/irix5/FL.py index 3142b1b..65184df 100755 --- a/Lib/irix5/FL.py +++ b/Lib/irix5/FL.py @@ -4,6 +4,7 @@ # Alternate use: from FL import *; ... NORMAL_BOX ... etc. _v20 = 1 +_v21 = 1 ##import fl ##try: ## _v20 = (fl.get_rgbmode <> None) @@ -198,6 +199,9 @@ if _v20: FLOAT_INPUT = 1 INT_INPUT = 2 HIDDEN_INPUT = 3 + if _v21: + MULTILINE_INPUT = 4 + SECRET_INPUT = 5 else: ALWAYS_INPUT = 1 INPUT_BOXTYPE = DOWN_BOX diff --git a/Lib/lib-stdwin/wdb.py b/Lib/lib-stdwin/wdb.py index 9914f3f..b3d6b73 100644 --- a/Lib/lib-stdwin/wdb.py +++ b/Lib/lib-stdwin/wdb.py @@ -283,6 +283,11 @@ def runctx(statement, globals, locals): try: x.runctx(statement, globals, locals) finally: x.close() +def runcall(*args): + x = Wdb().init() + try: apply(Pdb().init().runcall, args) + finally: x.close() + TESTCMD = 'import x; x.main()' def test(): diff --git a/Lib/pdb.py b/Lib/pdb.py index 0dd975b..f564f64 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -254,6 +254,9 @@ def run(statement): def runctx(statement, globals, locals): Pdb().init().runctx(statement, globals, locals) +def runcall(*args): + apply(Pdb().init().runcall, args) + TESTCMD = 'import x; x.main()' def test(): diff --git a/Lib/plat-irix5/FL.py b/Lib/plat-irix5/FL.py index 3142b1b..65184df 100755 --- a/Lib/plat-irix5/FL.py +++ b/Lib/plat-irix5/FL.py @@ -4,6 +4,7 @@ # Alternate use: from FL import *; ... NORMAL_BOX ... etc. _v20 = 1 +_v21 = 1 ##import fl ##try: ## _v20 = (fl.get_rgbmode <> None) @@ -198,6 +199,9 @@ if _v20: FLOAT_INPUT = 1 INT_INPUT = 2 HIDDEN_INPUT = 3 + if _v21: + MULTILINE_INPUT = 4 + SECRET_INPUT = 5 else: ALWAYS_INPUT = 1 INPUT_BOXTYPE = DOWN_BOX 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()') diff --git a/Lib/sched.py b/Lib/sched.py index 4a45309..685b2bc 100644 --- a/Lib/sched.py +++ b/Lib/sched.py @@ -28,6 +28,8 @@ # XXX instead of having to define a module or class just to hold # XXX the global state of your particular time and delay functtions. +import bisect + class scheduler: # # Initialize a new instance, passing the time and delay functions @@ -43,16 +45,7 @@ class scheduler: # to remove it, if necessary. # def enterabs(self, event): - time, priority, action, argument = event - q = self.queue - # XXX Could use bisection or linear interpolation? - for i in range(len(q)): - qtime, qpri, qact, qarg = q[i] - if time < qtime: break - if time == qtime and priority < qpri: break - else: - i = len(q) - q.insert(i, event) + bisect.insort(self.queue, event) return event # The ID # # A variant that specifies the time as a relative time. diff --git a/Lib/stdwin/wdb.py b/Lib/stdwin/wdb.py index 9914f3f..b3d6b73 100755 --- a/Lib/stdwin/wdb.py +++ b/Lib/stdwin/wdb.py @@ -283,6 +283,11 @@ def runctx(statement, globals, locals): try: x.runctx(statement, globals, locals) finally: x.close() +def runcall(*args): + x = Wdb().init() + try: apply(Pdb().init().runcall, args) + finally: x.close() + TESTCMD = 'import x; x.main()' def test(): -- cgit v0.12