Performance Optimizations

sportscar
Share on Facebook2Share on Google+6Tweet about this on TwitterShare on LinkedIn0

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


Share on Facebook2Share on Google+6Tweet about this on TwitterShare on LinkedIn0
Brent

Brent Sorrentino serves as a full-time Developer Evangelist for Corona Labs, assisting developers in the forums, maintaining documentation/guides, and creating samples which highlight core features of Corona SDK.

This entry has 15 replies

  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

    • Jack Crow says:

      When talking about avoiding ipairs, does this include for k,v in pairs(obj) ?

      • 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. Jon Simantov says:

    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

    • Brent says:

      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. Christopher says:

    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

    • open768 says:

      @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. Rais says:

    Very good post on the “Optimization topic”, please write about “Prevention Of Memory Leakage Tips” as well.

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

  8. open768 says:

    This is an excellent and informative article – thankyou very much for sharing this.

  9. open768 says:

    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

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