Upvalues

Upvalues

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Upvalues

Post by Argh »

I hit the wall today- the absolute limit of 60 upvalues. Doh!

Anybody have a good way around that limitation? One of the things I wanted to know was... if I localize a variable within a function, and it doesn't get referenced elsewhere... is that variable getting re-initialized every operation?

i.e... if I have something like this:

Code: Select all

function widget:DrawScreen
local foo1, foo2, foo3, foo4, foo5
end
Are those variables being re-created in memory every pass, and how bad is the cost?

I ended up solving my problem that way, and it just feels... very sloppy, to me. My understanding is that the number of upvalues is controlled on the C++ end- what are the performance implications of raising it from 60 to some higher number, Trepan? The default is a mere 32 (I have issues with my only decent debugging tool all the time because of this, where it complains and refuses to finish executing, but Spring runs the code).
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Upvalues

Post by AF »

What are upvalues?
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Upvalues

Post by jK »

Config is set to defaults: 60 upvalues & 200 local vars, the max stack size is 250. I don't know if those upvalues are part of the local vars or if they are seperate, so I don't know if it is possible to increase any of these numbers, but cuz the stacksize limits both of those it wouldn't change a lot.

and yes, lua creates each time it gets a local cmd a new variable on the stack. That's why you should create values only where they are needed and not to create a list of used vars at the top of the function (pascal/delphi style). Also you should try to avoid to create a local var w/o giving it any input (like "local myvar;").
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Upvalues

Post by Argh »

What are upvalues?
I probably shouldn't even try to answer this, but here's what I think I know, based on what I've read:

Upvalues are keys that are stored in the stack for a particular Lua execution to use at runtime, when your software needs to either query the API, which then talks to Spring, or send the API a request to make Spring execute a particular function call.

Every bit of information in Lua is basically table-oriented. It's the main thing I hate about Lua, tbh, but I've gradually gotten used to it. It's like hating your talented, popular roommate, who brings all of the ladies and their friends over on a regular basis- you can hate him, sure, but he's bringing women, man.

At any rate, using the key to specific table locations in the global area greatly speeds stuff up, because you're not asking Lua to find the key "Color" in the table "gl"- which is what gl.Color really means- you're giving it a very specific key number, and saying, "go there, pass these arguments, do not bother searching".

With the global variables, this is really, really important, because they're huge tables, and table searches are, alas, quite slow.

Therefore, what you want to do, to increase efficiency, is to bring certain common variables or locations within "upper" tables "down" into the stack your program's using, so that your software doesn't have to ever search the huge tables created when Lua's initialized. Then your function loops are basically using this "upper" table- a table that's created when your Lua is initialized, basically- to make their requests to the API using those keys, instead of requesting a search.

Lastly, upvalues are a way to create a "local-global" pool of variables for your various functions- things that all of the functions "know about". If you create a variable within a function loop, that key-value pair can only be searched by that function loop's logic- the other functions simply cannot get access to that data (er, I should say that it's possible, but would be very, very, very difficult and eat CPU like mad).

An example of creating upvalues would be this, outside of a function:

Code: Select all

local glResetState = gl.ResetState
local glColor = gl.Color
local glText = gl.Text
local math_random = math.random
local x,z = 0,0 
Which we could then use inside a function like this:

Code: Select all

function widget:DrawScreen()
x = math_random(0,500)
z = math_random(0,500)
glColor(1,0,1,1)
glText("Hello World",x,z,"rno")
glResetState
end
Basically, it's shorthand for a key value, AF. We cannot entirely avoid going back to the global variables, because those are necessary for the Lua API to pass on to Spring as a function call or query, along with whatever arguments the function wants.

But, there is a limit as to how many key values you can store this way. That's the "upvalues limit", basically, which is the wall I just smacked into. I've been trying to keep everything I need to use in any function an upvalue, because that was pretty much my understanding about good coding practice with this language when I first started talking to Trepan about this, over a year and a half ago.

If your program gets complicated enough, that's not possible. I'm surprised I haven't hit this wall before- anything involving OpenGL involves having to localize a lot of API calls, and that's completely necessary, if you want things to run fast.
Config is set to defaults: 60 upvalues & 200 local vars, the max stack size is 250. I don't know if those upvalues are part of the local vars or if they are seperate, so I don't know if it is possible to increase any of these numbers, but cuz the stacksize limits both of those it wouldn't change a lot.

and yes, lua creates each time it gets a local cmd a new variable on the stack. That's why you should create values only where they are needed and not to create a list of used vars at the top of the function (pascal/delphi style). Also you should try to avoid to create a local var w/o giving it any input (like "local myvar;").
Thanks for the detailed answer, I really appreciate that.

