NOTE: This tutorial is outdated and has been replaced by the Performance and Optimization guide.


Share this post....Share on Facebook0Share on Google+6Tweet about this on TwitterShare on LinkedIn0
  1. I feel like I need to reinforce the “time-critical” point made near the beginning. Some of these enhancements, such as avoiding table.insert or ipairs, provide better performance, but come with their own costs, such as a reduction in readability or simplicity. They are, precisely, optimizations, code constructs which show advantages primarily when performance is of the utmost concern.

    In particular, if you have to perform several operations on each element in an array, make sure to set a local reference to it inside the loop, or the repeated array lookups will penalize performance more than the function call:

    for i=1, #t do
    local item = t[i]
    action(item)
    item:method()
    end

      • Brent Sorrentino says:

        Hi Jack,
        “pairs” isn’t great, but it’s slightly better than “ipairs”… and with “pairs”, in many cases it’s just the easiest way to iterate over a dictionary table. You should be fine using it, just not inside time-critical (game-loop) code, inside a huge loop.

  2. Realistically, when will we start to see the performance impact of changing a single extra table access into a local?

    Will it be noticeably faster in a for loop of 100 iterations? 1,000? 10,000?

  3. Chris Leyton says:

    Might have been a good idea to put a timeStamp on to show the value of these improvements.

    I cannot stress the importance of localising math.* functions however. I was building a virtual dStick class that uses a fair bit if trig, and was getting 5fps at times on device – localising the relevant math. functions brought this right back to a solid 30fps.

  4. Regarding point 8:
    Could you please verify the following for me: are textures always rounded up to be square in proportion (width = height), or are width and height rounded up to the next power of 2 separately?

    In other words, is a 380 x 700 pixels texture rounded up to 512 x 1024 px or to 1024 x 1024 px. You seem to be saying the latter, but I always thought is was the former.

    Thanks,
    Thomas

    • Hi Thomas,
      It’s the first example that you state (each dimension rounds up to the next PoT independently). I clarified the section on that. Thanks for bringing it to my attention.

      • Hmmm. I’ve come across over the power of two thing again and again, because I keep telling the graphics guys to pay attention to it. Are you sure this is still (if ever) relevant?

        because this test suggest that it isn’t: (both on simulator and ios 6):

        local m0 = system.getInfo(‘textureMemoryUsed’)
        — load an 29×29 pixel image
        display.newImageRect( ‘Icon-Small.png’, 29, 29 )
        print( ‘real memory footprint’, system.getInfo(‘textureMemoryUsed’) – m0 )
        print( ‘exp. memory footprint’, 32*32*4 )

  5. One thing to point out, in #3, I wouldn’t’ recommend using #a as in “critical” loops it doesn’t perform well. If possible, assign the total count to a local variable and use that inside the loop instead.

    Rather than this:
    local a = {}

    for i = 1,100 do
    a[#a+1] = i
    end

    Use this:
    local a = {}
    local aSize = #a

    for i = 1,100 do
    a[aSize+1] = i
    end

    • @christopher aSize doesnt change in your example so you are effectively writing a[1]=i. I think you meant to autoincrement aSize.

      local a = {}
      local aSize = 0

      for i = 1,100 do
      aSize=aSize+1 –autoincrement
      a[aSize] = i
      end

    • Well, your last code only writes one value over and over again, in the same place.
      You set aSize to 0 and then set a[0] to i, from 1 to 100, but aSize is never updated.

      Modifying the loop line to this will do the trick. If we don’t need aSize to be consistent that is.
      for i = 1,100 do
      a[aSize+i] = i
      end

      If we need consistency :
      for i = 1,100 do
      aSize = aSize + 1
      a[aSize] = i
      end

  6. Hi,

    Is there a way to profile games in Corona in order to find the hotspots? Most of these optimizations are great, but will provide a great speed boost only if applied to actual bottlenecks…

    Thanks,
    Rémi

  7. just ran a little test on the simulator

    local iCount=0
    local iRounds=5000000

    function test1(picounter)
    return picounter +1
    end

    function test2()
    iCount = icount +1
    end

    local cClass={}
    cClass.test1=test1
    cClass.test2=test2

    print (“running “..iRounds..” iterations of each test”)
    t1=system.getTimer()
    print( “start: “..t1 )
    iCount=0
    for i=1,iRounds do
    icount=test1(iCount)
    end

    t2=system.getTimer()-t1
    t1=t2
    print( “end – simple function:”..t2)
    iCount=0
    for i=1,iRounds do
    test2()
    end
    t2=system.getTimer()-t1
    t1=t2
    print( “end – global variable:”..t2)

    iCount=0
    for i=1,iRounds do
    icount=cClass.test1(iCount)
    end
    t2=system.getTimer()-t1
    t1=t2
    print( “end – table fn:”..t2)

    iCount=0
    for i=1,iRounds do
    cClass.test2()
    end
    t2=system.getTimer()-t1
    t1=t2
    print( “end – table fn – global:”..t2)

    running 5000000 iterations of each test
    start: 11
    end – simple function:2687
    end – global variable:2355
    end – table fn:4577
    end – table fn – global:4313

    which shows that on the simulator using global variables is faster – but at the expense of coupling, and using tables is about twice as slow – but again at the expense of not being able to encapsulate.

    so its a tradeoff – if its a really time critical beast – go dirty, otherwise maintainability is cheaper in the long run.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>