--[[-------------------------------------------------------------------- Ovale Spell Priority Copyright (C) 2014 Johnny C. Lam This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License in the LICENSE file accompanying this program. --]]-------------------------------------------------------------------- --[[ Every time a new function is entered and exited, debugprofilestop() is called and the time between the two timestamps is calculated and attributed to that function. --]] local _, Ovale = ... local Profiler = {} Ovale.Profiler = Profiler -- local debugprofilestop = debugprofilestop local format = string.format local tinsert = table.insert local tsort = table.sort local API_GetTime = GetTime local self_timestamp = debugprofilestop() local self_stack = {} local self_stackSize = 0 local self_timeSpent = {} local self_timesInvoked = {} -- Profiling methods collections, indexed by group. local self_profiler = {} -- -- local function DoNothing() -- no-op end local function StartProfiler(tag) local newTimestamp = debugprofilestop() -- Attribute the time spent up to this call to the previous function. if self_stackSize > 0 then local delta = newTimestamp - self_timestamp local previous = self_stack[self_stackSize] local timeSpent = self_timeSpent[previous] or 0 timeSpent = timeSpent + delta self_timeSpent[previous] = timeSpent end -- Add the current function to the call stack. self_timestamp = newTimestamp self_stackSize = self_stackSize + 1 self_stack[self_stackSize] = tag do local timesInvoked = self_timesInvoked[tag] or 0 timesInvoked = timesInvoked + 1 self_timesInvoked[tag] = timesInvoked end end local function StopProfiler(tag) if self_stackSize > 0 then local currentTag = self_stack[self_stackSize] if currentTag == tag then local newTimestamp = debugprofilestop() local delta = newTimestamp - self_timestamp local timeSpent = self_timeSpent[currentTag] or 0 timeSpent = timeSpent + delta self_timeSpent[currentTag] = timeSpent self_timestamp = newTimestamp self_stackSize = self_stackSize - 1 end end end -- -- function Profiler:RegisterProfilingGroup(group, enableFunction, disableFunction) local profiler = self_profiler[group] or {} profiler.Enable = enableFunction profiler.Disable = disableFunction self_profiler[group] = profiler self:Disable(group, false) end function Profiler:GetProfilingGroup(group) return self_profiler[group] end function Profiler:Enable(group, isVerbose) if group then local profiler = self_profiler[group] if profiler then if isVerbose then Ovale:FormatPrint("Profiling for %s is enabled.", group) end if profiler.Enable then profiler.Enable() end profiler.Start = StartProfiler profiler.Stop = StopProfiler end else for group, profiler in pairs(self_profiler) do if isVerbose then Ovale:FormatPrint("Profiling for %s is enabled.", group) end if profiler.Enable then profiler.Enable() end profiler.Start = StartProfiler profiler.Stop = StopProfiler end end end function Profiler:Disable(group, isVerbose) if group then local profiler = self_profiler[group] if profiler then if isVerbose then Ovale:FormatPrint("Profiling for %s is disabled.", group) end if profiler.Disable then profiler.Disable() end profiler.Start = DoNothing profiler.Stop = DoNothing end else for group, profiler in pairs(self_profiler) do if isVerbose then Ovale:FormatPrint("Profiling for %s is disabled.", group) end if profiler.Disable then profiler.Disable() end profiler.Start = DoNothing profiler.Stop = DoNothing end end end function Profiler:Reset() for tag in pairs(self_timeSpent) do self_timeSpent[tag] = nil end for tag in pairs(self_timesInvoked) do self_timesInvoked[tag] = nil end end do local array = {} function Profiler:Info() if next(self_timeSpent) then local now = API_GetTime() Ovale:FormatPrint("Profiling statistics at %f:", now) -- Calculate the width needed to print out the times invoked. local width = 1 do local tenPower = 10 for _, timesInvoked in pairs(self_timesInvoked) do while timesInvoked > tenPower do width = width + 1 tenPower = tenPower * 10 end end end wipe(array) local formatString = format(" %%08.3fms: %%0%dd (%%05f) x %%s", width) for tag, timeSpent in pairs(self_timeSpent) do local timesInvoked = self_timesInvoked[tag] tinsert(array, format(formatString, timeSpent, timesInvoked, timeSpent / timesInvoked, tag)) end if next(array) then tsort(array) for _, v in ipairs(array) do Ovale:Print(v) end end end end end function Profiler:Wrap(group, tag, functionPtr) local profiler = self_profiler[group] local helper = function(...) profiler.Stop(tag) return ... end local wrapper = function(...) profiler.Start(tag) return helper(functionPtr(...)) end return wrapper end function Profiler:Debug() Ovale:FormatPrint("Profiler stack size = %d", self_stackSize) local index = self_stackSize while index > 0 and self_stackSize - index < 10 do local tag = self_stack[index] Ovale:FormatPrint(" [%d] %s", index, tag) index = index - 1 end end --