Log In  


Cart #45477 | 2017-10-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
1

Cart #28315 | 2016-09-11 | Code ▽ | Embed ▽ | No License
1

I was recently trying to reduce the number of tokens in one of my games and tried changing some of my loops from this form:

for i=1,#list do
 local item=list[i]

to:

for item in all(list) do

But found out my game's performance suffered greatly. Check out the demo starfield cart, press <x> to see the how the results of stat(1) differ between methods.

Has anyone else stumbled upon this problem?

Update: demonstrate iterations using pairs since that seems to be the most performant way of doing it:

for key,item in pairs(list) do
1


I think it has to do with the overhead of "for ... in" loop iterators in Lua. Under the hood, an "for ... in" loop will perform a function call per iteration of the loop.

According to the Lua 5.2 docs, this is how a generic / iterator-style for loop works.


A for statement like

     for var_1, ···, var_n in explist do block end

is equivalent to the code:

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         if var_1 == nil then break end
         var = var_1
         block
       end
     end

Note the following:

explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
f, s, and var are invisible variables. The names are here for explanatory purposes only.
You can use break to exit a for loop.
The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

all(t) could be implemented something like this:

function all(t)
 local i = 0
 return function(t)
  i = i + 1
  return t[i]
 end, t
end

all is a function that returns a closure. This closure keeps the current position in the table and returns the next element when called by a for loop. But those extra calls will add an extra overhead per iteration, which can add up CPU time with a large element count in your table. Meanwhile with a counted for loop, it can evaluate start, end and step once before the start of the loop.

Hope that helps!


Thanks Overkill! That's an awesomely detailed explanation which makes a lot of sense. I wonder if foreach would yield better results.

edit: i just tried it real quick and "foreach" seems to have a very similar problem to using "all".


Well right off the bat I can tell you 2500 stars is too much. Anything from 1783 stars to about 5000 taxes the drawing engine considerably.


Did you try running the cart, DR4IG? On my end it performs reasonably well.

But that's besides the point, the amount is set specifically large to test performance (although I do draw a lot of objects on The.Green.Legion, bullets, stars, enemies, etc).


@guerragames: Actually I'm going with personal experience as I published a parallaxing routine earlier.
Those seem to be the limits for individual moving objects before stutter starts happening.



[Please log in to post a comment]