10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao"""Statistics analyzer for HotShot.""" 20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 30a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport profile 40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport pstats 50a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 60a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport hotshot.log 70a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 80a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom hotshot.log import ENTER, EXIT 90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 110a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef load(filename): 120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return StatsLoader(filename).load() 130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 150a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass StatsLoader: 160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, logfn): 170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._logfn = logfn 180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._code = {} 190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._stack = [] 200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.pop_frame = self._stack.pop 210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def load(self): 230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The timer selected by the profiler should never be used, so make 240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # sure it doesn't work: 250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = Profile() 260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p.get_time = _brokentimer 270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao log = hotshot.log.LogReader(self._logfn) 280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao taccum = 0 290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for event in log: 300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao what, (filename, lineno, funcname), tdelta = event 310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if tdelta > 0: 320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao taccum += tdelta 330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # We multiply taccum to convert from the microseconds we 350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # have to the seconds that the profile/pstats module work 360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # with; this allows the numbers to have some basis in 370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # reality (ignoring calibration issues for now). 380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if what == ENTER: 400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao frame = self.new_frame(filename, lineno, funcname) 410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p.trace_dispatch_call(frame, taccum * .000001) 420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao taccum = 0 430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao elif what == EXIT: 450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao frame = self.pop_frame() 460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p.trace_dispatch_return(frame, taccum * .000001) 470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao taccum = 0 480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # no further work for line events 500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert not self._stack 520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return pstats.Stats(p) 530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def new_frame(self, *args): 550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # args must be filename, firstlineno, funcname 560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # our code objects are cached since we don't need to create 570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # new ones every time 580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao code = self._code[args] 600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except KeyError: 610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao code = FakeCode(*args) 620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._code[args] = code 630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # frame objects are create fresh, since the back pointer will 640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # vary considerably 650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self._stack: 660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao back = self._stack[-1] 670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao back = None 690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao frame = FakeFrame(code, back) 700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._stack.append(frame) 710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return frame 720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 740a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass Profile(profile.Profile): 750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def simulate_cmd_complete(self): 760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 790a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass FakeCode: 800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, filename, firstlineno, funcname): 810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.co_filename = filename 820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.co_firstlineno = firstlineno 830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.co_name = self.__name__ = funcname 840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 860a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass FakeFrame: 870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, code, back): 880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.f_back = back 890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.f_code = code 900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 920a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef _brokentimer(): 930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise RuntimeError, "this timer should not be called" 94