Remove your OnUpdate handler when you don't need it
I'm extremely new to WoW addons and Lua. Coming from an OO background I've made all the mistakes someone like myself is probably expected to make. Especially in how I use tables.
Recently I started to tackle what I felt was excessive CPU usage for a relatively simple addon (FullThrottle)
I've read all the threads I could find during this process. Here were some useful ones to list a few:
It was easy for me to get caught up in the notion that my use of tables, strings, globals, etc. was where I needed to optimize. Truth be told, Lua is pretty damn well optimized on it's own. I gained very little (hardly measurable with the tools I was using) trying to optimize my code using the kinds of techniques in those threads.
My addon has bars with textures that change width based on the time left on a spell. I also have text values that change. A bar is essentially either active (texture width and font is changing) or it's not. Besides throttling the OnUpdate handler, I also tried to be smart and check right away if I even needed to do any changes to the bar. But I was still handling OnUpdate.
As soon as I changed my code so that when a bar is not active I unregister the OnUpdate script, I saved ~40% CPU usage.
I'm simplifying what I had to do quite a bit, but that's essentially what was done.
Just because you sometimes need to do some sort of animation, doesn't mean you ALWAYS need to be running OnUpdate code. Even a throttled down OnUpdate handler is consuming resources.
That's all I got :)
Also, thanks to everyone here for all the great historical posts and for helping people like me. This is a lot of fun!
if you are doing any sort of Animation you should be using the Blizzard animation framework instead of an OnUpdate it will simplify things and be potentially even more CPU friendly since you are moving some calculations into C
I'm new to coding altogether... Would this be important if I'm working on a mod that has an fps display? If I understood correctly, I use a 1 second interval to check fps: PERFORMANCEBAR_UPDATE_INTERVAL, which is the variable Blizz assigned to check performance on their MicroMenu. So this little text display of performance is using 100k, but it seems like that's alot to me. What do you think? If it's important, how would I do it?
It looks like:
function TS:containerEnable()
local nextUpdate = updateInterval
TS.container:SetScript("OnUpdate", function(self, elapsed)
if (nextUpdate < 0) then
nextUpdate = updateInterval
self:UpdateText()
else
nextUpdate = nextUpdate - elapsed
end
end)
end
Does this need improvement? The latency and other text updates are also in UpdateText function, and I was thinking of splitting them up because latency only updates every 30 seconds anyway, but then I thought maybe I'd just be making two timers instead of one. Better together or apart?
if you are doing any sort of Animation you should be using the Blizzard animation framework instead of an OnUpdate it will simplify things and be potentially even more CPU friendly since you are moving some calculations into C
I'm kinda new to this whole thing, but I'd surely like to learn :) What do you mean by "Blizzard animation framework"? Any sort of hint would be nice, I'm not afraid to dig around, but that's an expression I've heard for the first time...
I wrote a little buff-addon for myself, to play with the new SecureAura header as well as the animation system (for fading icons and also for timer). Now I did some CPU-profiling and although it's hard to get anything useful from it since I didn't have anything to compare it too (eg, is ~2.5 cpu/sec, as reported by AddonProfiler, too much?) I noticed that when I played an animation there would be quite a jump in CPU-usage at first and then it would drop down again just as fast. Has anyone else noticed something similar?
I used the term "animation" loosely. Blizz's animation doesn't have an object for changing the width of something, only scale, alpha, position, and I think one more. In my case, I need to countdown a text value and change the width of a texture, neither of which can be controlled with regular events such as UNIT_AURA, etc.
Are there other tools for this I should be looking at?
Well, you can use the animation-system to mimic a timer, sort of like this:
local timerGroup = frame:CreateAnimationGroup()
local timer = timerGroup:CreateAnimation()
timer:SetOrder(1)
timer:SetDuration(1) -- how often you want it to finish
timer:SetMaxFramerate(25) -- use this to throttle
timerGroup:SetScript("OnFinished", function(self, requested)
self:Play() -- start it over again
DoStuff()
end)
So, the most efficient way to make a group of bars that are timers for buffs/debuffs that can be refreshed/dispelled/etc would be to make a frame, create an animation group for it and add an animation for each bar. On timer start, I'd start the animation with the correct length and set the bar, and then I'd use the OnUpdate script of the animation to check if I need to change the bar. The same would be for a text-countdown. Did I get this right?
I don't claim to know which method is "better" (throttle OnUpdate or use Animations). But I do know that I update my bar widths and duration text every 0.1 seconds. This would mean I'd need to replay a timer every 0.1 seconds. That's a little bit concerning, and it's not the pattern I see most addons using. It's either that or throttle the OnUpdate on an animation like Alakabaster is talking about, which would seem to defeat the purpose, no?
As it stands now, I am able to use UNIT_AURA events to decide whether I need to set or unset an OnUpdate function.
I understand that the Blizz animations are handled in C code but it doesn't seem like the appropriate tool in my scenario. I've not tried it though.
Incidentally, in regard to updating the width of the bar, I did implement one improvement that was noticeable:
function FullThrottle:RefreshActiveAnimations(bar)
...
local duration = group.Expiration - GetTime()
local width = (duration / group.FullDuration) * bar.width
if(ceil(bar.texture:GetWidth()) ~= ceil(width)) then
bar.texture:SetWidth(width)
end
...
end
Essentially, it's always comparing whole numbers and therefore only changes if the number went from say 250 to 249. For very large values of duration, this means the texture only changes widths every 20 seconds or so.
As opposed to...
function FullThrottle:RefreshActiveAnimations(bar)
...
local duration = group.Expiration - GetTime()
local width = (duration / group.FullDuration) * db.Width
bar.texture:SetWidth(width)
...
end
Where the numbers will be more like 250.0043123 and 249.999234
Or even less obvious, but the same problem...
function FullThrottle:RefreshActiveAnimations(bar)
...
local duration = group.Expiration - GetTime()
local width = (duration / group.FullDuration) * db.Width
if(bar.texture:GetWidth() ~= width) then
bar.texture:SetWidth(width)
end
...
end
In the last case, width will never equal bar.texture:GetWidth() because they're both floating numbers, so it's a wasted check.
I added similar "only if changed" checks for SetText() of the timer text but the differences weren't as apparent as the texture width checks.
Just a side note that monitoring UNIT_AURA to set / unset OnUpdate is not always cheaper than a throttled OnUpdate to begin with.
It would be true when solo but in a raid environment UNIT_AURA can fire exceptionally spammy
(many more times than a throttled OnUpdate would since that is a fixed interval you have picked)
Essentially using the OnUpdate would give you a more or less steady performance hit,
UNIT_AURA will vary greatly with environment.
Except that in the second case, an extra 4 bytes is allocated for the file scope variable "onUpdate", and you can set this same function to multiple frames' OnUpdate easily should more than 1 frame need it.
Except that in the second case, an extra 4 bytes is allocated for the file scope variable "onUpdate", and you can set this same function to multiple frames' OnUpdate easily should more than 1 frame need it.
Either way a function is made. Would it not use the same amount of memory both ways?
The function itself is the same, compiled to some location in memory.
But the second example essentially has a "function/chunk-scope" variable reference to it while it is executing which is on the stack. Once the function or chunk finishes execution, if no closure references the "onUpdate" variable, execution returns to the caller and the stack gets cleaned.
If a closure still references the "onUpdate" variable as an upvalue, then the variable gets moved from the stack to the heap when the function/chunk returns to the caller. Future references to the upvalue then costs a memory indirection.
In the first example, there wasn't an explicit variable reference to the function, so the function reference as passed into SetScript() was just a intermediate throwaway result in some register.
Those findings are interesting, but possibly a little misleading.
If I understand the testing methodology correctly, this only tells us how much CPU time is spent in the (testing) addon's own Lua code. So of course offloading the timing mechanism to the game client's animation system will reduce the Lua code's apparent CPU usage, but it comes at the cost of increasing the animation system's CPU usage, even if we can't measure that directly.
It's probably safe to say that the animation system can do the work more efficiently than Lua, but this doesn't measure that at all, so calling it a straight-up "2000% performance increase" is a stretch, I think.
Presumably the reason we care about CPU usage is to reduce CPU load in order to improve framerate, so what we really need is a test that measures average framerate under a heavy load of timers using each of these mechanisms. But since framerate varies quite a lot second-to-second anyway, I'm not sure what kind of data we'd need to show a conclusive benefit, and measure the size of that benefit.
On the other hand if all you care about is making your addon look better in the Lua profiler by hiding the timing overhead in the animation system instead, then these results are useful. :)
He is also using WoWs own benchmarking system, which is somewhat flawed, and adds a serious overhead itself on function calls, which makes OnUpdate look even worse.
Just a side note that monitoring UNIT_AURA to set / unset OnUpdate is not always cheaper than a throttled OnUpdate to begin with.
It would be true when solo but in a raid environment UNIT_AURA can fire exceptionally spammy
(many more times than a throttled OnUpdate would since that is a fixed interval you have picked)
Essentially using the OnUpdate would give you a more or less steady performance hit,
UNIT_AURA will vary greatly with environment.
I wanted to come back and bump this thread to acknowledge that Dridzt was correct in his thoughts about actual performance. While I still am able to see improvements, it was no where along the lones of 40%. Probably more like 5% truth be told. It's not really possible to reproduce the same exact situation.
I still have confidence that it was a good decision. Mainly, I already have to hook into UNIT_AURA for other events so I can't avoid it entirely
Thanks again everyone for the latter posts.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
I'm extremely new to WoW addons and Lua. Coming from an OO background I've made all the mistakes someone like myself is probably expected to make. Especially in how I use tables.
Recently I started to tackle what I felt was excessive CPU usage for a relatively simple addon (FullThrottle)
I've read all the threads I could find during this process. Here were some useful ones to list a few:
http://forums.wowace.com/showthread.php?t=18163
http://old.wowace.com/wiki/Coding_Tips#Function_syntactical_sugar
http://forums.wowace.com/showthread.php?t=17301
It was easy for me to get caught up in the notion that my use of tables, strings, globals, etc. was where I needed to optimize. Truth be told, Lua is pretty damn well optimized on it's own. I gained very little (hardly measurable with the tools I was using) trying to optimize my code using the kinds of techniques in those threads.
My addon has bars with textures that change width based on the time left on a spell. I also have text values that change. A bar is essentially either active (texture width and font is changing) or it's not. Besides throttling the OnUpdate handler, I also tried to be smart and check right away if I even needed to do any changes to the bar. But I was still handling OnUpdate.
As soon as I changed my code so that when a bar is not active I unregister the OnUpdate script, I saved ~40% CPU usage.
I'm simplifying what I had to do quite a bit, but that's essentially what was done.
Just because you sometimes need to do some sort of animation, doesn't mean you ALWAYS need to be running OnUpdate code. Even a throttled down OnUpdate handler is consuming resources.
That's all I got :)
Also, thanks to everyone here for all the great historical posts and for helping people like me. This is a lot of fun!
It looks like:
Does this need improvement? The latency and other text updates are also in UpdateText function, and I was thinking of splitting them up because latency only updates every 30 seconds anyway, but then I thought maybe I'd just be making two timers instead of one. Better together or apart?
I'm kinda new to this whole thing, but I'd surely like to learn :) What do you mean by "Blizzard animation framework"? Any sort of hint would be nice, I'm not afraid to dig around, but that's an expression I've heard for the first time...
Are there other tools for this I should be looking at?
As it stands now, I am able to use UNIT_AURA events to decide whether I need to set or unset an OnUpdate function.
I understand that the Blizz animations are handled in C code but it doesn't seem like the appropriate tool in my scenario. I've not tried it though.
Incidentally, in regard to updating the width of the bar, I did implement one improvement that was noticeable:
Essentially, it's always comparing whole numbers and therefore only changes if the number went from say 250 to 249. For very large values of duration, this means the texture only changes widths every 20 seconds or so.
As opposed to...
Where the numbers will be more like 250.0043123 and 249.999234
Or even less obvious, but the same problem...
In the last case, width will never equal bar.texture:GetWidth() because they're both floating numbers, so it's a wasted check.
I added similar "only if changed" checks for SetText() of the timer text but the differences weren't as apparent as the texture width checks.
It would be true when solo but in a raid environment UNIT_AURA can fire exceptionally spammy
(many more times than a throttled OnUpdate would since that is a fixed interval you have picked)
Essentially using the OnUpdate would give you a more or less steady performance hit,
UNIT_AURA will vary greatly with environment.
?
Except that in the second case, an extra 4 bytes is allocated for the file scope variable "onUpdate", and you can set this same function to multiple frames' OnUpdate easily should more than 1 frame need it.
Either way a function is made. Would it not use the same amount of memory both ways?
But the second example essentially has a "function/chunk-scope" variable reference to it while it is executing which is on the stack. Once the function or chunk finishes execution, if no closure references the "onUpdate" variable, execution returns to the caller and the stack gets cleaned.
If a closure still references the "onUpdate" variable as an upvalue, then the variable gets moved from the stack to the heap when the function/chunk returns to the caller. Future references to the upvalue then costs a memory indirection.
In the first example, there wasn't an explicit variable reference to the function, so the function reference as passed into SetScript() was just a intermediate throwaway result in some register.
http://forums.worldofwarcraft.com/thread.html?topicId=26723614545&postId=267208819134&sid=1#15
Those findings are interesting, but possibly a little misleading.
If I understand the testing methodology correctly, this only tells us how much CPU time is spent in the (testing) addon's own Lua code. So of course offloading the timing mechanism to the game client's animation system will reduce the Lua code's apparent CPU usage, but it comes at the cost of increasing the animation system's CPU usage, even if we can't measure that directly.
It's probably safe to say that the animation system can do the work more efficiently than Lua, but this doesn't measure that at all, so calling it a straight-up "2000% performance increase" is a stretch, I think.
Presumably the reason we care about CPU usage is to reduce CPU load in order to improve framerate, so what we really need is a test that measures average framerate under a heavy load of timers using each of these mechanisms. But since framerate varies quite a lot second-to-second anyway, I'm not sure what kind of data we'd need to show a conclusive benefit, and measure the size of that benefit.
On the other hand if all you care about is making your addon look better in the Lua profiler by hiding the timing overhead in the animation system instead, then these results are useful. :)
I wanted to come back and bump this thread to acknowledge that Dridzt was correct in his thoughts about actual performance. While I still am able to see improvements, it was no where along the lones of 40%. Probably more like 5% truth be told. It's not really possible to reproduce the same exact situation.
I still have confidence that it was a good decision. Mainly, I already have to hook into UNIT_AURA for other events so I can't avoid it entirely
Thanks again everyone for the latter posts.