Skip to content

Commit

Permalink
Merge branch 'release/1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
dualcoding committed Sep 10, 2017
2 parents 2ce75f4 + d03b022 commit c136d2c
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 95 deletions.
2 changes: 1 addition & 1 deletion !Profiler.toc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Interface: 70200
## Interface: 70300
## Title: !Profiler
## Notes: Find out what addons are slowing you down.
## Author: dualcoding
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ A profiler for WoW addons that tries to go deeper.
Find out which addons...
- Are increasing your startup times the most.
- Have the heaviest CPU-cost while the game is running.
- (not yet) ~~Causes the most frequent and heaviest CPU spikes.~~

## For developers
Shows the total CPU used and times called for all found functions in the global namespace and groups them by addon structure.
Expand All @@ -17,7 +16,7 @@ There is not much that can be done to track locals automatically, but addon auth

As an experimental feature, the Profiler can try to find out callers to functions. This is currently done with plain brute force by hooking the function, throwing an error and parsing the debugstack. As you might expect this is far too heavyweight to do automatically. The recommended approach is to do the following in your source:

local cache = profilingcache or function(f) return f end
local cache = profilingmonitor or function(f) return f end
local CreateFrame = cache(_G.CreateFrame)

There will be support for figuring out _where_ in a function the time is spent in the future that will work much like debugging prints - there is no reasonable way to do this automatically.
Expand Down
6 changes: 3 additions & 3 deletions src/callers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local OUR_NAME, profiler = ...


profiler.callers = {}
function profilingcache(fun, secure)
function profilingmonitor(fun, secure)
local cached = profiler.callers[fun]
if not cached then
cached = {
Expand Down Expand Up @@ -58,10 +58,10 @@ function profiler.hook(t, name)
local func = t[name]
local hookfunc
if issecurevariable(t, name) then
hookfunc = cache(func, true)
hookfunc = profilingmonitor(func, true)
hooksecurefunc(t, name, hookfunc)
else
hookfunc = cache(func)
hookfunc = profilingmonitor(func)
t[name] = hookfunc
end
profiler.hooks[hookfunc] = func
Expand Down
4 changes: 2 additions & 2 deletions src/eventhandlers.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local OUR_NAME, profiler = ...

local CreateFrame = profilingcache(_G.CreateFrame)
local CreateFrame = profilingmonitor(_G.CreateFrame)

function profiler.isFirstAddonLoaded()
-- Are any other addons loaded?
Expand All @@ -26,7 +26,7 @@ profiler.events = {
if addon_name==OUR_NAME then
-- We were loaded
if not profiler.isFirstAddonLoaded() then
error(OUR_NAME, "was not loaded first")
error(OUR_NAME.." was not loaded first, this will likely lead to attributing functions to the wrong addons.")
end

-- Start listening for new globals
Expand Down
9 changes: 0 additions & 9 deletions src/sort.lua

This file was deleted.

88 changes: 29 additions & 59 deletions src/times.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,97 +26,67 @@ function profiler.freezeStartup()
for i=1,#ns do
local x = ns[i]
x.startup = x.cpu
x.startupp = x.cpup
stack[#stack+1] = x.namespace
end
ns = table.remove(stack)
until not ns
end


function profiler.updateTimes(namespace, sortby, includeSubroutines)
function profiler.updateTimes(namespace, sortby)
if namespace==profiler.namespaces then
UpdateAddOnCPUUsage()
UpdateAddOnMemoryUsage()
end
local totalCPU = 0
local totalCPUp = 0
local totalMem = 0
if type(namespace)=="function" then
return GetFunctionCPUUsage(namespace, includeSubroutines)
local cpu, ncalls = GetFunctionCPUUsage(namespace, false)
local cpup = GetFunctionCPUUsage(namespace, true)
return cpu, cpup
end
for i=1,#namespace do
local x = namespace[i]
if x.type=="addon" then
x.cpu = GetAddOnCPUUsage(x.name)
local mem = GetAddOnMemoryUsage(x.name)
local now = debugprofilestop()
local dt = now - (x.updated or 0)
x.memlast = x.mem
x.mem = mem
x.memdiff = mem - x.memlast
x.memdiff = (mem - x.memlast)/(dt/1000)
elseif x.type=="function" then
x.cpu, x.ncalls = GetFunctionCPUUsage(x.fun, includeSubroutines)
x.cpu, x.ncalls = GetFunctionCPUUsage(x.fun, false)
x.cpup = GetFunctionCPUUsage(x.fun, true)
elseif x.type=="table" then
x.cpu = profiler.updateTimes(x.namespace, sortby, includeSubroutines)
x.cpu, x.cpup = profiler.updateTimes(x.namespace, sortby)
end
local oldtime = x.updated or debugprofilestop()
local oldupdatecpu = x.updatecpu or 0
local oldupdatecpup = x.updatecpup or 0
x.updated = debugprofilestop()
x.updatecpu = x.cpu - (x.startup or 0)
x.updatecpup = (x.cpup or x.cpu) - (x.startupp or x.startup or 0)
x.updatecpudiff = (x.updatecpu - oldupdatecpu)/(x.updated-oldtime)
x.updatecpupdiff = (x.updatecpup - oldupdatecpup)/(x.updated-oldtime)

totalCPU = totalCPU + x.cpu
totalCPUp = totalCPUp + (x.cpup or x.cpu)
totalMem = totalMem + (x.mem or 0)
end

sortby = sortby or "startup"

local function sort(t, fun)
-- Sorting tables first ended up being too much scrolling
--return table.sort(t, function(a,b)
-- if a.type=="table" and b.type~="table" then return true
-- elseif a.type~="table" and b.type=="table" then return false
-- end
-- return fun(a,b)
--end)
return table.sort(t, fun)
end

if sortby=="cpu" then
sort(namespace, function(a,b)
if a.cpu==b.cpu then
return a.name<b.name
else
return a.cpu>b.cpu
end
end)
elseif sortby=="name" then
sort(namespace, function(a,b)
table.sort(namespace, function(a,b)
if a[sortby]==b[sortby] then
return a.name<b.name
end)
--elseif sortby=="mem" then
elseif sortby=="ncalls" then
sort(namespace, function(a,b)
acalls = a.ncalls or a.memdiff or 0
bcalls = b.ncalls or b.memdiff or 0
if acalls==bcalls then
return a.name<b.name
else
return acalls>bcalls
end
end)
elseif sortby=="startup" then
sort(namespace, function(a,b)
a.startup = a.startup or 0
b.startup = b.startup or 0
if a.startup==b.startup then
if a.name and b.name then
return a.name<b.name
end
else
return a.startup>b.startup
end
end)
elseif sortby=="updatecpu" then
sort(namespace, function(a,b)
if a.updatecpu == b.updatecpu then
return a.name<b.name
end
return a.updatecpu>b.updatecpu
end)
end
return totalCPU, totalMem
else
if sortby=="name" then return a.name<b.name end
return (a[sortby] or 0) > (b[sortby] or 0)
end
end)

return totalCPU, totalCPUp, totalMem
end
Loading

0 comments on commit c136d2c

Please sign in to comment.