+++ /dev/null
-import _hotshot\r
-import os.path\r
-import parser\r
-import symbol\r
-\r
-from _hotshot import \\r
- WHAT_ENTER, \\r
- WHAT_EXIT, \\r
- WHAT_LINENO, \\r
- WHAT_DEFINE_FILE, \\r
- WHAT_DEFINE_FUNC, \\r
- WHAT_ADD_INFO\r
-\r
-\r
-__all__ = ["LogReader", "ENTER", "EXIT", "LINE"]\r
-\r
-\r
-ENTER = WHAT_ENTER\r
-EXIT = WHAT_EXIT\r
-LINE = WHAT_LINENO\r
-\r
-\r
-class LogReader:\r
- def __init__(self, logfn):\r
- # fileno -> filename\r
- self._filemap = {}\r
- # (fileno, lineno) -> filename, funcname\r
- self._funcmap = {}\r
-\r
- self._reader = _hotshot.logreader(logfn)\r
- self._nextitem = self._reader.next\r
- self._info = self._reader.info\r
- if 'current-directory' in self._info:\r
- self.cwd = self._info['current-directory']\r
- else:\r
- self.cwd = None\r
-\r
- # This mirrors the call stack of the profiled code as the log\r
- # is read back in. It contains tuples of the form:\r
- #\r
- # (file name, line number of function def, function name)\r
- #\r
- self._stack = []\r
- self._append = self._stack.append\r
- self._pop = self._stack.pop\r
-\r
- def close(self):\r
- self._reader.close()\r
-\r
- def fileno(self):\r
- """Return the file descriptor of the log reader's log file."""\r
- return self._reader.fileno()\r
-\r
- def addinfo(self, key, value):\r
- """This method is called for each additional ADD_INFO record.\r
-\r
- This can be overridden by applications that want to receive\r
- these events. The default implementation does not need to be\r
- called by alternate implementations.\r
-\r
- The initial set of ADD_INFO records do not pass through this\r
- mechanism; this is only needed to receive notification when\r
- new values are added. Subclasses can inspect self._info after\r
- calling LogReader.__init__().\r
- """\r
- pass\r
-\r
- def get_filename(self, fileno):\r
- try:\r
- return self._filemap[fileno]\r
- except KeyError:\r
- raise ValueError, "unknown fileno"\r
-\r
- def get_filenames(self):\r
- return self._filemap.values()\r
-\r
- def get_fileno(self, filename):\r
- filename = os.path.normcase(os.path.normpath(filename))\r
- for fileno, name in self._filemap.items():\r
- if name == filename:\r
- return fileno\r
- raise ValueError, "unknown filename"\r
-\r
- def get_funcname(self, fileno, lineno):\r
- try:\r
- return self._funcmap[(fileno, lineno)]\r
- except KeyError:\r
- raise ValueError, "unknown function location"\r
-\r
- # Iteration support:\r
- # This adds an optional (& ignored) parameter to next() so that the\r
- # same bound method can be used as the __getitem__() method -- this\r
- # avoids using an additional method call which kills the performance.\r
-\r
- def next(self, index=0):\r
- while 1:\r
- # This call may raise StopIteration:\r
- what, tdelta, fileno, lineno = self._nextitem()\r
-\r
- # handle the most common cases first\r
-\r
- if what == WHAT_ENTER:\r
- filename, funcname = self._decode_location(fileno, lineno)\r
- t = (filename, lineno, funcname)\r
- self._append(t)\r
- return what, t, tdelta\r
-\r
- if what == WHAT_EXIT:\r
- try:\r
- return what, self._pop(), tdelta\r
- except IndexError:\r
- raise StopIteration\r
-\r
- if what == WHAT_LINENO:\r
- filename, firstlineno, funcname = self._stack[-1]\r
- return what, (filename, lineno, funcname), tdelta\r
-\r
- if what == WHAT_DEFINE_FILE:\r
- filename = os.path.normcase(os.path.normpath(tdelta))\r
- self._filemap[fileno] = filename\r
- elif what == WHAT_DEFINE_FUNC:\r
- filename = self._filemap[fileno]\r
- self._funcmap[(fileno, lineno)] = (filename, tdelta)\r
- elif what == WHAT_ADD_INFO:\r
- # value already loaded into self.info; call the\r
- # overridable addinfo() handler so higher-level code\r
- # can pick up the new value\r
- if tdelta == 'current-directory':\r
- self.cwd = lineno\r
- self.addinfo(tdelta, lineno)\r
- else:\r
- raise ValueError, "unknown event type"\r
-\r
- def __iter__(self):\r
- return self\r
-\r
- #\r
- # helpers\r
- #\r
-\r
- def _decode_location(self, fileno, lineno):\r
- try:\r
- return self._funcmap[(fileno, lineno)]\r
- except KeyError:\r
- #\r
- # This should only be needed when the log file does not\r
- # contain all the DEFINE_FUNC records needed to allow the\r
- # function name to be retrieved from the log file.\r
- #\r
- if self._loadfile(fileno):\r
- filename = funcname = None\r
- try:\r
- filename, funcname = self._funcmap[(fileno, lineno)]\r
- except KeyError:\r
- filename = self._filemap.get(fileno)\r
- funcname = None\r
- self._funcmap[(fileno, lineno)] = (filename, funcname)\r
- return filename, funcname\r
-\r
- def _loadfile(self, fileno):\r
- try:\r
- filename = self._filemap[fileno]\r
- except KeyError:\r
- print "Could not identify fileId", fileno\r
- return 1\r
- if filename is None:\r
- return 1\r
- absname = os.path.normcase(os.path.join(self.cwd, filename))\r
-\r
- try:\r
- fp = open(absname)\r
- except IOError:\r
- return\r
- st = parser.suite(fp.read())\r
- fp.close()\r
-\r
- # Scan the tree looking for def and lambda nodes, filling in\r
- # self._funcmap with all the available information.\r
- funcdef = symbol.funcdef\r
- lambdef = symbol.lambdef\r
-\r
- stack = [st.totuple(1)]\r
-\r
- while stack:\r
- tree = stack.pop()\r
- try:\r
- sym = tree[0]\r
- except (IndexError, TypeError):\r
- continue\r
- if sym == funcdef:\r
- self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]\r
- elif sym == lambdef:\r
- self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"\r
- stack.extend(list(tree[1:]))\r