Commit 4e16098c authored by Guido van Rossum's avatar Guido van Rossum

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).
parent 2179945e
...@@ -68,7 +68,7 @@ class Bdb: # Basic Debugger ...@@ -68,7 +68,7 @@ class Bdb: # Basic Debugger
return self.trace_dispatch return self.trace_dispatch
# Normally derived classes don't override the following # 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. # definition of stopping and breakpoints.
def stop_here(self, frame): def stop_here(self, frame):
...@@ -93,28 +93,28 @@ class Bdb: # Basic Debugger ...@@ -93,28 +93,28 @@ class Bdb: # Basic Debugger
def break_anywhere(self, frame): def break_anywhere(self, frame):
return self.breaks.has_key(frame.f_code.co_filename) 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. # to gain control.
def user_call(self, frame, argument_list): 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 # that we ever need to stop in this function
pass pass
def user_line(self, frame): 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 pass
def user_return(self, frame, return_value): 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 pass
def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): 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 # but only if we are to stop at or just below this level
pass pass
# Derived classes and clients can call the following functions # Derived classes and clients can call the following methods
# to affect the stepping state. # to affect the stepping state.
def set_step(self): def set_step(self):
...@@ -147,8 +147,8 @@ class Bdb: # Basic Debugger ...@@ -147,8 +147,8 @@ class Bdb: # Basic Debugger
self.quitting = 1 self.quitting = 1
sys.settrace(None) sys.settrace(None)
# Derived classes and clients can call the following functions # Derived classes and clients can call the following methods
# to manipulate breakpoints. These functions return an # to manipulate breakpoints. These methods return an
# error message is something went wrong, None if all is well. # error message is something went wrong, None if all is well.
# Call self.get_*break*() to see the breakpoints. # Call self.get_*break*() to see the breakpoints.
...@@ -196,7 +196,7 @@ class Bdb: # Basic Debugger ...@@ -196,7 +196,7 @@ class Bdb: # Basic Debugger
def get_all_breaks(self): def get_all_breaks(self):
return self.breaks 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. # to get a data structure representing a stack trace.
def get_stack(self, f, t): def get_stack(self, f, t):
...@@ -234,7 +234,7 @@ class Bdb: # Basic Debugger ...@@ -234,7 +234,7 @@ class Bdb: # Basic Debugger
if line: s = s + ': ' + string.strip(line) if line: s = s + ': ' + string.strip(line)
return s 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. # a debugger to debug a statement, given as a string.
def run(self, cmd): def run(self, cmd):
...@@ -253,7 +253,20 @@ class Bdb: # Basic Debugger ...@@ -253,7 +253,20 @@ class Bdb: # Basic Debugger
finally: finally:
self.quitting = 1 self.quitting = 1
sys.settrace(None) 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 -------------------- # -------------------- testing --------------------
......
# 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
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# Alternate use: from FL import *; ... NORMAL_BOX ... etc. # Alternate use: from FL import *; ... NORMAL_BOX ... etc.
_v20 = 1 _v20 = 1
_v21 = 1
##import fl ##import fl
##try: ##try:
## _v20 = (fl.get_rgbmode <> None) ## _v20 = (fl.get_rgbmode <> None)
...@@ -198,6 +199,9 @@ if _v20: ...@@ -198,6 +199,9 @@ if _v20:
FLOAT_INPUT = 1 FLOAT_INPUT = 1
INT_INPUT = 2 INT_INPUT = 2
HIDDEN_INPUT = 3 HIDDEN_INPUT = 3
if _v21:
MULTILINE_INPUT = 4
SECRET_INPUT = 5
else: else:
ALWAYS_INPUT = 1 ALWAYS_INPUT = 1
INPUT_BOXTYPE = DOWN_BOX INPUT_BOXTYPE = DOWN_BOX
......
...@@ -283,6 +283,11 @@ def runctx(statement, globals, locals): ...@@ -283,6 +283,11 @@ def runctx(statement, globals, locals):
try: x.runctx(statement, globals, locals) try: x.runctx(statement, globals, locals)
finally: x.close() finally: x.close()
def runcall(*args):
x = Wdb().init()
try: apply(Pdb().init().runcall, args)
finally: x.close()
TESTCMD = 'import x; x.main()' TESTCMD = 'import x; x.main()'
def test(): def test():
......
...@@ -254,6 +254,9 @@ def run(statement): ...@@ -254,6 +254,9 @@ def run(statement):
def runctx(statement, globals, locals): def runctx(statement, globals, locals):
Pdb().init().runctx(statement, globals, locals) Pdb().init().runctx(statement, globals, locals)
def runcall(*args):
apply(Pdb().init().runcall, args)
TESTCMD = 'import x; x.main()' TESTCMD = 'import x; x.main()'
def test(): def test():
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# Alternate use: from FL import *; ... NORMAL_BOX ... etc. # Alternate use: from FL import *; ... NORMAL_BOX ... etc.
_v20 = 1 _v20 = 1
_v21 = 1
##import fl ##import fl
##try: ##try:
## _v20 = (fl.get_rgbmode <> None) ## _v20 = (fl.get_rgbmode <> None)
...@@ -198,6 +199,9 @@ if _v20: ...@@ -198,6 +199,9 @@ if _v20:
FLOAT_INPUT = 1 FLOAT_INPUT = 1
INT_INPUT = 2 INT_INPUT = 2
HIDDEN_INPUT = 3 HIDDEN_INPUT = 3
if _v21:
MULTILINE_INPUT = 4
SECRET_INPUT = 5
else: else:
ALWAYS_INPUT = 1 ALWAYS_INPUT = 1
INPUT_BOXTYPE = DOWN_BOX INPUT_BOXTYPE = DOWN_BOX
......
# #
# Class for profiling python code. # Class for profiling python code.
# Author: Sjoerd Mullender # Author: Sjoerd Mullender
# Hacked somewhat by: Guido van Rossum
# #
# See the accompanying document profile.doc for more information. # See the accompanying document profile.doc for more information.
import sys import sys
import codehack import codehack
import posix import os
import string
import fpformat
import marshal
class Profile(): class Profile():
...@@ -30,7 +34,7 @@ class Profile(): ...@@ -30,7 +34,7 @@ class Profile():
if self.profile_func.has_key(funcname): if self.profile_func.has_key(funcname):
return return
self.profiling = 1 self.profiling = 1
t = posix.times() t = os.times()
t = t[0] + t[1] t = t[0] + t[1]
lineno = codehack.getlineno(frame.f_code) lineno = codehack.getlineno(frame.f_code)
filename = frame.f_code.co_filename filename = frame.f_code.co_filename
...@@ -42,13 +46,16 @@ class Profile(): ...@@ -42,13 +46,16 @@ class Profile():
s0 = 'call: ' + key + ' depth: ' + `self.call_level` + ' time: ' + `t` s0 = 'call: ' + key + ' depth: ' + `self.call_level` + ' time: ' + `t`
if pframe: if pframe:
pkey = pframe.f_code.co_filename + ':' + \ pkey = pframe.f_code.co_filename + ':' + \
`codehack.getlineno(pframe.f_code)` + '(' + \ `codehack.getlineno(pframe.f_code)` \
codehack.getcodename(pframe.f_code) + ')' + '(' + \
codehack.getcodename(pframe.f_code) \
+ ')'
if self.debug: if self.debug:
s1 = 'parent: ' + pkey s1 = 'parent: ' + pkey
if pframe.f_locals.has_key('__start_time'): if pframe.f_locals.has_key('__start_time'):
st = pframe.f_locals['__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: if self.debug:
s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct` s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct`
if callers.has_key(key): if callers.has_key(key):
...@@ -80,7 +87,8 @@ class Profile(): ...@@ -80,7 +87,8 @@ class Profile():
if self.profile_func: if self.profile_func:
if not self.profiling: if not self.profiling:
return 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.profiling = 0
self.call_level = depth(frame) self.call_level = depth(frame)
self.cur_frame = frame self.cur_frame = frame
...@@ -106,11 +114,12 @@ class Profile(): ...@@ -106,11 +114,12 @@ class Profile():
self.call_level = call_level self.call_level = call_level
self.cur_frame = frame self.cur_frame = frame
return return
print 'profile.Profile.dispatch: unknown debugging event:', `event` print 'profile.Profile.dispatch: unknown debugging event:',
print `event`
return return
def handle_return(self, pframe, frame, s0): def handle_return(self, pframe, frame, s0):
t = posix.times() t = os.times()
t = t[0] + t[1] t = t[0] + t[1]
funcname = codehack.getcodename(frame.f_code) funcname = codehack.getcodename(frame.f_code)
lineno = codehack.getlineno(frame.f_code) lineno = codehack.getlineno(frame.f_code)
...@@ -128,11 +137,13 @@ class Profile(): ...@@ -128,11 +137,13 @@ class Profile():
if pframe.f_locals.has_key('__start_time') and \ if pframe.f_locals.has_key('__start_time') and \
self.timings.has_key(pkey): self.timings.has_key(pkey):
st = pframe.f_locals['__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: if self.debug:
s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct` s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct`
s1 = s1+' after: st='+`t`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct+(t-st)` 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 pframe.f_locals['__start_time'] = t
if self.timings.has_key(key): if self.timings.has_key(key):
nc, tt, ct, callers, callees = self.timings[key] nc, tt, ct, callers, callees = self.timings[key]
...@@ -147,35 +158,30 @@ class Profile(): ...@@ -147,35 +158,30 @@ class Profile():
s0 = s0+' after: nc='+`nc`+' tt='+`tt+(t-st)`+' ct='+`ct+(t-st)` s0 = s0+' after: nc='+`nc`+' tt='+`tt+(t-st)`+' ct='+`ct+(t-st)`
print s0 print s0
print s1 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): def print_stats(self):
import string # Print in reverse order by ct
s = string.rjust('# calls', 8) print_title()
s = s + ' ' + string.rjust('tot time', 8) list = []
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)'
for key in self.timings.keys(): for key in self.timings.keys():
nc, tt, ct, callers, callees = self.timings[key] nc, tt, ct, callers, callees = self.timings[key]
if nc == 0: if nc == 0:
continue continue
s = string.rjust(`nc`, 8) list.append(ct, tt, nc, key)
s = s + ' ' + string.rjust(`tt`, 8) list.sort()
s = s + ' ' + string.rjust(`tt/nc`, 8) list.reverse()
s = s + ' ' + string.rjust(`ct`, 8) for ct, tt, nc, key in list:
s = s + ' ' + string.rjust(`ct/nc`, 8) print_line(nc, tt, ct, os.path.basename(key))
print s + ' ' + key
def dump_stats(self, file): def dump_stats(self, file):
import marshal
f = open(file, 'w') f = open(file, 'w')
marshal.dump(self.timings, f) marshal.dump(self.timings, f)
f.close() f.close()
# 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. # a profiler to profile a statement, given as a string.
def run(self, cmd): def run(self, cmd):
import __main__ import __main__
...@@ -183,17 +189,21 @@ class Profile(): ...@@ -183,17 +189,21 @@ class Profile():
self.runctx(cmd, dict, dict) self.runctx(cmd, dict, dict)
def runctx(self, cmd, globals, locals): def runctx(self, cmd, globals, locals):
## self.reset()
sys.setprofile(self.trace_dispatch) sys.setprofile(self.trace_dispatch)
try: try:
## try: exec(cmd + '\n', globals, locals)
exec(cmd + '\n', globals, locals)
## except ProfQuit:
## pass
finally: finally:
## self.quitting = 1
sys.setprofile(None) 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): def depth(frame):
d = 0 d = 0
...@@ -202,98 +212,8 @@ def depth(frame): ...@@ -202,98 +212,8 @@ def depth(frame):
frame = frame.f_back frame = frame.f_back
return d 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(): class Stats():
def init(self, file): def init(self, file):
import marshal
f = open(file, 'r') f = open(file, 'r')
self.stats = marshal.load(f) self.stats = marshal.load(f)
f.close() f.close()
...@@ -301,26 +221,22 @@ class Stats(): ...@@ -301,26 +221,22 @@ class Stats():
return self return self
def print_stats(self): def print_stats(self):
import string print_title()
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)'
if self.stats_list: if self.stats_list:
for i in range(len(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 = \
print_line(nc, tt, ct, callers, callees, key) self.stats_list[i]
print_line(nc, tt, ct, key)
else: else:
for key in self.stats.keys(): for key in self.stats.keys():
nc, tt, ct, callers, callees = self.stats[key] 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): def print_callers(self):
if self.stats_list: if self.stats_list:
for i in range(len(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, print key,
for func in callers.keys(): for func in callers.keys():
print func+'('+`callers[func]`+')', print func+'('+`callers[func]`+')',
...@@ -336,7 +252,8 @@ class Stats(): ...@@ -336,7 +252,8 @@ class Stats():
def print_callees(self): def print_callees(self):
if self.stats_list: if self.stats_list:
for i in range(len(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, print key,
for func in callees.keys(): for func in callees.keys():
print func+'('+`callees[func]`+')', print func+'('+`callees[func]`+')',
...@@ -375,8 +292,10 @@ class Stats(): ...@@ -375,8 +292,10 @@ class Stats():
nt = nt[:field] + t[0:1] + nt[field:] nt = nt[:field] + t[0:1] + nt[field:]
self.stats_list.append(nt) self.stats_list.append(nt)
def reverse_order(self):
self.stats_list.reverse()
def strip_dirs(self): def strip_dirs(self):
import os
newstats = {} newstats = {}
for key in self.stats.keys(): for key in self.stats.keys():
nc, tt, ct, callers, callees = self.stats[key] nc, tt, ct, callers, callees = self.stats[key]
...@@ -391,7 +310,44 @@ class Stats(): ...@@ -391,7 +310,44 @@ class Stats():
self.stats = newstats self.stats = newstats
self.stats_list = None 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(): def debug():
prof = Profile().init() prof = Profile().init()
prof.debug = 1 prof.debug = 1
...@@ -401,5 +357,6 @@ def debug(): ...@@ -401,5 +357,6 @@ def debug():
pass pass
prof.print_stats() prof.print_stats()
# test command
def test(): def test():
run('import x; x.main()') run('import x; x.main()')
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
# XXX instead of having to define a module or class just to hold # XXX instead of having to define a module or class just to hold
# XXX the global state of your particular time and delay functtions. # XXX the global state of your particular time and delay functtions.
import bisect
class scheduler: class scheduler:
# #
# Initialize a new instance, passing the time and delay functions # Initialize a new instance, passing the time and delay functions
...@@ -43,16 +45,7 @@ class scheduler: ...@@ -43,16 +45,7 @@ class scheduler:
# to remove it, if necessary. # to remove it, if necessary.
# #
def enterabs(self, event): def enterabs(self, event):
time, priority, action, argument = event bisect.insort(self.queue, 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)
return event # The ID return event # The ID
# #
# A variant that specifies the time as a relative time. # A variant that specifies the time as a relative time.
......
...@@ -283,6 +283,11 @@ def runctx(statement, globals, locals): ...@@ -283,6 +283,11 @@ def runctx(statement, globals, locals):
try: x.runctx(statement, globals, locals) try: x.runctx(statement, globals, locals)
finally: x.close() finally: x.close()
def runcall(*args):
x = Wdb().init()
try: apply(Pdb().init().runcall, args)
finally: x.close()
TESTCMD = 'import x; x.main()' TESTCMD = 'import x; x.main()'
def test(): def test():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment