WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   How to improve bottleneck functions? (https://www.wowinterface.com/forums/showthread.php?t=33096)

Crepusculu 06-11-10 01:25 AM

How to improve bottleneck functions?
 
I am trying to improve the performance of my bottleneck functions that (ab)use the OnUpdate event. Since this event is called so frequently, I would like to optimize the functions.

My idea is to move my temporary variables outside of the function.

Here's a silly example:
Code:

myFrame:SetScript("OnUpdate",function(self,elapsedTime)
  for i=1,#array do
    local name = UnitName("raid"..i.."target")
    -- do important stuff
  end
end)

The concept is that moving the temporary variables on the outer scope of the function will still encapsulate the variables, but would recycle the existing variables when the function gets called again. This should reduce the garbage collection.

The fix would be:
Code:

do
  local i, name
  myFrame:SetScript("OnUpdate",function(self,elapsedTime)
    for i=1,#array do
      name = UnitName("raid"..i.."target")
      -- do important stuff
    end
  end)
end



Does this extended variable scope have any benefit, or should I be letting the garbage collector pick up every local variable? Do for-loop variables override preexisting variables and build new localized ones?

Thanks to any Lua-gurus out there!

Torhal 06-11-10 02:02 AM

Variables created within the for loop are done so on the stack and are freed immediately after the end of execution without even being on the garbage collection facility's radar. You can create your variable at the top of the function so it's declared exactly once per run or leave it in the do block as you're doing now, but either way isn't going to significantly improve your CPU usage.

The only real optimization you can do in your OnUpdate script is to throttle how often it occurs - at the moment, if your FPS is 120 your function is executed 120 times in one second.

Here, I'm limiting the runs to once every quarter of a second.

Code:

do
  local last_update = 0

  myFrame:SetScript("OnUpdate", function(self, elapsedTime)
        last_update = last_update + elapsedTime

        if last_update < 0.25 then
                return
        end
        local name

        last_update = 0

        for i = 1, #array do
                name = UnitName("raid"..i.."target")
                -- do important stuff
        end
  end)
end


Foxlit 06-11-10 04:59 AM

Quote:

Originally Posted by Crepusculu (Post 191698)
Do for-loop variables override preexisting variables and build new localized ones?

Yes, they do. Variables that appear in for i=... or for i,v in ... loop syntax are new and local to the loop. You cannot bypass this behavior.

Vrul 06-11-10 09:49 AM

I would make a local reference to UnitName as well.

lilsparky 06-11-10 10:34 AM

yeah, stuff the unitname into the array you're using (or have another array that contains that info). if you absolutely can't do that, at least prebuild your unitid instead of running that pointless concat function. ie, unitid[1] = "raid1target"

Crepusculu 06-11-10 02:26 PM

Thanks for the replies!

Normally I would be imposing time restrictions as Torhal has suggested. This particular situation I am referencing is an exception, as i am dealing with time critical status changes that lack any triggered event.

Pre-concatenated strings is an excellent idea, since I am dealing with a small finite set. The return value on the unit is actually the focus of the bottleneck.


I'm not exactly sure how localizing UnitName would work. Does that mean doing something like
Code:

local UnitNameShortcut = UnitName
and using the local reference to bypass the lookup time on the global function? That sounds like it might help a bit.

dr_AllCOM3 06-11-10 03:23 PM

local UnitName = UnitName
is fine.

Waverian 06-12-10 03:25 PM

Quote:

Originally Posted by Crepusculu (Post 191771)
and using the local reference to bypass the lookup time on the global function? That sounds like it might help a bit.

It won't. The difference in execution time of local vs global functions is trivial. The difference between them for me, over a million iterations, is .077 second. If a user is running at 60 FPS with a completely unthrottled OnUpdate running constantly, you're saving .077 second of execution time every 4.6 hours.

There's no serious flaw in localizing globals that you're going to use a lot, but there's really no tangible benefit unless you're trying to prevent the function from being tampered with outside of your addon.

Slakah 06-12-10 05:22 PM

Having a quick glance of the code the best optimizations your gonna get is by either keeping tab of the size of array so you don't have to iterate over the entire thing with #array or by keeping a copy of the concatenation "raid"..i.."target".
i.e.
lua Code:
  1. local raidtargets = setmetatable({}, {__index = function(t,i)
  2.     t[i] = "raid"..i.."target"
  3.     return t[i]
  4. end})
  5. myFrame:SetScript("OnUpdate",function(self,elapsedTime)
  6.     for i=1,array.size do --keep a tab of array.size
  7.         local name = UnitName(raidtargets[i])
  8.         -- do important stuff
  9.     end
  10. end)

These are probably the best optimizations your gonna get if your nutty about that stuff.


All times are GMT -6. The time now is 06:15 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI