05-23-11, 08:46 AM | #1 |
hooksecurefunc & memory use
Hello, I recently made a button border AddOn, the first version of which took this approach:
This "worked", the trouble was sporadic memory usage spikes & consequent FPS drops...usually when doing certain things (like shapshifting). I would run through Elwynn doing nothing but stealthing/unstealthing, and would drop to zero FPS both ways for a second as this AddOn's memory use grew from 10 KB to 2 MB momentarily (no other AddOns loaded). My second version took an approach I've seen in a few other AddOns (notably nMainbar): The result is dramatically better performance with no lag issues whatsoever. I'm trying to understand why, as I still like the idea of one "do stuff" function that is referenced in all subsequent hooked secure functions. first version | second version Last edited by Aprikot : 05-23-11 at 09:37 AM. Reason: i r spel gud |
|
05-23-11, 09:34 AM | #2 |
If you're creating textures and frames every time DoStuff() is called, expanded memory usage is to be expected. If, however, you create the textures and frames exactly once and apply them when they're needed, you're only ever growing the memory once.
Without seeing code, I can't rightly say what's happening.
__________________
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. |
|
05-23-11, 09:43 AM | #3 |
I have pastebin links in the op, but here's the meat of the two versions:
First version: lua Code:
lua Code:
|
|
05-23-11, 10:16 AM | #4 |
Ah - I missed the links in the OP...I must have thought it was part of a sig.
Anyway...it looks like the original method iterates over everything every time one of the hooked functions is called, whereas the new method specifically targets the appropriate UI widget. If the hooked functions are being called many times in a short period, the excessive iterations (and thereby all of the function calls per iteration) will definitely have a huge impact on your FPS, whereas the specific targeting may still have minor performance issues (if not throttled) but definitely nothing of the magnitude of the "let's change everything" approach.
__________________
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. |
|
05-23-11, 01:29 PM | #5 |
I guess I'm trying to determine if the first approach is fundementally unsound, or just poorly implemented.
The content of my "main" function is all conditional on what objects are being passed to it, and in my hooksecurefunc calls I'm trying to say "hey go check that main function, and if it knows who you are, do what it tells you". It seems like this would be fairly efficient resource-wise, but I'm largely ignorant of best practices & optimization (but learning ). |
|
05-23-11, 02:17 PM | #6 |
Your original code creates at least three garbage tables every time one of the hooked functions is called. Some of those hooked functions, like ActionButton_UpdateUsable, get called a lot: once per visible action button for each action that becomes usable/unusable. Every action button is registered for ACTIONBAR_UPDATE_USABLE, and each one responds by calling ActionButton_UpdateUsable separately.
Imagine you have 20 action buttons visible, and 10 of them become unusable when you unstealth. If you unstealth, ACTIONBAR_UPDATE_USABLE fires 10 times, and ActionButton_UpdateUsable gets called 10*20 = 200 times. Then, your hook creates one garbage table each call: Code:
hooksecurefunc("ActionButton_UpdateUsable", function(self) for i, v in pairs({"ActionButton", "MultiBarBottomLeftButton", "MultiBarBottomRightButton", "MultiBarLeftButton", "MultiBarRightButton", "MultiCastActionButton", "MultiCastSummonSpellButton", "MultiCastRecallSpellButton"}) do Code:
local BorderBeautification = function(object) if IsAddOnLoaded("FacePaint") and FacePaint then tc = {r = topcolor.r, g = topcolor.g, b = topcolor.b, a = topalpha} bc = {r = bottomcolor.r, g = bottomcolor.g, b = bottomcolor.b, a = bottomalpha} else tc = {r = BorderColors.top.r, g = BorderColors.top.g, b = BorderColors.top.b, a = BorderColors.top.a} bc = {r = BorderColors.bot.r, g = BorderColors.bot.g, b = BorderColors.bot.b, a = BorderColors.bot.a} end That explains why your memory usage ballooned when you spammed stealth/unstealth. The other technique in your second version is more efficient because it doesn't recolor the same button multiple times per event like the first did. It still would still create a fair number of garbage color tables though. I suggest using the preexisting topcolor/bottomcolor and BorderColors tables instead of copying them each time. Using the second version of your code, here's an updated colorit function that doesn't create any new tables: lua Code:
|
|
05-23-11, 03:05 PM | #7 |
@Saiket: very eyeopening & helpful (& humbling ), ty!
I think I've reread your post & reexamined my code x100 so far, and am nearing comprehension. I'll be trying out the table-less colorit function. Somewhat related, I hadn't been able to capture/transfer color values from FacePaint's variables (topcolor, topalpha, bottomcolor, bottomalpha) without using global variables in both that AddOn and this. I'm now wondering if it was due to my use of tables, and I should probably revisit that in FacePaint. In general is there an accepted practice of sharing varibles between AddOns (or at least one reading the other) which avoids the global namespace? Saved variables I'm guessing? |
|
05-23-11, 03:09 PM | #8 |
Saved variables are in the global namespace.
|
|
05-23-11, 03:42 PM | #9 |
Most addons have a main table they use for all of their storage, so that no matter how many variables and functions they use, the "namespace" main table only takes up one global. For example if FacePaint had one global table named FacePaint, you could save and access the color tables to/from FacePaint.topcolor and FacePaint.bottomcolor. You could also read the other mod's saved variables table as Seerah suggested.
|
|
05-23-11, 04:12 PM | #10 | |
D'oh!
lua Code:
become this? lua Code:
I've been curious for awhile about namspace declarations at the beginning of AddOns (local _, ns = ...), but if I understand correctly, this is to use multiple Lua files under the same AddOn? |
||
05-23-11, 06:17 PM | #11 | |
I suggest creating "getter" functions instead though, to simplify how other addons interact with FacePaint. Basically, instead of requiring other mods to reach into the guts of FacePaint to get color values, FacePaint could provide a few standard, reliable functions to return color settings. If it had two functions, FacePaint.GetColorTop and FacePaint.GetColorBottom, they could handle the logic of when colors are flipped, or if class coloring is enabled, or any other feature FacePaint gets in the future. Here's one way you could set something like that up, with the ns table: lua Code:
If FacePaint were set up like this, your colorit function could be simplified: lua Code:
Last edited by Saiket : 05-23-11 at 06:19 PM. Reason: Snip |
||
05-24-11, 12:25 PM | #12 | |
Regarding namespace: at the top of the code you posted I'm having trouble understanding how a table is being created: lua Code:
Also, with a namespace of "FacePaint" defined, does this mean that other AddOns could then reference FacePaint's tables, variables, and functions by name as FacePaint."name", or is this only intended for cross-file sharing within the FacePaint AddOn directory? |
||
05-24-11, 12:51 PM | #13 |
Blizzard passes two variables in through the vararg for every file in your addon. The first is the name of the addon (as defined by the containing folder) and the second is a table that is unique to the addon.
So the code Code:
local ns = select(2, ...) FacePaint = ns |
|
05-24-11, 02:20 PM | #14 | |
|
||
05-24-11, 03:58 PM | #15 | |
__________________
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. |
||
05-24-11, 05:38 PM | #16 |
WoWInterface » Developer Discussions » Lua/XML Help » hooksecurefunc & memory use |
«
Previous Thread
|
Next Thread
»
|
Display Modes |
Linear Mode |
Switch to Hybrid Mode |
Switch to Threaded Mode |
|
|