Difference between revisions of "Optimizations"
From GiderosMobile
(Created page with "'''Supported platforms:''' File:Platform android.pngFile:Platform ios.pngFile:Platform mac.pngFile:Platform pc.pngFile:Platform html5.pngFile:Platform wi...") |
|||
(5 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
__TOC__ | __TOC__ | ||
− | |||
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(- | + | local x1, y1, x2, y2 = random(-10000, 10000), random(-10000, 10000), random(-10000, 10000), random(-10000, 10000) |
− | + | ||
+ | -- classic (boring!) | ||
local dx, dy | local dx, dy | ||
+ | -- with vectors | ||
+ | local p1, p2 = vector(x1, y1), vector(x2, y2) | ||
− | -- init | + | -- init |
− | local dist = | + | 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, -- | + | 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, -- | + | 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, -- | + | 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 | |
− | end, -- | + | dist = dx^2 + dy^2 |
+ | end, -- 36ms but wrong result! | ||
}, | }, | ||
{ | { | ||
− | "math.distance", | + | "math.distance ", |
function() | function() | ||
− | dist = | + | dist = distance(x1, y1, x2, y2) |
− | end, -- | + | 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)", "", " | + | 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, -- | + | end, -- 816ms (much better than addChildAt) |
}, | }, | ||
{ | { | ||
Line 110: | Line 212: | ||
end | end | ||
end | 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!) | ||
}, | }, | ||
} | } | ||
Line 119: | Line 235: | ||
local func = block[2] | local func = block[2] | ||
local start = os.timer() | local start = os.timer() | ||
− | for i = 1, | + | 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
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.
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!