python-2.5.2/win32/Lib/hotshot/log.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 import _hotshot
       
     2 import os.path
       
     3 import parser
       
     4 import symbol
       
     5 import sys
       
     6 
       
     7 from _hotshot import \
       
     8      WHAT_ENTER, \
       
     9      WHAT_EXIT, \
       
    10      WHAT_LINENO, \
       
    11      WHAT_DEFINE_FILE, \
       
    12      WHAT_DEFINE_FUNC, \
       
    13      WHAT_ADD_INFO
       
    14 
       
    15 
       
    16 __all__ = ["LogReader", "ENTER", "EXIT", "LINE"]
       
    17 
       
    18 
       
    19 ENTER = WHAT_ENTER
       
    20 EXIT  = WHAT_EXIT
       
    21 LINE  = WHAT_LINENO
       
    22 
       
    23 
       
    24 class LogReader:
       
    25     def __init__(self, logfn):
       
    26         # fileno -> filename
       
    27         self._filemap = {}
       
    28         # (fileno, lineno) -> filename, funcname
       
    29         self._funcmap = {}
       
    30 
       
    31         self._reader = _hotshot.logreader(logfn)
       
    32         self._nextitem = self._reader.next
       
    33         self._info = self._reader.info
       
    34         if self._info.has_key('current-directory'):
       
    35             self.cwd = self._info['current-directory']
       
    36         else:
       
    37             self.cwd = None
       
    38 
       
    39         # This mirrors the call stack of the profiled code as the log
       
    40         # is read back in.  It contains tuples of the form:
       
    41         #
       
    42         #   (file name, line number of function def, function name)
       
    43         #
       
    44         self._stack = []
       
    45         self._append = self._stack.append
       
    46         self._pop = self._stack.pop
       
    47 
       
    48     def close(self):
       
    49         self._reader.close()
       
    50 
       
    51     def fileno(self):
       
    52         """Return the file descriptor of the log reader's log file."""
       
    53         return self._reader.fileno()
       
    54 
       
    55     def addinfo(self, key, value):
       
    56         """This method is called for each additional ADD_INFO record.
       
    57 
       
    58         This can be overridden by applications that want to receive
       
    59         these events.  The default implementation does not need to be
       
    60         called by alternate implementations.
       
    61 
       
    62         The initial set of ADD_INFO records do not pass through this
       
    63         mechanism; this is only needed to receive notification when
       
    64         new values are added.  Subclasses can inspect self._info after
       
    65         calling LogReader.__init__().
       
    66         """
       
    67         pass
       
    68 
       
    69     def get_filename(self, fileno):
       
    70         try:
       
    71             return self._filemap[fileno]
       
    72         except KeyError:
       
    73             raise ValueError, "unknown fileno"
       
    74 
       
    75     def get_filenames(self):
       
    76         return self._filemap.values()
       
    77 
       
    78     def get_fileno(self, filename):
       
    79         filename = os.path.normcase(os.path.normpath(filename))
       
    80         for fileno, name in self._filemap.items():
       
    81             if name == filename:
       
    82                 return fileno
       
    83         raise ValueError, "unknown filename"
       
    84 
       
    85     def get_funcname(self, fileno, lineno):
       
    86         try:
       
    87             return self._funcmap[(fileno, lineno)]
       
    88         except KeyError:
       
    89             raise ValueError, "unknown function location"
       
    90 
       
    91     # Iteration support:
       
    92     # This adds an optional (& ignored) parameter to next() so that the
       
    93     # same bound method can be used as the __getitem__() method -- this
       
    94     # avoids using an additional method call which kills the performance.
       
    95 
       
    96     def next(self, index=0):
       
    97         while 1:
       
    98             # This call may raise StopIteration:
       
    99             what, tdelta, fileno, lineno = self._nextitem()
       
   100 
       
   101             # handle the most common cases first
       
   102 
       
   103             if what == WHAT_ENTER:
       
   104                 filename, funcname = self._decode_location(fileno, lineno)
       
   105                 t = (filename, lineno, funcname)
       
   106                 self._append(t)
       
   107                 return what, t, tdelta
       
   108 
       
   109             if what == WHAT_EXIT:
       
   110                 return what, self._pop(), tdelta
       
   111 
       
   112             if what == WHAT_LINENO:
       
   113                 filename, firstlineno, funcname = self._stack[-1]
       
   114                 return what, (filename, lineno, funcname), tdelta
       
   115 
       
   116             if what == WHAT_DEFINE_FILE:
       
   117                 filename = os.path.normcase(os.path.normpath(tdelta))
       
   118                 self._filemap[fileno] = filename
       
   119             elif what == WHAT_DEFINE_FUNC:
       
   120                 filename = self._filemap[fileno]
       
   121                 self._funcmap[(fileno, lineno)] = (filename, tdelta)
       
   122             elif what == WHAT_ADD_INFO:
       
   123                 # value already loaded into self.info; call the
       
   124                 # overridable addinfo() handler so higher-level code
       
   125                 # can pick up the new value
       
   126                 if tdelta == 'current-directory':
       
   127                     self.cwd = lineno
       
   128                 self.addinfo(tdelta, lineno)
       
   129             else:
       
   130                 raise ValueError, "unknown event type"
       
   131 
       
   132     def __iter__(self):
       
   133         return self
       
   134 
       
   135     #
       
   136     #  helpers
       
   137     #
       
   138 
       
   139     def _decode_location(self, fileno, lineno):
       
   140         try:
       
   141             return self._funcmap[(fileno, lineno)]
       
   142         except KeyError:
       
   143             #
       
   144             # This should only be needed when the log file does not
       
   145             # contain all the DEFINE_FUNC records needed to allow the
       
   146             # function name to be retrieved from the log file.
       
   147             #
       
   148             if self._loadfile(fileno):
       
   149                 filename = funcname = None
       
   150             try:
       
   151                 filename, funcname = self._funcmap[(fileno, lineno)]
       
   152             except KeyError:
       
   153                 filename = self._filemap.get(fileno)
       
   154                 funcname = None
       
   155                 self._funcmap[(fileno, lineno)] = (filename, funcname)
       
   156         return filename, funcname
       
   157 
       
   158     def _loadfile(self, fileno):
       
   159         try:
       
   160             filename = self._filemap[fileno]
       
   161         except KeyError:
       
   162             print "Could not identify fileId", fileno
       
   163             return 1
       
   164         if filename is None:
       
   165             return 1
       
   166         absname = os.path.normcase(os.path.join(self.cwd, filename))
       
   167 
       
   168         try:
       
   169             fp = open(absname)
       
   170         except IOError:
       
   171             return
       
   172         st = parser.suite(fp.read())
       
   173         fp.close()
       
   174 
       
   175         # Scan the tree looking for def and lambda nodes, filling in
       
   176         # self._funcmap with all the available information.
       
   177         funcdef = symbol.funcdef
       
   178         lambdef = symbol.lambdef
       
   179 
       
   180         stack = [st.totuple(1)]
       
   181 
       
   182         while stack:
       
   183             tree = stack.pop()
       
   184             try:
       
   185                 sym = tree[0]
       
   186             except (IndexError, TypeError):
       
   187                 continue
       
   188             if sym == funcdef:
       
   189                 self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]
       
   190             elif sym == lambdef:
       
   191                 self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"
       
   192             stack.extend(list(tree[1:]))