summaryrefslogtreecommitdiff
path: root/lib/python2.7/hotshot
diff options
context:
space:
mode:
authorrahulp132020-03-17 14:55:41 +0530
committerrahulp132020-03-17 14:55:41 +0530
commit296443137f4288cb030e92859ccfbe3204bc1088 (patch)
treeca4798c2da1e7244edc3bc108d81b462b537aea2 /lib/python2.7/hotshot
parent0db48f6533517ecebfd9f0693f89deca28408b76 (diff)
downloadKiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.gz
KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.bz2
KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.zip
initial commit
Diffstat (limited to 'lib/python2.7/hotshot')
-rw-r--r--lib/python2.7/hotshot/__init__.py78
-rw-r--r--lib/python2.7/hotshot/log.py194
-rw-r--r--lib/python2.7/hotshot/stats.py93
-rw-r--r--lib/python2.7/hotshot/stones.py30
4 files changed, 395 insertions, 0 deletions
diff --git a/lib/python2.7/hotshot/__init__.py b/lib/python2.7/hotshot/__init__.py
new file mode 100644
index 0000000..3692f93
--- /dev/null
+++ b/lib/python2.7/hotshot/__init__.py
@@ -0,0 +1,78 @@
+"""High-perfomance logging profiler, mostly written in C."""
+
+import _hotshot
+from _hotshot import ProfilerError
+
+from warnings import warnpy3k as _warnpy3k
+_warnpy3k("The 'hotshot' module is not supported in 3.x, "
+ "use the 'profile' module instead.", stacklevel=2)
+
+class Profile:
+ def __init__(self, logfn, lineevents=0, linetimings=1):
+ self.lineevents = lineevents and 1 or 0
+ self.linetimings = (linetimings and lineevents) and 1 or 0
+ self._prof = p = _hotshot.profiler(
+ logfn, self.lineevents, self.linetimings)
+
+ # Attempt to avoid confusing results caused by the presence of
+ # Python wrappers around these functions, but only if we can
+ # be sure the methods have not been overridden or extended.
+ if self.__class__ is Profile:
+ self.close = p.close
+ self.start = p.start
+ self.stop = p.stop
+ self.addinfo = p.addinfo
+
+ def close(self):
+ """Close the logfile and terminate the profiler."""
+ self._prof.close()
+
+ def fileno(self):
+ """Return the file descriptor of the profiler's log file."""
+ return self._prof.fileno()
+
+ def start(self):
+ """Start the profiler."""
+ self._prof.start()
+
+ def stop(self):
+ """Stop the profiler."""
+ self._prof.stop()
+
+ def addinfo(self, key, value):
+ """Add an arbitrary labelled value to the profile log."""
+ self._prof.addinfo(key, value)
+
+ # These methods offer the same interface as the profile.Profile class,
+ # but delegate most of the work to the C implementation underneath.
+
+ def run(self, cmd):
+ """Profile an exec-compatible string in the script
+ environment.
+
+ The globals from the __main__ module are used as both the
+ globals and locals for the script.
+ """
+ import __main__
+ dict = __main__.__dict__
+ return self.runctx(cmd, dict, dict)
+
+ def runctx(self, cmd, globals, locals):
+ """Evaluate an exec-compatible string in a specific
+ environment.
+
+ The string is compiled before profiling begins.
+ """
+ code = compile(cmd, "<string>", "exec")
+ self._prof.runcode(code, globals, locals)
+ return self
+
+ def runcall(self, func, *args, **kw):
+ """Profile a single call of a callable.
+
+ Additional positional and keyword arguments may be passed
+ along; the result of the call is returned, and exceptions are
+ allowed to propagate cleanly, while ensuring that profiling is
+ disabled on the way out.
+ """
+ return self._prof.runcall(func, args, kw)
diff --git a/lib/python2.7/hotshot/log.py b/lib/python2.7/hotshot/log.py
new file mode 100644
index 0000000..17e8b50
--- /dev/null
+++ b/lib/python2.7/hotshot/log.py
@@ -0,0 +1,194 @@
+import _hotshot
+import os.path
+import parser
+import symbol
+
+from _hotshot import \
+ WHAT_ENTER, \
+ WHAT_EXIT, \
+ WHAT_LINENO, \
+ WHAT_DEFINE_FILE, \
+ WHAT_DEFINE_FUNC, \
+ WHAT_ADD_INFO
+
+
+__all__ = ["LogReader", "ENTER", "EXIT", "LINE"]
+
+
+ENTER = WHAT_ENTER
+EXIT = WHAT_EXIT
+LINE = WHAT_LINENO
+
+
+class LogReader:
+ def __init__(self, logfn):
+ # fileno -> filename
+ self._filemap = {}
+ # (fileno, lineno) -> filename, funcname
+ self._funcmap = {}
+
+ self._reader = _hotshot.logreader(logfn)
+ self._nextitem = self._reader.next
+ self._info = self._reader.info
+ if 'current-directory' in self._info:
+ self.cwd = self._info['current-directory']
+ else:
+ self.cwd = None
+
+ # This mirrors the call stack of the profiled code as the log
+ # is read back in. It contains tuples of the form:
+ #
+ # (file name, line number of function def, function name)
+ #
+ self._stack = []
+ self._append = self._stack.append
+ self._pop = self._stack.pop
+
+ def close(self):
+ self._reader.close()
+
+ def fileno(self):
+ """Return the file descriptor of the log reader's log file."""
+ return self._reader.fileno()
+
+ def addinfo(self, key, value):
+ """This method is called for each additional ADD_INFO record.
+
+ This can be overridden by applications that want to receive
+ these events. The default implementation does not need to be
+ called by alternate implementations.
+
+ The initial set of ADD_INFO records do not pass through this
+ mechanism; this is only needed to receive notification when
+ new values are added. Subclasses can inspect self._info after
+ calling LogReader.__init__().
+ """
+ pass
+
+ def get_filename(self, fileno):
+ try:
+ return self._filemap[fileno]
+ except KeyError:
+ raise ValueError, "unknown fileno"
+
+ def get_filenames(self):
+ return self._filemap.values()
+
+ def get_fileno(self, filename):
+ filename = os.path.normcase(os.path.normpath(filename))
+ for fileno, name in self._filemap.items():
+ if name == filename:
+ return fileno
+ raise ValueError, "unknown filename"
+
+ def get_funcname(self, fileno, lineno):
+ try:
+ return self._funcmap[(fileno, lineno)]
+ except KeyError:
+ raise ValueError, "unknown function location"
+
+ # Iteration support:
+ # This adds an optional (& ignored) parameter to next() so that the
+ # same bound method can be used as the __getitem__() method -- this
+ # avoids using an additional method call which kills the performance.
+
+ def next(self, index=0):
+ while 1:
+ # This call may raise StopIteration:
+ what, tdelta, fileno, lineno = self._nextitem()
+
+ # handle the most common cases first
+
+ if what == WHAT_ENTER:
+ filename, funcname = self._decode_location(fileno, lineno)
+ t = (filename, lineno, funcname)
+ self._append(t)
+ return what, t, tdelta
+
+ if what == WHAT_EXIT:
+ try:
+ return what, self._pop(), tdelta
+ except IndexError:
+ raise StopIteration
+
+ if what == WHAT_LINENO:
+ filename, firstlineno, funcname = self._stack[-1]
+ return what, (filename, lineno, funcname), tdelta
+
+ if what == WHAT_DEFINE_FILE:
+ filename = os.path.normcase(os.path.normpath(tdelta))
+ self._filemap[fileno] = filename
+ elif what == WHAT_DEFINE_FUNC:
+ filename = self._filemap[fileno]
+ self._funcmap[(fileno, lineno)] = (filename, tdelta)
+ elif what == WHAT_ADD_INFO:
+ # value already loaded into self.info; call the
+ # overridable addinfo() handler so higher-level code
+ # can pick up the new value
+ if tdelta == 'current-directory':
+ self.cwd = lineno
+ self.addinfo(tdelta, lineno)
+ else:
+ raise ValueError, "unknown event type"
+
+ def __iter__(self):
+ return self
+
+ #
+ # helpers
+ #
+
+ def _decode_location(self, fileno, lineno):
+ try:
+ return self._funcmap[(fileno, lineno)]
+ except KeyError:
+ #
+ # This should only be needed when the log file does not
+ # contain all the DEFINE_FUNC records needed to allow the
+ # function name to be retrieved from the log file.
+ #
+ if self._loadfile(fileno):
+ filename = funcname = None
+ try:
+ filename, funcname = self._funcmap[(fileno, lineno)]
+ except KeyError:
+ filename = self._filemap.get(fileno)
+ funcname = None
+ self._funcmap[(fileno, lineno)] = (filename, funcname)
+ return filename, funcname
+
+ def _loadfile(self, fileno):
+ try:
+ filename = self._filemap[fileno]
+ except KeyError:
+ print "Could not identify fileId", fileno
+ return 1
+ if filename is None:
+ return 1
+ absname = os.path.normcase(os.path.join(self.cwd, filename))
+
+ try:
+ fp = open(absname)
+ except IOError:
+ return
+ st = parser.suite(fp.read())
+ fp.close()
+
+ # Scan the tree looking for def and lambda nodes, filling in
+ # self._funcmap with all the available information.
+ funcdef = symbol.funcdef
+ lambdef = symbol.lambdef
+
+ stack = [st.totuple(1)]
+
+ while stack:
+ tree = stack.pop()
+ try:
+ sym = tree[0]
+ except (IndexError, TypeError):
+ continue
+ if sym == funcdef:
+ self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]
+ elif sym == lambdef:
+ self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"
+ stack.extend(list(tree[1:]))
diff --git a/lib/python2.7/hotshot/stats.py b/lib/python2.7/hotshot/stats.py
new file mode 100644
index 0000000..7ff2277
--- /dev/null
+++ b/lib/python2.7/hotshot/stats.py
@@ -0,0 +1,93 @@
+"""Statistics analyzer for HotShot."""
+
+import profile
+import pstats
+
+import hotshot.log
+
+from hotshot.log import ENTER, EXIT
+
+
+def load(filename):
+ return StatsLoader(filename).load()
+
+
+class StatsLoader:
+ def __init__(self, logfn):
+ self._logfn = logfn
+ self._code = {}
+ self._stack = []
+ self.pop_frame = self._stack.pop
+
+ def load(self):
+ # The timer selected by the profiler should never be used, so make
+ # sure it doesn't work:
+ p = Profile()
+ p.get_time = _brokentimer
+ log = hotshot.log.LogReader(self._logfn)
+ taccum = 0
+ for event in log:
+ what, (filename, lineno, funcname), tdelta = event
+ if tdelta > 0:
+ taccum += tdelta
+
+ # We multiply taccum to convert from the microseconds we
+ # have to the seconds that the profile/pstats module work
+ # with; this allows the numbers to have some basis in
+ # reality (ignoring calibration issues for now).
+
+ if what == ENTER:
+ frame = self.new_frame(filename, lineno, funcname)
+ p.trace_dispatch_call(frame, taccum * .000001)
+ taccum = 0
+
+ elif what == EXIT:
+ frame = self.pop_frame()
+ p.trace_dispatch_return(frame, taccum * .000001)
+ taccum = 0
+
+ # no further work for line events
+
+ assert not self._stack
+ return pstats.Stats(p)
+
+ def new_frame(self, *args):
+ # args must be filename, firstlineno, funcname
+ # our code objects are cached since we don't need to create
+ # new ones every time
+ try:
+ code = self._code[args]
+ except KeyError:
+ code = FakeCode(*args)
+ self._code[args] = code
+ # frame objects are create fresh, since the back pointer will
+ # vary considerably
+ if self._stack:
+ back = self._stack[-1]
+ else:
+ back = None
+ frame = FakeFrame(code, back)
+ self._stack.append(frame)
+ return frame
+
+
+class Profile(profile.Profile):
+ def simulate_cmd_complete(self):
+ pass
+
+
+class FakeCode:
+ def __init__(self, filename, firstlineno, funcname):
+ self.co_filename = filename
+ self.co_firstlineno = firstlineno
+ self.co_name = self.__name__ = funcname
+
+
+class FakeFrame:
+ def __init__(self, code, back):
+ self.f_back = back
+ self.f_code = code
+
+
+def _brokentimer():
+ raise RuntimeError, "this timer should not be called"
diff --git a/lib/python2.7/hotshot/stones.py b/lib/python2.7/hotshot/stones.py
new file mode 100644
index 0000000..fb88d58
--- /dev/null
+++ b/lib/python2.7/hotshot/stones.py
@@ -0,0 +1,30 @@
+import errno
+import hotshot
+import hotshot.stats
+import sys
+import test.pystone
+
+def main(logfile):
+ p = hotshot.Profile(logfile)
+ benchtime, stones = p.runcall(test.pystone.pystones)
+ p.close()
+
+ print "Pystone(%s) time for %d passes = %g" % \
+ (test.pystone.__version__, test.pystone.LOOPS, benchtime)
+ print "This machine benchmarks at %g pystones/second" % stones
+
+ stats = hotshot.stats.load(logfile)
+ stats.strip_dirs()
+ stats.sort_stats('time', 'calls')
+ try:
+ stats.print_stats(20)
+ except IOError, e:
+ if e.errno != errno.EPIPE:
+ raise
+
+if __name__ == '__main__':
+ if sys.argv[1:]:
+ main(sys.argv[1])
+ else:
+ import tempfile
+ main(tempfile.NamedTemporaryFile().name)