diff options
author | rahulp13 | 2020-03-17 14:55:41 +0530 |
---|---|---|
committer | rahulp13 | 2020-03-17 14:55:41 +0530 |
commit | 296443137f4288cb030e92859ccfbe3204bc1088 (patch) | |
tree | ca4798c2da1e7244edc3bc108d81b462b537aea2 /lib/python2.7/hotshot | |
parent | 0db48f6533517ecebfd9f0693f89deca28408b76 (diff) | |
download | KiCad-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__.py | 78 | ||||
-rw-r--r-- | lib/python2.7/hotshot/log.py | 194 | ||||
-rw-r--r-- | lib/python2.7/hotshot/stats.py | 93 | ||||
-rw-r--r-- | lib/python2.7/hotshot/stones.py | 30 |
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) |