PyXR

c:\python24\lib \ hotshot \ log.py



0001 import _hotshot
0002 import os.path
0003 import parser
0004 import symbol
0005 import sys
0006 
0007 from _hotshot import \
0008      WHAT_ENTER, \
0009      WHAT_EXIT, \
0010      WHAT_LINENO, \
0011      WHAT_DEFINE_FILE, \
0012      WHAT_DEFINE_FUNC, \
0013      WHAT_ADD_INFO
0014 
0015 
0016 __all__ = ["LogReader", "ENTER", "EXIT", "LINE"]
0017 
0018 
0019 ENTER = WHAT_ENTER
0020 EXIT  = WHAT_EXIT
0021 LINE  = WHAT_LINENO
0022 
0023 
0024 class LogReader:
0025     def __init__(self, logfn):
0026         # fileno -> filename
0027         self._filemap = {}
0028         # (fileno, lineno) -> filename, funcname
0029         self._funcmap = {}
0030 
0031         self._reader = _hotshot.logreader(logfn)
0032         self._nextitem = self._reader.next
0033         self._info = self._reader.info
0034         if self._info.has_key('current-directory'):
0035             self.cwd = self._info['current-directory']
0036         else:
0037             self.cwd = None
0038 
0039         # This mirrors the call stack of the profiled code as the log
0040         # is read back in.  It contains tuples of the form:
0041         #
0042         #   (file name, line number of function def, function name)
0043         #
0044         self._stack = []
0045         self._append = self._stack.append
0046         self._pop = self._stack.pop
0047 
0048     def close(self):
0049         self._reader.close()
0050 
0051     def fileno(self):
0052         """Return the file descriptor of the log reader's log file."""
0053         return self._reader.fileno()
0054 
0055     def addinfo(self, key, value):
0056         """This method is called for each additional ADD_INFO record.
0057 
0058         This can be overridden by applications that want to receive
0059         these events.  The default implementation does not need to be
0060         called by alternate implementations.
0061 
0062         The initial set of ADD_INFO records do not pass through this
0063         mechanism; this is only needed to receive notification when
0064         new values are added.  Subclasses can inspect self._info after
0065         calling LogReader.__init__().
0066         """
0067         pass
0068 
0069     def get_filename(self, fileno):
0070         try:
0071             return self._filemap[fileno]
0072         except KeyError:
0073             raise ValueError, "unknown fileno"
0074 
0075     def get_filenames(self):
0076         return self._filemap.values()
0077 
0078     def get_fileno(self, filename):
0079         filename = os.path.normcase(os.path.normpath(filename))
0080         for fileno, name in self._filemap.items():
0081             if name == filename:
0082                 return fileno
0083         raise ValueError, "unknown filename"
0084 
0085     def get_funcname(self, fileno, lineno):
0086         try:
0087             return self._funcmap[(fileno, lineno)]
0088         except KeyError:
0089             raise ValueError, "unknown function location"
0090 
0091     # Iteration support:
0092     # This adds an optional (& ignored) parameter to next() so that the
0093     # same bound method can be used as the __getitem__() method -- this
0094     # avoids using an additional method call which kills the performance.
0095 
0096     def next(self, index=0):
0097         while 1:
0098             # This call may raise StopIteration:
0099             what, tdelta, fileno, lineno = self._nextitem()
0100 
0101             # handle the most common cases first
0102 
0103             if what == WHAT_ENTER:
0104                 filename, funcname = self._decode_location(fileno, lineno)
0105                 t = (filename, lineno, funcname)
0106                 self._append(t)
0107                 return what, t, tdelta
0108 
0109             if what == WHAT_EXIT:
0110                 return what, self._pop(), tdelta
0111 
0112             if what == WHAT_LINENO:
0113                 filename, firstlineno, funcname = self._stack[-1]
0114                 return what, (filename, lineno, funcname), tdelta
0115 
0116             if what == WHAT_DEFINE_FILE:
0117                 filename = os.path.normcase(os.path.normpath(tdelta))
0118                 self._filemap[fileno] = filename
0119             elif what == WHAT_DEFINE_FUNC:
0120                 filename = self._filemap[fileno]
0121                 self._funcmap[(fileno, lineno)] = (filename, tdelta)
0122             elif what == WHAT_ADD_INFO:
0123                 # value already loaded into self.info; call the
0124                 # overridable addinfo() handler so higher-level code
0125                 # can pick up the new value
0126                 if tdelta == 'current-directory':
0127                     self.cwd = lineno
0128                 self.addinfo(tdelta, lineno)
0129             else:
0130                 raise ValueError, "unknown event type"
0131 
0132     def __iter__(self):
0133         return self
0134 
0135     #
0136     #  helpers
0137     #
0138 
0139     def _decode_location(self, fileno, lineno):
0140         try:
0141             return self._funcmap[(fileno, lineno)]
0142         except KeyError:
0143             #
0144             # This should only be needed when the log file does not
0145             # contain all the DEFINE_FUNC records needed to allow the
0146             # function name to be retrieved from the log file.
0147             #
0148             if self._loadfile(fileno):
0149                 filename = funcname = None
0150             try:
0151                 filename, funcname = self._funcmap[(fileno, lineno)]
0152             except KeyError:
0153                 filename = self._filemap.get(fileno)
0154                 funcname = None
0155                 self._funcmap[(fileno, lineno)] = (filename, funcname)
0156         return filename, funcname
0157 
0158     def _loadfile(self, fileno):
0159         try:
0160             filename = self._filemap[fileno]
0161         except KeyError:
0162             print "Could not identify fileId", fileno
0163             return 1
0164         if filename is None:
0165             return 1
0166         absname = os.path.normcase(os.path.join(self.cwd, filename))
0167 
0168         try:
0169             fp = open(absname)
0170         except IOError:
0171             return
0172         st = parser.suite(fp.read())
0173         fp.close()
0174 
0175         # Scan the tree looking for def and lambda nodes, filling in
0176         # self._funcmap with all the available information.
0177         funcdef = symbol.funcdef
0178         lambdef = symbol.lambdef
0179 
0180         stack = [st.totuple(1)]
0181 
0182         while stack:
0183             tree = stack.pop()
0184             try:
0185                 sym = tree[0]
0186             except (IndexError, TypeError):
0187                 continue
0188             if sym == funcdef:
0189                 self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]
0190             elif sym == lambdef:
0191                 self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"
0192             stack.extend(list(tree[1:]))
0193 

Generated by PyXR 0.9.4
SourceForge.net Logo