Difference between revisions of "Optimizations"

From GiderosMobile
 
 
(5 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
__TOC__
 
__TOC__
  
=== Optimizations ===
 
 
When you're ready to optimize your game, this page can be helpful.
 
When you're ready to optimize your game, this page can be helpful.
 +
 +
=== Luau ===
 +
You can take advantage of Luau new features added to Gideros:
 +
* '''[[Integer Divide Operator]]'''
 +
* '''[[Larger and Smaller Operators]]'''
 +
* '''[[Mutation Operators]]'''
 +
* '''[[Native Code Generation]]'''
 +
* '''[[Trigonometry Conversion Operators]]'''
 +
* '''[[Type Checking]]'''
 +
 +
=== Various Functions ===
 +
Gideros 2025.2 introduces '''setsafeenv'''(''flags'') which tells Luau the global environment is "safe" and so enables optimizations. ''flags'' parameter indicates which optimizations to enable, and you'll probably want them all by using -1 value.
 +
<syntaxhighlight lang="lua">
 +
setsafeenv(-1)
 +
</syntaxhighlight>
 +
 +
You can add '''''setsafeenv(-1)''''' at the beginning of the following tests to see the difference.
  
 
==== '''Distance''' ====
 
==== '''Distance''' ====
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- simple functions test timer by @antix
+
-- distance (based on simple functions test timer by @antix)
local random, sqrt = math.random, math.sqrt
+
local distance, random, sqrt = math.distance, math.random, math.sqrt
  
local x1, y1 = random(-100000, 100000), random(-100000, 100000)
+
local x1, y1, x2, y2 = random(-10000, 10000), random(-10000, 10000), random(-10000, 10000), random(-10000, 10000)
local x2, y2 = random(-100000, 100000), random(-100000, 100000)
+
 
 +
-- classic (boring!)
 
local dx, dy
 
local dx, dy
 +
-- with vectors
 +
local p1, p2 = vector(x1, y1), vector(x2, y2)
  
-- init test
+
-- init
local dist = math.distance(x1, y1, x2, y2)
+
local dist = distance(x1, y1, x2, y2)
 +
print("")
 
print("*** POINT A: "..x1, y1, "POINT B: "..x2, y2)
 
print("*** POINT A: "..x1, y1, "POINT B: "..x2, y2)
print("*** DISTANCE: "..dist)
+
print("*** DISTANCE:     "..dist)
 +
 
 +
dist = #(p2-p1)
 +
print("*** VECTORS DIST.: "..dist)
 +
print("")
  
 
-- tests
 
-- tests
 
local data = {
 
local data = {
 
{
 
{
"sqrt",
+
"sqrt                           ",
 
function()
 
function()
 
dx, dy = x2-x1, y2-y1
 
dx, dy = x2-x1, y2-y1
 
dist = sqrt(dx*dx + dy*dy)
 
dist = sqrt(dx*dx + dy*dy)
end, -- 56ms
+
end, -- 50ms
 
},
 
},
 
{
 
{
"exponent",
+
"exponent                       ",
 
function()
 
function()
 
dx, dy = x2-x1, y2-y1
 
dx, dy = x2-x1, y2-y1
 
dist = (dx^2 + dy^2)^0.5
 
dist = (dx^2 + dy^2)^0.5
end, -- 40ms
+
end, -- 37ms
 
},
 
},
 
{
 
{
"multiply/exponent",
+
"multiply/exponent             ",
 
function()
 
function()
 
dx, dy = x2-x1, y2-y1
 
dx, dy = x2-x1, y2-y1
 
dist = (dx*dx + dy*dy)^0.5
 
dist = (dx*dx + dy*dy)^0.5
end, -- 43ms
+
end, -- 40ms
 
},
 
},
 
{
 
{
Line 46: Line 70:
 
function()
 
function()
 
dx, dy = x2-x1, y2-y1
 
dx, dy = x2-x1, y2-y1
dist = dx*dx + dy*dy
+
-- dist = dx*dx + dy*dy
end, -- 40ms but wrong result!
+
dist = dx^2 + dy^2
 +
end, -- 36ms but wrong result!
 
},
 
},
 
{
 
{
"math.distance",
+
"math.distance                 ",
 
function()
 
function()
dist = math.distance(x1, y1, x2, y2)
+
dist = distance(x1, y1, x2, y2)
end, -- 73ms
+
end, -- 53ms
 +
},
 +
{
 +
"Luau VECTORS                  ",
 +
function()
 +
dist = #(p2-p1)
 +
end, -- 24ms => this is our WINNER (Gideros 2024.11+)
 
},
 
},
 
}
 
}
 +
 +
-- run all functions
 +
for i = 1, #data do
 +
local block = data[i]
 +
local func = block[2]
 +
local start = os.timer()
 +
for i = 1, 1000000 do -- 1 million repetitions!
 +
func()
 +
end
 +
local elapsed = math.floor((os.timer() - start) * 1000)
 +
print(block[1].." ("..elapsed.."ms)", "", "distance: "..dist)
 +
end
 +
 +
--[[ RESULTS
 +
 +
*** POINT A: -4709 7129 POINT B: 5172 7263
 +
*** DISTANCE:      9881.908570716489
 +
*** VECTORS DIST.: 9881.908520118976
 +
 +
sqrt                            (50ms) distance: 9881.908570716489
 +
exponent                        (37ms) distance: 9881.908570716489
 +
multiply/exponent              (40ms) distance: 9881.908570716489
 +
multiply/exponent without power (36ms) distance: 97652117
 +
math.distance                  (53ms) distance: 9881.908570716489
 +
Luau VECTORS                    (24ms) distance: 9881.908520118976]]
 +
</syntaxhighlight>
 +
 +
==== '''Clamp''' ====
 +
<syntaxhighlight lang="lua">
 +
-- clamp (based on simple functions test timer by @antix)
 +
local clamp, random = math.clamp, math.random
 +
 +
local v, mi, ma = random(-15, 15), -10, 10
 +
 +
-- init
 +
local result = clamp(v, mi, ma)
 +
print("")
 +
print("*** V: "..v, "MIN: "..mi, "MAX: "..ma)
 +
print("*** CLAMPED: "..result)
 +
print("")
  
 +
local function fclamp(v, min, max)
 +
return (v <> min) >< max
 +
end
 +
 +
-- tests
 +
local data = {
 +
{
 +
"math.clamp ",
 +
function()
 +
result = clamp(v ,mi, ma)
 +
end, -- 38ms
 +
},
 +
{
 +
"clamp function ",
 +
function()
 +
result = fclamp(v ,mi, ma)
 +
end, -- 20ms, no comments!
 +
},
 +
}
 +
 
-- run all functions
 
-- run all functions
 
for i = 1, #data do
 
for i = 1, #data do
Line 66: Line 157:
 
end
 
end
 
local elapsed = math.floor((os.timer() - start) * 1000)
 
local elapsed = math.floor((os.timer() - start) * 1000)
print(block[1].." ("..elapsed.."ms)", "", "", "", "", "distance: "..dist)
+
print(block[1].." ("..elapsed.."ms)", "", "clamped value: "..result)
 
end
 
end
 +
 +
--[[ RESULTS
 +
 +
*** V: -1 MIN: -10 MAX: 10
 +
*** CLAMPED: -1
 +
 +
math.clamp (38ms) clamped value: -1
 +
clamp function (20ms) clamped value: -1
 +
 +
]]
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 76: Line 177:
  
 
local sprites = {}
 
local sprites = {}
 +
 
for i = 1, 64 do
 
for i = 1, 64 do
 
sprites[i] = {}
 
sprites[i] = {}
Line 99: Line 201:
 
end
 
end
 
end
 
end
end, -- 412ms (our winner!)
+
end, -- 816ms (much better than addChildAt)
 
},
 
},
 
