Thread Tools Display Modes
01-18-12, 06:00 AM   #1
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
OnUpdate efficiency

Hello!

I use an OnUpdate script to display fps/latency/hour+minutes in my UI. It updates every second, mainly for the fps.

I was wondering though. Considering latency is only updated every 10 seconds, and there is no use in getting for the time every second when it only updates every minute, would it be more efficient to use 3 separate OnUpdate loops - one which updates the hour/minute value every 30 secs, one which updates the latency every 10 secs, and one which handles the fps as well as displaying the other values - or should I stick to just 1?

The difference is minimal, of course, it's mostly a matter of principle.

Thanks!
  Reply With Quote
01-18-12, 07:04 AM   #2
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
So either one update that runs a function or two updates running two separate functions, good question.

Oh, I just wish you could make onupdate scripts and specify the update interval when you set the script on the widget, think it would be more performance friendly like in scenarios like this yes? Having a bunch of variables to count in order to track the time elapsed, too many of those and you get impact on performance... oh sorry off topic!
  Reply With Quote
01-18-12, 07:55 AM   #3
Barjack
A Black Drake
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 89
My intuition would be that function call overhead makes a single OnUpdate function (marginally) more efficient--though I haven't actually tested this.

But since OnUpdate scripts on visible frames are called once per frame regardless of whether or not your condition in that function evaluates true or false, the result in either case is 3 mathematical operations per frame (adding time elapsed to a "time since last update" for each type of thing), 3 comparisons per frame (comparing total time elapsed against your delay for that type), but 1-3 function calls per frame depending on the number of functions you're using.

Again though, this is all just assumptions on my part. I've not actually benchmarked the difference and there may very well be considerations I'm overlooking. And if frames are ever being hidden and their OnUpdate scripts therefore skipped, that may make a difference as well.

Last edited by Barjack : 01-18-12 at 07:57 AM.
  Reply With Quote
01-18-12, 07:57 AM   #4
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
I had an idea, not sure why I didn't think of this before - and I think it is what Barjack means also - it would be possible to use 3 different 'time since last update' values, check for each in one OnUpdate script and let them count to different numbers. That might be the most efficient, unless conditions actually require more instructions than a simple time/latency check.
  Reply With Quote
01-18-12, 08:07 AM   #5
Barjack
A Black Drake
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 89
Originally Posted by Haleth View Post
I had an idea, not sure why I didn't think of this before - and I think it is what Barjack means also - it would be possible to use 3 different 'time since last update' values, check for each in one OnUpdate script and let them count to different numbers. That might be the most efficient, unless conditions actually require more instructions than a simple time/latency check.
That's how I was assuming the single-OnUpdate version would work, yeah. Something like

Code:
function someUpdateChecker (self, elapsed)
  local timer1 = timer1 + elapsed
  local timer2 = timer2 + elapsed
  if timer1 > limit1 then
    timer1 = 0
    doStuff1()
  end
  if timer2 > limit2 then
    timer2 = 0
    doStuff2()
  end
end
Which is what I assume is more efficient than a 3-function (or 2-function in this simplified example) alternative simply because it essentially is 3 different update functions, just all crammed into one. Perhaps you had something else in mind, though.

Naturally, as you said in the original post, the difference is probably undetectably minor. In fact, I wouldn't be surprised to learn that the speed of whatever has to manage SetScript callbacks etc. is slower than the actual difference here and therefore results in a slightly bigger difference overall.

Again, all completely untested etc.
  Reply With Quote
01-18-12, 08:12 AM   #6
Nimhfree
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 267
My first assumption is that you should code everything up in just one. Ignore the timing of FPS and the actual clock and just update all of them each time you decide to do work in your OnUpdate script. If that works well and does not slow things down you are fine. If you are really worried about it, you can time the individual calls and determine if their overhead is worth the mathematical comparisons needed to control accessing them.
  Reply With Quote
01-18-12, 05:56 PM   #7
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
Thanks for the insight everyone, worth a read

I figured that a time lookup would be too light to put in a condition and give its own counter. I just update that every second. I did give latency its own update frequency though.

Code:
local _, _, home, world = GetNetStats()

local last = 0
local lastLag = 0

f:SetScript("OnUpdate", function(self, elapsed)
	last = last + elapsed
	lastLag = lastLag + elapsed

	if lastLag >= 10 then
		_, _, home, world = GetNetStats()
		lastLag = 0
	end

	if last >= 1 then
		text:SetText("|cffffffff"..ceil(GetFramerate()).."|r fps   |cffffffff"..home.."|r/|cffffffff"..world.."|r ms   |cffffffff"..date("%H:%M"))
		last = 0
	end
end)
  Reply With Quote
01-18-12, 05:59 PM   #8
Nibelheim
local roygbi-
 
Nibelheim's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 1,600
Latency only updates every 30 seconds (unless they changed it in 4.3). Best course of action is to do a fast timer (say every 3 seconds) until the Latency value updates, then start a timer every 30 seconds from that point. This way you get the latency value when it updates, and only when it updates.
  Reply With Quote
01-18-12, 06:24 PM   #9
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
Oh right, it somehow got into my head that it was 10. Thanks
  Reply With Quote
