Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

[Tips] Optimization 101
Started by Danny Dec 02 2011 06:45 PM

* * * * * 8 votes
87 replies to this topic
[TOPIC CONTROLS]
« Page 4 of 4 2 3 4
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#76

Hendrix000007

[GLOBAL: userInfoPane.html]
Hendrix000007
  • Contributor

  • 177 posts
  • Corona SDK

@Rob Miracle

You are like a lexicon man :)

thanx



[TOPIC: post.html]
#77

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,588 posts
  • Corona SDK

(Disclaimer: Verify this on your target platform before believing this.)

 

Current testing Results

  • Simulator on Windows 7 PC - num ^ 0.5 = 40%+ faster
  • iPad Air Gen 1 (iOS 8.02) - math.sqrt() = %21 faster

 

The Real Take Away

Test any optimization on your target machine before assuming it will work. 

 

 

 

The Short Description Of This Tip (for the attention-challenged  ;) )

local sqrt( num )
   return num ^ 0.5
end

may be  faster than:

local mSqrt = math.sqrt
local sqrt( num )
   return mSqrt( num )
end

The Long Description Of This Tip

 

I recently answered a math question which led me to calculate the Nth root of a number.  The equation for this is:

local function( num, root )
   return num ^ 1/root
end

While there is nothing exciting about this, it suddenly occurred to me that this might be faster than the math.sqrt function for root == 2.  

 

It is!  .... or is it?

 

On my windows test machine, num^0.5 is almost 40% faster than a localized math.sqrt() call.  However, on my iPad Air math.sqrt is 21% faster

 

 

Here is my test code:


local function round(val, n)
  if (n) then
    return math.floor( (val * 10^n) + 0.5) / (10^n)
  else
    return math.floor(val+0.5)
  end
end

local function test1( num )
   local mSqrt = math.sqrt
   local startTime = system.getTimer()
   local v
   for i = 1, num do
      v = mSqrt(i)
   end
   local endTime = system.getTimer()
   local dt = (endTime-startTime)
   print("math.sqrt x " .. num .. " == " .. dt .. " ms" )
   return dt
end

local function test2( num )
   local mSqrt = math.sqrt
   local startTime = system.getTimer()
   local v
   for i = 1, num do
      v = i^0.5
   end
   local endTime = system.getTimer()
   local dt = (endTime-startTime)
   print("M^0.5 x " .. num .. " == " .. dt .. " ms" )
   return dt
end

local t1 = 0
local t2 = 0
t1 = t1 + test1(1000000)
t1 = t1 + test1(1000000)
t1 = t1 + test1(1000000)
t2 = t2 + test2(1000000)
t2 = t2 + test2(1000000)
t2 = t2 + test2(1000000)

if( t1 > t2 ) then
   print(" M^0.5 is faster by " .. round( 1 - t2/t1,2 ) * 100 .. "%"  )
else
   print(" math.sqrt is faster by " .. round( 1 - t1/t2,2 ) * 100 .. "%"  )
end

Edited by roaminggamer, 17 March 2015 - 12:23 PM.


[TOPIC: post.html]
#78

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 815 posts
  • Corona SDK

@roaminggamer

 

On that same note, I've found multiplying by powers of 2, e.g. x * 2^power, quite a lot faster than bit.lshift() or math.ldexp() (with the localizations, of course) in the Windows simulator. On device, I don't know if I've done any tests. Likewise x^2 versus x * x (lookup local, invoke operator with constant, vs. lookup local, lookup "another" local, invoke operator).

 

On the subject of bitwise ops, where possible, I tend to favor the + and - operators over of bit.bor() and bit.band() / bit.bnot(). The % operator, on the other hand, still seemed pretty expensive vs. bit.band().

 

Any non-Windows numbers, or contrary results on Windows itself, would be much appreciated!



[TOPIC: post.html]
#79

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,588 posts
  • Corona SDK

For optimization geeks, I created an additional way to test the above (requires above code):



local function visualizeResults2( test1, test2, size, num, doPower )
	local t1 = 0
	local t2 = 0
	size = size or 2
	num = num or 100
	
	local t1 = 0
	local t2 = 0
	local count = 1

	local width  = round(display.contentWidth/size)
	local height = round(display.contentHeight/size)

	local yield = coroutine.yield

	print("Running ", width * height * num * 2, " calculations." )
	local lastTime = getTimer()
	local timerID
	local wrapped = coroutine.wrap( 
		function( event ) 
			for i = 1, height do
				for j = 1, width do
					if( doPower ) then
						t1 = test1( num, 10^(count-1) )
						t2 = test2( num, 10^(count-1) )
					else
						t1 = test1( num, count )
						t2 = test2( num, count )
					end
					local tmp = display.newRect( (j-1) * size, (i-1) * size,  size, size )
					tmp.anchorX = 0
					tmp.anchorY = 0
					if( t1 > t2 ) then
					--if( count%7 == 0 ) then
						tmp:setFillColor(0,1,0)
					else
						tmp:setFillColor(1,0,0)
					end
					count = count + 1
					--if( count%100 == 0 ) then yield() end
					if( getTimer() - lastTime > 25 ) then
						lastTime = getTimer()
						yield()
					end
					
				end
			end
			print("DONE")
			timerID = event.source
			timer.cancel(timerID)
		end )
	timer.performWithDelay( 1, wrapped, 0 )