{
 
{
Line 110: Line 212:
 
end
 
end
 
end
 
end
end, -- 636ms
+
end, -- 1272ms
 +
},
 +
{
 +
"async swap",
 +
function()
 +
local function fun()
 +
for _, v in pairs(sprites) do
 +
if v.spr1:getY() < v.spr2:getY() then
 +
spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
 +
stage:swapChildren(v.spr1, v.spr2)
 +
end
 +
end
 +
end
 +
Core.asyncCall(fun) -- profiler seems to be faster without asyncCall (because of pairs traversing?)
 +
end, -- 29ms (the best but has some glitches!)
 
},
 
},
 
}
 
}
Line 119: Line 235:
 
local func = block[2]
 
local func = block[2]
 
local start = os.timer()
 
local start = os.timer()
for i = 1, 12500 do func() end
+
for i = 1, 25000 do func() end -- 12500
 
local elapsed = math.floor((os.timer() - start) * 1000)
 
local elapsed = math.floor((os.timer() - start) * 1000)
 
print(block[1].." ("..elapsed.."ms)", spr1y, spr2y)
 
print(block[1].." ("..elapsed.."ms)", spr1y, spr2y)
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
 +
  
  

Latest revision as of 07:24, 6 February 2025

Supported platforms: Platform android.pngPlatform ios.pngPlatform mac.pngPlatform pc.pngPlatform html5.pngPlatform winrt.pngPlatform win32.pngPlatform linux.png

When you're ready to optimize your game, this page can be helpful.

Luau

You can take advantage of Luau new features added to Gideros:

Various Functions

Gideros 2025.2 introduces setsafeenv(flags) which tells Luau the global environment is "safe" and so enables optimizations. flags parameter indicates which optimizations to enable, and you'll probably want them all by using -1 value.

setsafeenv(-1)

You can add setsafeenv(-1) at the beginning of the following tests to see the difference.

Distance

