local a, b, c, d, e
local frame = CreateFrame("Frame")
local function foofoo()
do
stuff
end
end
local function foo()
a, b = wowBarZ()
c = wowBarY()
d, e = wowBarX()
if (a and c) or (e and c) then
foofoo()
print(format("%s%s", b, d))
end
end
frame:SetScript("OnUpdate", foo)
local frame = CreateFrame("Frame")
local function foo()
local a, b = wowBarZ()
local c = wowBarY()
local d, e = wowBarX()
if (a and c) or (e and c) then
local function foofoo()
do
stuff
end
print(format("%s%s", b, d))
end
end
frame:SetScript("OnUpdate", foo)
note: don't mind syntax and all - it's just for the idea
I think you can spot the difference, in the first, all vars are declared and all functions have the file as scope and thus are instantiated. The second, everything that is needed is instantiated on the fly.
Now with the garbage collector in play, I was wondering what was the least intensive way of doing things, aka, what creates the lesser load? Keeping in mind that lua passes by reference...
The first will ofcourse have more initial memory, but having everything at the ready, it only needs to access/read that memory rather then create/write it first.
The second has the benefit of having less constant memory, but higher peak memory. This also needs to be removed again by the garbage collector. Memory jumps a lot more so to say. It is more memory-usage-intensive.
Now the above are only small things with minor impact, however, when doing stuff like tooltips, if on every tooltip-call you have to create roughly 40 locals (random number), when you're mousing through dalaran, you're creating quite a lot of em...
local a, b, c, d, e
local frame = CreateFrame("Frame")
local function foofoo()
do
stuff
end
end
local function foo()
a, b = wowBarZ()
c = wowBarY()
d, e = wowBarX()
if (a and c) or (e and c) then
foofoo()
print(format("%s%s", b, d))
end
end
frame:SetScript("OnUpdate", foo)
local frame = CreateFrame("Frame")
local function foo()
local a, b = wowBarZ()
local c = wowBarY()
local d, e = wowBarX()
if (a and c) or (e and c) then
local function foofoo()
do
stuff
end
print(format("%s%s", b, d))
end
end
frame:SetScript("OnUpdate", foo)
note: don't mind syntax and all - it's just for the idea
I think you can spot the difference, in the first, all vars are declared and all functions have the file as scope and thus are instantiated. The second, everything that is needed is instantiated on the fly.
Now with the garbage collector in play, I was wondering what was the least intensive way of doing things, aka, what creates the lesser load? Keeping in mind that lua passes by reference...
The first will ofcourse have more initial memory, but having everything at the ready, it only needs to access/read that memory rather then create/write it first.
The second has the benefit of having less constant memory, but higher peak memory. This also needs to be removed again by the garbage collector. Memory jumps a lot more so to say. It is more memory-usage-intensive.
Now the above are only small things with minor impact, however, when doing stuff like tooltips, if on every tooltip-call you have to create roughly 40 locals (random number), when you're mousing through dalaran, you're creating quite a lot of em...
Which would have the lesser impact on a system?
Aside from the syntax error in the second example, it will have significant problems considering you are potentially creating a new function for every FPS.
Aside from the syntax error in the second example, it will have significant problems considering you are potentially creating a new function for every FPS.
copy/paste fail... it's early over here ;)
But yeah, as I thought. Keep it clean.
Something else bubbled up though:
I've got a config file, with a global config
config.lua
config = {
["1"] = {
etcetc
Is there a benefit from renaming that to locals? As everything is passed by reference, that local and global (until either changes) point to the same memory location... what is the benefit of using renaming (local x = config.y) as I so often see in addons? Or is that only "should the global change due to outside influence, at least the local has the original value"?
The difference in using upvalues or pure locals is negligible. Locals are on the stack, and don't create real "garbage". You're calling the functions to fill the variables every time anyway.
What is significant is the function creation in the second example. Don't create functions if you don't have to. Create one function and pass in values as parameters instead of creating a new closure everytime. That will certainly create garbage.
For your config related question, usually people just do the local aliases to their config tables for a negligible increase in speed when reading the variable (global lookup is slower), or just simply to make the code more readable.
what is the benefit of using renaming (local x = config.y) as I so often see in addons?
Slight speed improvement is usually the reason. The local value is available through an indirection whereas a global requires quite a bit of work.
If you repeat ten times the same "config.foo.bar", "config.foo.baz", ... construct in your code, then the GETTABLE operation is repeated each time. Keeping a local reference like "local foo = config.foo ; foo.bar ; foo.baz" reduces drastically the number of operations done by your code. This is not only faster to execute, but the function prototype will use less memory as well.
Or is that only "should the global change due to outside influence, at least the local has the original value"?
In fact, I think most of the time this is either overlooked or ignored, although it can be a perfectly valid reason to use an upvalue.
For your original question, I would say that you probably need to instrument the two solutions and measure the difference, if any. I'm pretty sure the difference is not really noticeable.
Treat functions like tables, only declare them when you absolutely have to, and try to reuse them as much as you can... but also don't be afraid to dereference one so it will GC if you are not going to use it any more.
Creating a new function closure in an OnUpdate will certainly show a visible increase in garbage creation.
I'm not sure he meant to create then call the function in the second example. Only copy the function's code block. In that case, the difference between the two examples is that the first uses a bunch of upvalues but the function context doesn't use any memory space to keep the local variables, whereas the second does the opposite. I haven't checked but I'm pretty sure lua's engine release the space for local at once, whatever the number of declared local variables, so I don't think it matters much how many locals you use.
Declaring a function just to call it later doesn't achieve anything meaningful here.
But yeah, you're right of course, unless it's necessary, never create closure multiple times.
Of course, I can think of at least one example of my own code where I do just that :-) At least I've some explanation in case there's a trial ;-)
Perhaps it would be an idea if there could be made some sort of thread containing some basic pointers with regards to optimization and code streamlining? More just a general Tips & Tricks when it comes to wow-Lua I suppose
Note the very important word : "premature". What it means is that you shouldn't even think about optimization until you have too (i.e. your code is too slow).
In other word : Write code that is easy to read and follow. Once your program is done, and if it's too taxing, then try to find out where using instrumentation and then try to optimize that part.
You should however, already have "broad optimizations" in mind when you write an addon. By broad, I mean you should already have decided and picked which algorithms and data structures you are going to use (eg, quick sort versus merge sort, separate hash tables of data or tables of tables of data, etc). Some solutions will use more memory but be faster, some will be slower but use less memory. Depending on the addon, one or the other will be more important.
[...] I mean you should already have decided and picked which algorithms and data structures you are going to use (eg, quick sort versus merge sort, separate hash tables of data or tables of tables of data, etc). [...]
Isn't this standard when writing any code? I mean, just starting to write with no clue on what, why, how and where is pointless. Well, not pointless if you're just in it for the fun of it, but then why bother?
Why? I mean, i just write a sort function, and which algorithm is in there isn't really important at that point. If i really care, i can benchmark the different versions later to figure out which would be best for my case.
Why? I mean, i just write a sort function, and which algorithm is in there isn't really important at that point. If i really care, i can benchmark the different versions later to figure out which would be best for my case.
Well, depending on how you structure your data, your sort function might need to be written differently. If for example, you use separate tables to store data instead of tables of tables, then the sorting has to be synced across the the separate tables and a custom sort function has to be written.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
I'm wondering about something...
Consider the 2 following examples:
note: don't mind syntax and all - it's just for the idea
I think you can spot the difference, in the first, all vars are declared and all functions have the file as scope and thus are instantiated. The second, everything that is needed is instantiated on the fly.
Now with the garbage collector in play, I was wondering what was the least intensive way of doing things, aka, what creates the lesser load? Keeping in mind that lua passes by reference...
The first will ofcourse have more initial memory, but having everything at the ready, it only needs to access/read that memory rather then create/write it first.
The second has the benefit of having less constant memory, but higher peak memory. This also needs to be removed again by the garbage collector. Memory jumps a lot more so to say. It is more memory-usage-intensive.
Now the above are only small things with minor impact, however, when doing stuff like tooltips, if on every tooltip-call you have to create roughly 40 locals (random number), when you're mousing through dalaran, you're creating quite a lot of em...
Which would have the lesser impact on a system?
Aside from the syntax error in the second example, it will have significant problems considering you are potentially creating a new function for every FPS.
copy/paste fail... it's early over here ;)
But yeah, as I thought. Keep it clean.
Something else bubbled up though:
I've got a config file, with a global config
config.lua
Is there a benefit from renaming that to locals? As everything is passed by reference, that local and global (until either changes) point to the same memory location... what is the benefit of using renaming (local x = config.y) as I so often see in addons? Or is that only "should the global change due to outside influence, at least the local has the original value"?
What is significant is the function creation in the second example. Don't create functions if you don't have to. Create one function and pass in values as parameters instead of creating a new closure everytime. That will certainly create garbage.
For your config related question, usually people just do the local aliases to their config tables for a negligible increase in speed when reading the variable (global lookup is slower), or just simply to make the code more readable.
Slight speed improvement is usually the reason. The local value is available through an indirection whereas a global requires quite a bit of work.
If you repeat ten times the same "config.foo.bar", "config.foo.baz", ... construct in your code, then the GETTABLE operation is repeated each time. Keeping a local reference like "local foo = config.foo ; foo.bar ; foo.baz" reduces drastically the number of operations done by your code. This is not only faster to execute, but the function prototype will use less memory as well.
In fact, I think most of the time this is either overlooked or ignored, although it can be a perfectly valid reason to use an upvalue.
For your original question, I would say that you probably need to instrument the two solutions and measure the difference, if any. I'm pretty sure the difference is not really noticeable.
Creating a new function closure in an OnUpdate will certainly show a visible increase in garbage creation.
I'm not sure he meant to create then call the function in the second example. Only copy the function's code block. In that case, the difference between the two examples is that the first uses a bunch of upvalues but the function context doesn't use any memory space to keep the local variables, whereas the second does the opposite. I haven't checked but I'm pretty sure lua's engine release the space for local at once, whatever the number of declared local variables, so I don't think it matters much how many locals you use.
Declaring a function just to call it later doesn't achieve anything meaningful here.
But yeah, you're right of course, unless it's necessary, never create closure multiple times.
Of course, I can think of at least one example of my own code where I do just that :-) At least I've some explanation in case there's a trial ;-)
Having Java as background, Lua is quite something to get used to in terms of optimization, due to the lack of classes per sé and instantiation etc.
Perhaps it would be an idea if there could be made some sort of thread containing some basic pointers with regards to optimization and code streamlining? More just a general Tips & Tricks when it comes to wow-Lua I suppose
Thread finished, right there! :)
Until you know *how* to actually optimize, you really should not.
hence why I ask before I start with it (still analyzing and testing atm) ;)
Donald Knuth
In other word : Write code that is easy to read and follow. Once your program is done, and if it's too taxing, then try to find out where using instrumentation and then try to optimize that part.
Isn't this standard when writing any code? I mean, just starting to write with no clue on what, why, how and where is pointless. Well, not pointless if you're just in it for the fun of it, but then why bother?
Why? I mean, i just write a sort function, and which algorithm is in there isn't really important at that point. If i really care, i can benchmark the different versions later to figure out which would be best for my case.
Well, depending on how you structure your data, your sort function might need to be written differently. If for example, you use separate tables to store data instead of tables of tables, then the sorting has to be synced across the the separate tables and a custom sort function has to be written.