01-19-12, 12:23 PM   #10
Spike`
A Defias Bandit
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 3
AceTimer3.0 lets you set functions that are only runned in the seconds you specify

from wowace page:

Code:
MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")

function MyAddon:OnEnable()
  self.timerCount = 0
  self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
end

function MyAddon:TimerFeedback()
  self.timerCount = self.timerCount + 1
  print(("%d seconds passed"):format(5 * self.timerCount))
  -- run 30 seconds in total
  if self.timerCount == 6 then
    self:CancelTimer(self.testTimer)
  end
end
and

Code:
MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")

function MyAddon:OnEnable()
  self:ScheduleTimer("TimerFeedback", 5)
end

function MyAddon:TimerFeedback()
  print("5 seconds passed")
end
now the question is, what is more efficient? onupdate or this library ?
  Reply With Quote
01-19-12, 12:29 PM   #11
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,359
AceTimer-3.0 uses an OnUpdate internally so there's no magic sauce in ScheduleTimer

It does take the approach of using 1 frame with a single OnUpdate to run all those separate registered timers from different addons so that says something,
but this is not an OnUpdate vs AceTimer thing it's OnUpdate vs OnUpdate.
  Reply With Quote
01-25-12, 03:38 AM   #12
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Same do the animation widgets.

Another funny thing. You can make yourself a timer based on the animation widget.
Maybe not efficient but maybe more fun.

lua Code:
  1. --create animation timer
  2.     local b = CreateFrame("Frame")
  3.  
  4.     local t = b:CreateTexture()
  5.  
  6.     --anim
  7.     --http://wowprogramming.com/docs/widgets/Animation
  8.     local ag = t:CreateAnimationGroup()
  9.     local anim = ag:CreateAnimation("Rotation")
  10.     anim:SetDegrees(0)
  11.     anim:SetDuration(60)--in seconds
  12.     ag:Play()
  13.  
  14.     ag:SetScript("OnFinished", function(self, event, ...)
  15.       print('done')
  16.     end)

Afaik Tuller tried that in some of his cooldown mods aswell. Internally the animation widget is using onUpdate aswell (I guess). You even have the option to repeat the animation forever.

The thing is the CPU usage may fade but it is just transfered to Blizzard code by using the animation API.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 01-25-12 at 04:02 AM.
  Reply With Quote
01-25-12, 09:18 PM   #13
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
You don't actually need to specify a type for the animation:
lua Code:
  1. local timer = frame:CreateAnimationGroup()
  2.  
  3. local timerAnim = timerGroup:CreateAnimation()
  4. timerAnim:SetDuration(60) -- how often you want it to finish
  5.  
  6. timer:SetScript("OnFinished", function(self, requested)
  7.     -- requested = true if you used timer:Stop(), false if it finished naturally
  8.  
  9.     -- do stuff here
  10.  
  11.     self:Play() -- start it over again
  12. end)
  13.  
  14. timer:Play()
  Reply With Quote
01-26-12, 07:53 AM   #14
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Even better.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
01-26-12, 02:06 PM   #15
ronconsoda
A Defias Bandit
Join Date: May 2006
Posts: 3
i personally prefer to let blizz do the loop:

Code:
local mapTimer = AnimTimerFrame:CreateAnimationGroup()
mapTimer:SetLooping("REPEAT")
mapTimer:SetScript("OnLoop", self.YourUpdateFunction)
  Reply With Quote
01-26-12, 02:14 PM   #16
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That works if you always want to repeat the timer. It only adds one line to control it myself (the animationGroup:Play() call at the end of the OnFinished script) and lets the timer be used as a delay (eg. "do this once, 30 seconds from now") or to detect when something happens that can't reliably be detected via events (eg. "check every 1 second to see if I'm mounted, then stop checking once I am mounted"). Auto-looping may be simpler if you're simply replacing a throttled always-on OnUpdate, though.
  Reply With Quote
01-26-12, 04:27 PM   #17
Xuerian
A Fallenroot Satyr
 
Xuerian's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 27
So this thread is relevant to my interests.

Using animations instead of throttling OnUpdate seems to be a pretty straightforward way of reducing wasted cycles, since they are handled natively - not free, but faster in C.

A example inspired by NPCScan would be
lua Code:
  1. local group = frame:CreateAnimationGroup()
  2. group.UpdateRate = 60
  3. function group:OnLoop()
  4.   print('60 second tick')
  5. end
  6. -- In your OnLoad
  7. group:Play()
  8. -- When you don't need the timer
  9. group:Stop()
Has anyone put together general information on Animations documentation-wise, beyond api docs? I haven't found any good reading on them until this thread. Benchmarks would be interesting too, though redundant if it is a improvement at all.

Just what I needed. More things to putz with and change instead of working on what I need to =P

Last edited by Xuerian : 01-26-12 at 04:38 PM.
  Reply With Quote
01-26-12, 07:50 PM   #18
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Back when the Animation System was new, Shefki (PitBull4 maintainer) wrote LibShefkiTimer-1.0 as a drop-in replacement for AceTimer-3.0.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
01-26-12, 09:03 PM   #19
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
My concern would be the resource cost of adding 2 objects on top of the frame to handle it. The animation group and animation object per timer. It is unknown as to the actual impact on CPU usage between using OnUpdate timers and animation objects. Just because exposure to Lua code is reduced doesn't mean it's automatically faster. The C code could be running much more than just triggering an OnFinished script and that would take time too.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » OnUpdate efficiency

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off