--[[--------------------------------------------------------------------
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
--