Meh, I need to learn how to profile, and see what the real difference is, between doing it as a populate --> destruct cycle and an iterative table search.

Somehow I'm guessing that it'll come out so close it won't matter a lot for what I'm doing, though- these are all variables that only get used within one function loop, and can be created before the main logical loops within the function start, so it's a one-time cost, vs. table searches over and over and over again. I suspect I come out ahead on speed, in this particular instance.
Andrej
Posts: 176
Joined: 13 Aug 2006, 18:55

Re: Upvalues

Post by Andrej »

i was actually writing a response
then
i
was
like
fuck

7/10 for the effort
+2.5 bonus because i think you are actually serious

please delete thread before permament damage to new lua coders
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Upvalues

Post by Argh »

Meh, if you'd like to provide a better explanation, or explain what I've said that's incorrect, go right ahead, it doesn't offend me.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Upvalues

Post by Kloot »

Upvalues are keys that are stored in the stack for a particular Lua execution to use at runtime
No.

You need to understand the concept of scope in programming languages (and Lua's type of it, which is static aka. lexical) and how it affects binding of variables to know what an upvalue really is, "keys held in a stack" is just totally meaningless misuse of terms. To be precise, upvalues are variables that neither have local nor global scope, and which are referred to from inside anonymous functions (Lua treats functions as first-class objects, which basically means a function can be _constructed_ at runtime and reference part of its enclosing environment). Whatever your mental picture of Lua is, erase it and look at this example without making other assumptions:

Code: Select all

function sort(wizards, spellStrengths)
  table.sort(wizards, function(wizard1, wizard2)
    -- spellStrengths is an upvalue (external local var) here
    return (spellStrengths[wizard1] > spellStrengths[wizard2])
  end)
end
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Upvalues

Post by Argh »

Ok, read Wikipedia's definition of scope.

To my way of thinking, what I said is correct though, in the context of Lua's own particular semantics. Sorry, I'm not really used to talking about this in computer-science terms- I just do this stuff, people, I don't really worry about what to call it.

I mean... basically, what matters is that Lua stores all data in tables, pretty much. So, we're ultimately talking about providing a pointer to a given memory location in the stack, or creating a stack of our own that has these pointers in them as a reference, right?

I guess what I'm really asking is, what is really happening, when we localize an API call? Why does that greatly increase the efficiency of our software? I know it does, and ultimately, the OP was about not only running out of them, but the implications of the limits, and what can be done, in terms of efficiency.

For example which is really faster, this:

Code: Select all

local variable_table = {var1, var2, var3, var4}

function blahblah()
for i = 1,1000,1 do
if variable_table.var1 > blah then blah end
end
end
Or this:

Code: Select all

function blahblah()
local var1, var2, var3, var4 = 1,2,3,4
for i = 1,1000,1 do
if var1 > blah then blah end
end
end
Because, ultimately, that's the real nuts-and-bolts question, for me- is the cost of destroying / reinitializing the variables at the start of a very long logical loop greater, or less than, the cost of that pointer to a position in the table array?
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Upvalues

Post by Kloot »

Sorry, I'm not really used to talking about this in computer-science terms
If you want to understand the "why" behind ...
I guess what I'm really asking is, what is really happening, when we localize an API call? Why does that greatly increase the efficiency of our software?
... this, you _have_ to know what the computer-science terms mean, and not make wild guesses about how things work (those only get you so far in a field grounded in applied math). Localizing a table value (which can be a function, such as Spring's API parts) ...

Code: Select all

local spXXX = Spring.XXX
-- same as
-- local spXXX = Spring["XXX"]
... means that calling "XXX" ("XXX" being merely the name of the function, _not_ its code address) can be done _without_ first having to look up the value for the key "XXX" in the "Spring" table, since "Spring.XXX(a, b, c)" is only shorthand notation for Spring["XXX"](a, b, c) (thus you eliminate overhead). How large the overhead is (as a function of the table size) depends on the C data structure used to implement Lua's tables, but you don't want it in time-sensitive code and that's why locals are such a big deal. ;)
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Upvalues

Post by jK »

Kloot wrote: since "Spring.XXX(a, b, c)" is only shorthand notation for Spring["XXX"](a, b, c)
it is even more:
_G["Spring"]["XXX"](a,b,c)

(in the case of metatables this can be even ways longer)
Last edited by jK on 30 Aug 2008, 01:38, edited 1 time in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Upvalues

Post by Argh »

Ah... so it's saving not one, but two searches? That explains a lot.
User avatar
REVENGE
Posts: 2382
Joined: 24 Aug 2006, 06:13

Re: Upvalues

Post by REVENGE »

I read on the LUA tutorial that upvalues are basically the equivalent of an inline static variable type from C, meaning that if you initialize an upvalue inside a block or a local function, the value is available for use later on for all other sub-functions in your big main lua function.

Now, is this hard-limit per function, or total? And why do we have it anyways?
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Re: Upvalues

Post by KDR_11k »

jK wrote:Also you should try to avoid to create a local var w/o giving it any input (like "local myvar;").
Is "local myvar = nil" preferred then?
User avatar
FrOzEnTaCo
Posts: 81
Joined: 02 Jul 2008, 05:52

Re: Upvalues

Post by FrOzEnTaCo »

Argh wrote:
What are upvalues?
I probably shouldn't even try to answer this, but here's what I think I know, based on what I've read:

Upvalues are keys that are stored in the stack for a particular Lua execution to use at runtime, when your software needs to either query the API, which then talks to Spring, or send the API a request to make Spring execute a particular function call.

Every bit of information in Lua is basically table-oriented. It's the main thing I hate about Lua, tbh, but I've gradually gotten used to it. It's like hating your talented, popular roommate, who brings all of the men and their friends over on a regular basis- you can hate her, sure, but he's bringing men, woman.

At any rate, using the key to specific table locations in the global area greatly speeds stuff up, because you're not asking Lua to find the key "Color" in the table "gl"- which is what gl.Color really means- you're giving it a very specific key number, and saying, "go there, pass these arguments, do not bother searching".

With the global variables, this is really, really important, because they're huge tables, and table searches are, alas, quite slow.

Therefore, what you want to do, to increase efficiency, is to bring certain common variables or locations within "upper" tables "down" into the stack your program's using, so that your software doesn't have to ever search the huge tables created when Lua's initialized. Then your function loops are basically using this "upper" table- a table that's created when your Lua is initialized, basically- to make their requests to the API using those keys, instead of requesting a search.

Lastly, upvalues are a way to create a "local-global" pool of variables for your various functions- things that all of the functions "know about". If you create a variable within a function loop, that key-value pair can only be searched by that function loop's logic- the other functions simply cannot get access to that data (er, I should say that it's possible, but would be very, very, very difficult and eat CPU like mad).

An example of creating upvalues would be this, outside of a function:

Code: Select all

local glResetState = gl.ResetState
local glColor = gl.Color
local glText = gl.Text
local math_random = math.random
local x,z = 0,0 
Which we could then use inside a function like this:

Code: Select all

function widget:DrawScreen()
x = math_random(0,500)
z = math_random(0,500)
glColor(1,0,1,1)
glText("Hello World",x,z,"rno")
glResetState
end
Basically, it's shorthand for a key value, AF. We cannot entirely avoid going back to the global variables, because those are necessary for the Lua API to pass on to Spring as a function call or query, along with whatever arguments the function wants.

But, there is a limit as to how many key values you can store this way. That's the "upvalues limit", basically, which is the wall I just smacked into. I've been trying to keep everything I need to use in any function an upvalue, because that was pretty much my understanding about good coding practice with this language when I first started talking to Trepan about this, over a year and a half ago.

If your program gets complicated enough, that's not possible. I'm surprised I haven't hit this wall before- anything involving OpenGL involves having to localize a lot of API calls, and that's completely necessary, if you want things to run fast.
Config is set to defaults: 60 upvalues & 200 local vars, the max stack size is 250. I don't know if those upvalues are part of the local vars or if they are seperate, so I don't know if it is possible to increase any of these numbers, but cuz the stacksize limits both of those it wouldn't change a lot.

and yes, lua creates each time it gets a local cmd a new variable on the stack. That's why you should create values only where they are needed and not to create a list of used vars at the top of the function (pascal/delphi style). Also you should try to avoid to create a local var w/o giving it any input (like "local myvar;").
Thanks for the detailed answer, I really appreciate that.

Meh, I need to learn how to profile, and see what the real difference is, between doing it as a populate --> destruct cycle and an iterative table search.

Somehow I'm guessing that it'll come out so close it won't matter a lot for what I'm doing, though- these are all variables that only get used within one function loop, and can be created before the main logical loops within the function start, so it's a one-time cost, vs. table searches over and over and over again. I suspect I come out ahead on speed, in this particular instance.

spot the lol
User avatar
Zpock
Posts: 1218
Joined: 16 Sep 2004, 23:20

Re: Upvalues

Post by Zpock »

Stop worrying about obscure programming tricks and do actual stuff instead?
User avatar
Pxtl
Posts: 6112
Joined: 23 Oct 2004, 01:43

Re: Upvalues

Post by Pxtl »

Argh, this strikes me as premature optimization. If table-hits are causing a real performance cost, by all means gut them out of your innermost loops. But I'm sure that 90% of the time they are having no real impact on your code.
Post Reply

Return to “Lua Scripts”