Remove code and docs for the OldProfile and HotProfile classes: code

hasn't worked in years, docs were wrong, and they aren't interesting
anymore regardless.
This commit is contained in:
Tim Peters 2001-10-07 03:12:08 +00:00
parent 6d483d3477
commit 0a1fc4e389
3 changed files with 31 additions and 284 deletions

View File

@ -628,181 +628,34 @@ at this point, when a constant can be used.
\nodename{Profiler Extensions}
The \class{Profile} class of module \module{profile} was written so that
derived classes could be developed to extend the profiler. Rather
than describing all the details of such an effort, I'll just present
the following two examples of derived classes that can be used to do
profiling. If the reader is an avid Python programmer, then it should
be possible to use these as a model and create similar (and perchance
better) profile classes.
derived classes could be developed to extend the profiler. The details
are not described here, as doing this successfully requires an expert
understanding of how the \class{Profile} class works internally. Study
the source code of module \module{profile} carefully if you want to
pursue this.
If all you want to do is change how the timer is called, or which
timer function is used, then the basic class has an option for that in
the constructor for the class. Consider passing the name of a
function to call into the constructor:
If all you want to do is change how current time is determined (for
example, to force use of wall-clock time or elapsed process time),
pass the timing function you want to the \class{Profile} class
constructor:
\begin{verbatim}
pr = profile.Profile(your_time_func)
\end{verbatim}
The resulting profiler will call \code{your_time_func()} instead of
\function{os.times()}. The function should return either a single number
or a list of numbers (like what \function{os.times()} returns). If the
function returns a single time number, or the list of returned numbers
has length 2, then you will get an especially fast version of the
dispatch routine.
The resulting profiler will then call \code{your_time_func()}.
The function should return a single number, or a list of
numbers whose sum is the current time (like what \function{os.times()}
returns). If the function returns a single time number, or the list of
returned numbers has length 2, then you will get an especially fast
version of the dispatch routine.
Be warned that you \emph{should} calibrate the profiler class for the
Be warned that you should calibrate the profiler class for the
timer function that you choose. For most machines, a timer that
returns a lone integer value will provide the best results in terms of
low overhead during profiling. (\function{os.times()} is
\emph{pretty} bad, as it returns a tuple of floating point values,
so all arithmetic is floating point in the profiler!). If you want to
substitute a better timer in the cleanest fashion, you should derive a
class, and simply put in the replacement dispatch method that better
\emph{pretty} bad, as it returns a tuple of floating point values). If
you want to substitute a better timer in the cleanest fashion,
derive a class and hardwire a replacement dispatch method that best
handles your timer call, along with the appropriate calibration
constant.
Note that subclasses which override any of the
\method{trace_dispatch_call()}, \method{trace_dispatch_exception()},
or \method{trace_dispatch_return()} methods also need to specify a
dispatch table as well. The table, named \member{dispatch}, should
have the three keys \code{'call'}, \code{'exception'}, and
\code{'return'}, each giving the function of the corresponding
handler. Note that best performance is achieved by using the
\emph{function} objects for the handlers and not bound methods. This
is preferred since calling a simple function object executes less code
in the runtime than calling either bound or unbound methods. For
example, if the derived profiler overrides only one method, the
\member{dispatch} table can be built like this:
\begin{verbatim}
from profile import Profile
class MyProfiler(Profile):
def trace_dispath_call(self, frame, t):
# do something interesting here
...
dispatch = {
'call': trace_dispatch_call,
'exception': Profile.__dict__['trace_dispatch_exception'],
'return': Profile.__dict__['trace_dispatch_return'],
}
\end{verbatim}
\subsection{OldProfile Class \label{profile-old}}
The following derived profiler simulates the old style profiler,
providing errant results on recursive functions. The reason for the
usefulness of this profiler is that it runs faster (less
overhead) than the new profiler. It still creates all the caller
stats, and is quite useful when there is \emph{no} recursion in the
user's code. It is also a lot more accurate than the old profiler, as
it does not charge all its overhead time to the user's code.
\begin{verbatim}
class OldProfile(Profile):
def trace_dispatch_exception(self, frame, t):
rt, rtt, rct, rfn, rframe, rcur = self.cur
if rcur and not rframe is frame:
return self.trace_dispatch_return(rframe, t)
return 0
def trace_dispatch_call(self, frame, t):
fn = `frame.f_code`
self.cur = (t, 0, 0, fn, frame, self.cur)
if self.timings.has_key(fn):
tt, ct, callers = self.timings[fn]
self.timings[fn] = tt, ct, callers
else:
self.timings[fn] = 0, 0, {}
return 1
def trace_dispatch_return(self, frame, t):
rt, rtt, rct, rfn, frame, rcur = self.cur
rtt = rtt + t
sft = rtt + rct
pt, ptt, pct, pfn, pframe, pcur = rcur
self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
tt, ct, callers = self.timings[rfn]
if callers.has_key(pfn):
callers[pfn] = callers[pfn] + 1
else:
callers[pfn] = 1
self.timings[rfn] = tt+rtt, ct + sft, callers
return 1
dispatch = {
"call": trace_dispatch_call,
"exception": trace_dispatch_exception,
"return": trace_dispatch_return,
}
def snapshot_stats(self):
self.stats = {}
for func in self.timings.keys():
tt, ct, callers = self.timings[func]
callers = callers.copy()
nc = 0
for func_caller in callers.keys():
nc = nc + callers[func_caller]
self.stats[func] = nc, nc, tt, ct, callers
\end{verbatim}
\subsection{HotProfile Class \label{profile-HotProfile}}
This profiler is the fastest derived profile example. It does not
calculate caller-callee relationships, and does not calculate
cumulative time under a function. It only calculates time spent in a
function, so it runs very quickly (re: very low overhead). In truth,
the basic profiler is so fast, that is probably not worth the savings
to give up the data, but this class still provides a nice example.
\begin{verbatim}
class HotProfile(Profile):
def trace_dispatch_exception(self, frame, t):
rt, rtt, rfn, rframe, rcur = self.cur
if rcur and not rframe is frame:
return self.trace_dispatch_return(rframe, t)
return 0
def trace_dispatch_call(self, frame, t):
self.cur = (t, 0, frame, self.cur)
return 1
def trace_dispatch_return(self, frame, t):
rt, rtt, frame, rcur = self.cur
rfn = `frame.f_code`
pt, ptt, pframe, pcur = rcur
self.cur = pt, ptt+rt, pframe, pcur
if self.timings.has_key(rfn):
nc, tt = self.timings[rfn]
self.timings[rfn] = nc + 1, rt + rtt + tt
else:
self.timings[rfn] = 1, rt + rtt
return 1
dispatch = {
"call": trace_dispatch_call,
"exception": trace_dispatch_exception,
"return": trace_dispatch_return,
}
def snapshot_stats(self):
self.stats = {}
for func in self.timings.keys():
nc, tt = self.timings[func]
self.stats[func] = nc, nc, tt, 0, {}
\end{verbatim}

