| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  | import _hotshot | 
					
						
							|  |  |  | import os.path | 
					
						
							|  |  |  | import parser | 
					
						
							|  |  |  | import symbol | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from _hotshot import \ | 
					
						
							|  |  |  |      WHAT_ENTER, \ | 
					
						
							|  |  |  |      WHAT_EXIT, \ | 
					
						
							|  |  |  |      WHAT_LINENO, \ | 
					
						
							|  |  |  |      WHAT_DEFINE_FILE, \ | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |      WHAT_DEFINE_FUNC, \ | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  |      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 = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-13 02:55:40 +00:00
										 |  |  |         self._reader = _hotshot.logreader(logfn) | 
					
						
							| 
									
										
										
										
											2007-04-21 15:47:16 +00:00
										 |  |  |         self._nextitem = self._reader.__next__ | 
					
						
							| 
									
										
										
										
											2001-10-29 20:57:23 +00:00
										 |  |  |         self._info = self._reader.info | 
					
						
							| 
									
										
										
										
											2006-08-19 16:17:20 +00:00
										 |  |  |         if 'current-directory' in self._info: | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |             self.cwd = self._info['current-directory'] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.cwd = None | 
					
						
							| 
									
										
										
										
											2002-05-29 19:40:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # 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) | 
					
						
							|  |  |  |         # | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  |         self._stack = [] | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |         self._append = self._stack.append | 
					
						
							|  |  |  |         self._pop = self._stack.pop | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 14:54:28 +00:00
										 |  |  |     def close(self): | 
					
						
							|  |  |  |         self._reader.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 19:17:20 +00:00
										 |  |  |     def fileno(self): | 
					
						
							|  |  |  |         """Return the file descriptor of the log reader's log file.""" | 
					
						
							|  |  |  |         return self._reader.fileno() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-29 20:57:23 +00:00
										 |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |     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" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  |     # 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-21 15:47:16 +00:00
										 |  |  |     def __next__(self, index=0): | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |         while 1: | 
					
						
							| 
									
										
										
										
											2002-07-18 19:48:46 +00:00
										 |  |  |             # This call may raise StopIteration: | 
					
						
							| 
									
										
										
										
											2002-07-18 19:20:23 +00:00
										 |  |  |             what, tdelta, fileno, lineno = self._nextitem() | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # handle the most common cases first | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if what == WHAT_ENTER: | 
					
						
							|  |  |  |                 filename, funcname = self._decode_location(fileno, lineno) | 
					
						
							| 
									
										
										
										
											2002-05-29 19:40:36 +00:00
										 |  |  |                 t = (filename, lineno, funcname) | 
					
						
							|  |  |  |                 self._append(t) | 
					
						
							|  |  |  |                 return what, t, tdelta | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if what == WHAT_EXIT: | 
					
						
							| 
									
										
										
										
											2002-05-29 19:40:36 +00:00
										 |  |  |                 return what, self._pop(), tdelta | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if what == WHAT_LINENO: | 
					
						
							| 
									
										
										
										
											2002-05-29 19:40:36 +00:00
										 |  |  |                 filename, firstlineno, funcname = self._stack[-1] | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |                 return what, (filename, lineno, funcname), tdelta | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |             if what == WHAT_DEFINE_FILE: | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |                 filename = os.path.normcase(os.path.normpath(tdelta)) | 
					
						
							|  |  |  |                 self._filemap[fileno] = filename | 
					
						
							|  |  |  |             elif what == WHAT_DEFINE_FUNC: | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |                 filename = self._filemap[fileno] | 
					
						
							|  |  |  |                 self._funcmap[(fileno, lineno)] = (filename, tdelta) | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |             elif what == WHAT_ADD_INFO: | 
					
						
							| 
									
										
										
										
											2001-10-29 20:57:23 +00:00
										 |  |  |                 # value already loaded into self.info; call the | 
					
						
							|  |  |  |                 # overridable addinfo() handler so higher-level code | 
					
						
							|  |  |  |                 # can pick up the new value | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |                 if tdelta == 'current-directory': | 
					
						
							|  |  |  |                     self.cwd = lineno | 
					
						
							| 
									
										
										
										
											2001-10-29 20:57:23 +00:00
										 |  |  |                 self.addinfo(tdelta, lineno) | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2002-03-12 14:26:37 +00:00
										 |  |  |                 raise ValueError, "unknown event type" | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 14:33:14 +00:00
										 |  |  |     def __iter__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     #  helpers | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _decode_location(self, fileno, lineno): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return self._funcmap[(fileno, lineno)] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							| 
									
										
										
										
											2001-10-15 22:05:32 +00:00
										 |  |  |             # | 
					
						
							|  |  |  |             # 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. | 
					
						
							|  |  |  |             # | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  |             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: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("Could not identify fileId", fileno) | 
					
						
							| 
									
										
										
										
											2001-10-12 20:56:29 +00:00
										 |  |  |             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:])) |