Profiler In Lua |
|
(It was written in about 12 minutes, so bear with me here. --Pedro)
Usage: call Profiler:activate()
to start measuring, Profiler:deactivate()
to stop, and then Profiler:print_results()
to see the results. Tweak the print function to your heart's desire to sort the way you want, etc.
Note that through overloading os.time()
with a non-ANSI, millisecond-precision function one can enhance the thing. But for my application seconds was good enough to spot the lines that were making time go quadratical instead of linear.
Also note that for now it can only measure line execution counts and times. One could extend it to call execution if necessary. Some preparations have been made, but not nearly enough.
--| Profiler module. --b "Pedro Miller Rabinovitch" <miller@inf.puc-rio.br> --$Id: prof.lua,v 1.4 2003/10/17 00:17:21 miller Exp $ --TODO add function call profiling. Some of the skeleton is already in --- place, but call profiling behaves different, so a couple of new --- functionalities must be added. --TODO add methods for proper result retrieval --TODO use optional clock() function for millisecond precision, if it's --- available local E, I = {}, {} --& Profiler module. Profiler = E --. Keeps track of the hit counts of each item E.counts = { line = {} } --. These should be inside the _line_ table above. E.last_line = nil E.last_time = os.time() E.started, E.ended = nil, nil --% Activates the profiling system. --@ [kind] (string) Optional hook kind. For now, only 'line' works, --- so just avoid it. >: ) function E:activate( kind ) kind = kind or 'line' local function hook_counter( hk_name, param,... ) local t = self.counts[hk_name][param] if t == nil then t = { count=0, time = 0 } self.counts[hk_name][param] = t end self.counts[hk_name][param].count = self.counts[hk_name][param].count + 1 if self.last_line then local delta = os.time() - self.last_time if delta > 0 then self.counts[hk_name][self.last_line].time = self.counts[hk_name][self.last_line].time + delta self.last_time = os.time() end end self.last_line = param end self.started = os.time() debug.sethook( hook_counter, kind ) end --% Deactivates the profiling system. --@ [kind] (string) Optional hook kind. For now, only 'line' works, --- so just avoid it. function E:deactivate( kind ) kind = kind or 'line' self.ended = os.time() debug.sethook( nil, kind ) end --% Prints the results. --@ [kind] (string) Optional hook... Aah, you got it by now. --TODO add print output formatting and sorting function E:print_results( kind ) kind = kind or 'line' print( kind, 'count', 'approx. time (s)' ) print( '----', '-----', '----------------' ) for i,v in pairs( self.counts[kind] ) do print( i, v.count, v.time ) end print( self.ended - self.started, ' second(s) total (approximately).' ) end