end


visualizeResults2( test1, test2, 8, 10000, true )

This produces a full page visualization of what numbers are faster one way or the other.  Interestingly for certain powers of 10, one method is faster than the other.

 

Note: I think  I have an error in the above code as it crashes at the end. oops!



[TOPIC: post.html]
#80

Hendrix000007

[GLOBAL: userInfoPane.html]
Hendrix000007
  • Contributor

  • 177 posts
  • Corona SDK

@StarCrunch

Yes, it is actually a real handy little thing the do command

If there is a certain order you like to fire functions and blocks of code, you can put them in do blocks

and the way you show it here is really nice because the variables lives just as long as the do block is active

when it´s done executing, the scope is gone and all the local variables in the scope is released too

I use it quite often 



[TOPIC: post.html]
#81

Hendrix000007

[GLOBAL: userInfoPane.html]
Hendrix000007
  • Contributor

  • 177 posts
  • Corona SDK

Here´s a couple of functions I made to both check what´s actually going on inside the package.loaded table at runtime:

 

I make a global function in the mainfile:

function printClasses()
for k,v in pairs(_G.package.loaded) do
  print(k)
end
end
function deleteClass(class)
if package.loaded[class] then
  package.loaded[class] = nil
  print("**** Removed class: " .. class, " ******")
end
end

If you run your code with theese functions inside you can look in the terminal and se all the modules/ classes loaded.

Now, if you have modules loaded in your scripts like i.e:

require("MyModule")

This will be listed in the terminal window if you call:

printClasses()

Now, let´s say that you want to clean up because the player has won or lost and he/ she is taken to a typical gameover page you can run the second function and remove the module completely, you just call the function from whereever you like in your code:

deleteClass("MyModule")

The simulator will print out: **** Removed class: MyModule  ******

 

I use these functions alot



[TOPIC: post.html]
#82

evanspro

[GLOBAL: userInfoPane.html]
evanspro
  • Contributor

  • 186 posts
  • Corona SDK

Thanks a lot Hendrix000007 ! It's gonna be very usefull to me :)



[TOPIC: post.html]
#83

noriega

[GLOBAL: userInfoPane.html]
noriega
  • Observer

  • 25 posts
  • Corona SDK

https://docs.coronalabs.com/guide/basics/optimization/index.html

 

I noticed the localizing parts refer to the main lua libraries (math, io, type),  

 

1st question: Would this also prove useful to the corona sdk libraries.. such as if i was creating a lot of display.newText's in a file,  would be better or worse if I was to declare local dNewText = display.newText or would there be no noticeable difference? 
 

2nd question: I am also assuming that all these core lua functions are ones I should be localize for optimization if I use them in my code.

On the bottom of the manual
http://www.lua.org/manual/5.1/

 

 

I am trying to find the find the line between optimization and over optimization.



[TOPIC: post.html]
#84

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,588 posts
  • Corona SDK

@noribl87,

 

1. Localization would make it faster, but not noticeably unless you did many.

 

2. Localization gives you the most speedup for functions where, the 'table lookup' is comparable to the execution time of the function.

 

(T below is a 'made up unit of time' for the examples just to show relative improvement)

 

Example 1 -  Short Execution Time:

  • 'table lookup' is 2T
  • function execution in 10T
  • total cost to call == 12T

Localized lookup:

  • localized lookup is 1T 
  • function execution in 10T
  • total cost to call == 11T
  • 9% improvement

 

Example 2 - Long Execution time

  • 'table lookup' is 2T 
  • function execution in 100T
  • total cost to call == 102T

Localized lookup:

  • localized lookup is 1T 
  • function execution in 100T
  • total cost to call == 101T
  • 1% improvement

 

 

Generally, I use localization for two reasons:

  • Speedup
  • Ease of typing (more valuable for your example)

 

So in your example, I'd simply do this:

local newText = display.newText -- some speedup, way faster to type.

  • noriega likes this

[TOPIC: post.html]
#85

noriega

[GLOBAL: userInfoPane.html]
noriega
  • Observer

  • 25 posts
  • Corona SDK

Makes sense,  I'm assuming the corona libraries are optimized enough so they are not as long with lookup times vs calling a core lua library  :).  But yeah, I'll experiment around and see if there is any negligible improvement.

 

thanks



[TOPIC: post.html]
#86

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,062 posts
  • Enterprise

Can't argue too much with Ed's logic in particular that newText is easier to type that display.newText. The one thing is supportability. I was just looking at a project for someone else and they had abstracted things out and it made it tougher to read.

 

But on software optimization, you need to decide how often you are calling an API call. For instance, if you only need one random number at the beginning of a scene:create() event, The few microseconds you would gain isn't really perceivable. Our modern devices execute 10's of millions of instructions per second.

 

Now lets say you're generating a curve and need to call a lot of sin(), cos() and other trig functions in a tight loop, then those few microseconds add up in a hurry.


  • noriega likes this

