Log In  

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

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

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]


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
P#28317 2016-09-11 12:46 ( Edited 2017-10-26 19:45)

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:

       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

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

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!

P#28320 2016-09-11 13:11 ( Edited 2016-09-11 17:17)

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".

P#28352 2016-09-11 19:42 ( Edited 2016-09-11 23:47)
:: DR4IG

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.

P#45478 2017-10-26 14:27 ( Edited 2017-10-26 18:27)

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).

P#45480 2017-10-26 15:14 ( Edited 2017-10-26 19:23)
:: DR4IG

@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.

P#45482 2017-10-26 15:45 ( Edited 2017-10-26 19:45)

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2021-09-23 07:48:03 | 0.020s | Q:20