-- distance (based on simple functions test timer by @antix)
local distance, random, sqrt = math.distance, math.random, math.sqrt

local x1, y1, x2, y2 = random(-10000, 10000), random(-10000, 10000), random(-10000, 10000), random(-10000, 10000)

-- classic (boring!)
local dx, dy
-- with vectors
local p1, p2 = vector(x1, y1), vector(x2, y2)

-- init
local dist = distance(x1, y1, x2, y2)
print("")
print("*** POINT A: "..x1, y1, "POINT B: "..x2, y2)
print("*** DISTANCE:      "..dist)

dist = #(p2-p1)
print("*** VECTORS DIST.: "..dist)
print("")

-- tests
local data = {
	{
		"sqrt                           ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = sqrt(dx*dx + dy*dy)
		end, -- 50ms
	},
	{
		"exponent                       ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = (dx^2 + dy^2)^0.5
		end, -- 37ms
	},
	{
		"multiply/exponent              ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = (dx*dx + dy*dy)^0.5
		end, -- 40ms
	},
	{
		"multiply/exponent without power",
		function()
			dx, dy = x2-x1, y2-y1
--			dist = dx*dx + dy*dy
			dist = dx^2 + dy^2
		end, -- 36ms but wrong result!
	},
	{
		"math.distance                  ",
		function()
			dist = distance(x1, y1, x2, y2)
		end, -- 53ms
	},
	{
		"Luau VECTORS                   ",
		function()
			dist = #(p2-p1)
		end, -- 24ms => this is our WINNER (Gideros 2024.11+)
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 1000000 do -- 1 million repetitions!
		func()
	end
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", "", "distance: "..dist)
end

--[[ RESULTS

*** POINT A: -4709	7129	POINT B: 5172	7263
*** DISTANCE:      9881.908570716489
*** VECTORS DIST.: 9881.908520118976

sqrt                            (50ms)		distance: 9881.908570716489
exponent                        (37ms)		distance: 9881.908570716489
multiply/exponent               (40ms)		distance: 9881.908570716489
multiply/exponent without power (36ms)		distance: 97652117
math.distance                   (53ms)		distance: 9881.908570716489
Luau VECTORS                    (24ms)		distance: 9881.908520118976]]

Clamp

-- clamp (based on simple functions test timer by @antix)
local clamp, random = math.clamp, math.random

local v, mi, ma = random(-15, 15), -10, 10

-- init
local result = clamp(v, mi, ma)
print("")
print("*** V: "..v, "MIN: "..mi, "MAX: "..ma)
print("*** CLAMPED:	"..result)
print("")

local function fclamp(v, min, max)
	return (v <> min) >< max
end

-- tests
local data = {
	{
		"math.clamp		",
		function()
			result = clamp(v ,mi, ma)
		end, -- 38ms
	},
	{
		"clamp function	",
		function()
			result = fclamp(v ,mi, ma)
		end, -- 20ms, no comments!
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 1000000 do -- 1 million repetitions!
		func()
	end
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", "", "clamped value: "..result)
end

--[[ RESULTS

*** V: -1	MIN: -10	MAX: 10
*** CLAMPED:	-1

math.clamp		 (38ms)		clamped value: -1
clamp function	 (20ms)		clamped value: -1

]]

Sprite Sorting

-- sprite sorting (based on simple functions test timer by @antix)
local random = math.random

local sprites = {}

for i = 1, 64 do
	sprites[i] = {}
	sprites[i].spr1 = Pixel.new(0x0, 1, 64, 64)
	sprites[i].spr1:setPosition(random(1, 640), 48) -- 48, 96
	stage:addChild(sprites[i].spr1)
	sprites[i].spr2 = Pixel.new(0xff0000, 1, 64, 64)
	sprites[i].spr2:setPosition(random(1, 640), 64)
	stage:addChild(sprites[i].spr2)
end

local spr1y, spr2y = 0, 0

-- tests
local data = {
	{
		"swap",
		function()
			for _, v in pairs(sprites) do
				if v.spr1:getY() < v.spr2:getY() then
					spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
					stage:swapChildren(v.spr1, v.spr2)
				end
			end
		end, -- 816ms (much better than addChildAt)
	},
	{
		"addChildAt",
		function()
			for _, v in pairs(sprites) do
				if v.spr1:getY() < v.spr2:getY() then
					spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
					stage:addChildAt(v.spr1, stage:getChildIndex(v.spr2))
				end
			end
		end, -- 1272ms
	},
	{
		"async swap",
		function()
			local function fun()
				for _, v in pairs(sprites) do
					if v.spr1:getY() < v.spr2:getY() then
						spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
						stage:swapChildren(v.spr1, v.spr2)
					end
				end
			end
			Core.asyncCall(fun) -- profiler seems to be faster without asyncCall (because of pairs traversing?)
		end, -- 29ms (the best but has some glitches!)
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 25000 do func() end -- 12500
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", spr1y, spr2y)
end




More to come, God's willing!