[TOPIC: post.html]
#87

msahil

[GLOBAL: userInfoPane.html]
msahil
  • Enthusiast

  • 35 posts
  • Corona SDK

Please help me in optimizing the code below , it hangs in few seconds.-
 
----------------------------------------------------------------------------------------
--
-- main.lua
--
-----------------------------------------------------------------------------------------
 
-- Your code here
local physics = require "physics"
 
physics.start()
physics.setGravity( 0, 0)
local  math = require("math")
display.setStatusBar(display.HiddenStatusBar) 
local outermainarray={}
 
local h2=820;
 
local dotsforshootarray = {}
local bulletanglearray={}
local dotarray={}
local pausedcircle11
local pausedcircle
local id=1;
local DX, DY = 3, 3
local XMIN, XMAX = 1, display.contentWidth-1
local YMIN, YMAX = 20, display.contentHeight-1
 
 _W = display.contentWidth; -- Get the width of the screen
 _H = display.contentHeight; -- Get the height of the screen
 motionx = 0; -- Variable used to move character along x axis
 speed = 2; -- Set Walking Speed
local w = display.contentWidth
local h = display.contentHeight
local centerX = display.contentCenterX
local centerY = display.contentCenterY
 
local myTable = {}
 
 
 
local rect
 
local Cos = math.cos
local Sin = math.sin
local Rad = math.rad
local Atan2 = math.atan2
local Deg = math.deg 
 
local function arc(x, y, radius, theta1, theta2, width, detail)
local vertices = {};
local k = 1;
 
----------------------------------------------
-- UPRIGHT - Comment out UPSIDE DOWN if using
----------------------------------------------
for i = (360 - theta2), (360 - theta1), detail
do
vertices[k] = radius*math.cos(2*math.pi*(i / 360));
vertices[k + 1] = radius*math.sin(2*math.pi*(i / 360));
k = k + 2;
end
for i = ((360 - theta1) - ((360 - theta1) % detail)), (360 - theta2), -detail
do
vertices[k] = (radius - width)*math.cos(2*math.pi*(i / 360));
vertices[k + 1] = (radius - width)*math.sin(2*math.pi*(i / 360));
k = k + 2;
end
 
 
 
return display.newPolygon(x, y, vertices), vertices;
end
local function spawnnewloop( event )
 
 
 
  
          
 
 
          
print(myTable)
            local function spawnnewrings(event)
 
                  
for s=#myTable,1,-1 do
      
 
if myTable[s]~=nil   then
if myTable[s].y>1200 then
 
transition.cancel( myTable[s] )
 
display.remove(myTable[s])
 
  myTable[s] = nil
  end
end
end
 
                       
if #myTable<200 then
           spawnnew()
 
 end
              end
 
 
for j=#myTable,1,-1 do
if(myTable[j]~=nil) then
          transition.to(myTable[j],{time=2000, y=myTable[j].y+1200,onComplete=spawnnewrings})
  end
  end
            
                 
 
                
         
 
            
    
 
 
end
 
function spawnBubble(ringx,ringy,ringradi,ringstart,ringend,bubblex,bubbley,rotationspeed)
-- add bottom arch 2
 
  
 
 
 
 
 
 
 
       local circle2bubble =display.newCircle(display.contentWidth/2,display.contentHeight/2,25)
 
 
 circle2bubble:setFillColor( 0, 1, 1 )
circle2bubble.x = bubblex
circle2bubble.y = bubbley-364
circle2bubble.linearDamping=0
circle2bubble.myName="bubble"
physics.addBody(circle2bubble)
 
 transition.to(circle2bubble,{time=1000, y=bubbley,x=bubblex})
 
 circle2bubble.isSensor = true
 myTable[#myTable+1]=circle2bubble
 
 
 transition.to(circle2,{time=1000, y=ringy,x=ringx})
 
 
 
end
 
 
 
function spawnnew( event )
 
if (myTable[#myTable]~=nil) then
 
 
h2=myTable[#myTable].y-200
 
end
for m = 1, 5 do
if(m%5==1) then
spawnBubble(384,h2, 2, -95,2,384,h2,6.5)
 
end
 
if(m%5==2)  then
spawnBubble(160,h2, 2, -95,2,160,h2,6.5)
end
if(m%5==3)  then
spawnBubble(520, h2, 2, -95,2,520,h2,6.5)
end
 
if(m%5==4)  then
spawnBubble(190, h2, 2, -95,2,190,h2,6.5)
end
if(m%5==0)  then
spawnBubble(500, h2, 2, -95,2,500,h2,6.5)
spawnnewloop()
 
--h2=h2+700
end
h2=h2-200
end
 
 
 
end
 
 
 
 
spawnnew()


[TOPIC: post.html]
#88

toril.swift

[GLOBAL: userInfoPane.html]
toril.swift
  • Observer

  • 6 posts
  • Corona SDK

Hiiiiiii.
This  information is  a  best  and  funtastic  info...i liked this  info  i  want  more   info this 
easily types....so you create  more  topics  so you  add me  b cose  i liked very liked this topics




[topic_controls]
« Page 4 of 4 2 3 4
 
[/topic_controls]