View File

@ -497,121 +497,6 @@ class Profile:
## t = t[0] + t[1]
self.ut = t
class OldProfile(Profile):
"""A derived profiler that simulates the old style profile, providing
errant results on recursive functions. The reason for the usefulness of
this profiler is that it runs faster (i.e., less overhead). It still
creates all the caller stats, and is quite useful when there is *no*
recursion in the user's code.
This code also shows how easy it is to create a modified profiler.
"""
def trace_dispatch_exception(self, frame, t):
rt, rtt, rct, rfn, rframe, rcur = self.cur
if rcur and not rframe is frame:
return self.trace_dispatch_return(rframe, t)
return 0
def trace_dispatch_call(self, frame, t):
fn = `frame.f_code`
self.cur = (t, 0, 0, fn, frame, self.cur)
if self.timings.has_key(fn):
tt, ct, callers = self.timings[fn]
self.timings[fn] = tt, ct, callers
else:
self.timings[fn] = 0, 0, {}
return 1
def trace_dispatch_return(self, frame, t):
rt, rtt, rct, rfn, frame, rcur = self.cur
rtt = rtt + t
sft = rtt + rct
pt, ptt, pct, pfn, pframe, pcur = rcur
self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
tt, ct, callers = self.timings[rfn]
if callers.has_key(pfn):
callers[pfn] = callers[pfn] + 1
else:
callers[pfn] = 1
self.timings[rfn] = tt+rtt, ct + sft, callers
return 1
dispatch = {
"call": trace_dispatch_call,
"exception": trace_dispatch_exception,
"return": trace_dispatch_return,
}
def snapshot_stats(self):
self.stats = {}
for func in self.timings.keys():
tt, ct, callers = self.timings[func]
callers = callers.copy()
nc = 0
for func_caller in callers.keys():
nc = nc + callers[func_caller]
self.stats[func] = nc, nc, tt, ct, callers
class HotProfile(Profile):
"""The fastest derived profile example. It does not calculate
caller-callee relationships, and does not calculate cumulative
time under a function. It only calculates time spent in a
function, so it runs very quickly due to its very low overhead.
"""
def trace_dispatch_exception(self, frame, t):
rt, rtt, rfn, rframe, rcur = self.cur
if rcur and not rframe is frame:
return self.trace_dispatch_return(rframe, t)
return 0
def trace_dispatch_call(self, frame, t):
self.cur = (t, 0, frame, self.cur)
return 1
def trace_dispatch_return(self, frame, t):
rt, rtt, frame, rcur = self.cur
rfn = `frame.f_code`
pt, ptt, pframe, pcur = rcur
self.cur = pt, ptt+rt, pframe, pcur
if self.timings.has_key(rfn):
nc, tt = self.timings[rfn]
self.timings[rfn] = nc + 1, rt + rtt + tt
else:
self.timings[rfn] = 1, rt + rtt
return 1
dispatch = {
"call": trace_dispatch_call,
"exception": trace_dispatch_exception,
"return": trace_dispatch_return,
}
def snapshot_stats(self):
self.stats = {}
for func in self.timings.keys():
nc, tt = self.timings[func]
self.stats[func] = nc, nc, tt, 0, {}
#****************************************************************************
def Stats(*args):
print 'Report generating functions are in the "pstats" module\a'

View File

@ -38,6 +38,15 @@ Library
to cause wrong output, including spurious claims of recursive
functions and attribution of time spent to the wrong function.
The code and documentation for the derived OldProfile and HotProfile
profiling classes was removed. The code hasn't worked for years (if
you tried to use them, they raised exceptions). OldProfile
intended to reproduce the behavior of the profiler Python used more
than 7 years ago, and isn't interesting anymore. HotProfile intended
to provide a faster profiler (but producing less information), and
that's a worthy goal we intend to meet via a different approach (but
without losing information).
- quopri's encode and decode methods take an optional header parameter,
which indicates whether output is intended for the header 'Q' encoding.