mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 47cada7ab8
			
		
	
	
		47cada7ab8
		
	
	
	
	
		
			
			hotshot.stats.load(logfilename) returns a pstats.Stats instance, which is about as compatible as it gets.
		
			
				
	
	
		
			93 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """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"
 |