- Joined
- Jun 23, 2007
- Messages
- 4,066
JASS Benchmarking & Efficiency Results
Feel free to post your own tests or dispute one of mine. I'll be updating this thread with as much info as I can. Remember results may vary depending on your computer.
Much of this has already been known or could be assumed, but it's nice to have the actual numbers and a reference like this.
All tests are done with the StopWatch Natives.
Native comparisons
Other comparisons
Feel free to post your own tests or dispute one of mine. I'll be updating this thread with as much info as I can. Remember results may vary depending on your computer.
Much of this has already been known or could be assumed, but it's nice to have the actual numbers and a reference like this.
All tests are done with the StopWatch Natives.
Native comparisons
- ExecuteFunc
- It seems length of the function name significantly changes the execution time. With a lengths of 1 and 70, the function with a name of length 1 was ~13% faster
- ~27% slower than
TriggerEvaluate
- [Results]
- TriggerEvaluate
- ~87% slower than a function call - [Results]
- ~25% faster than
TriggerExecute
which leads us to believe thattriggercondition
is more efficient thantriggeraction
in terms of execution time.
- UnitAlive
- ~15-20% faster than
GetWidgetLife(u) > 0.405
- ~47-50% faster than
IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0
- ~15-20% faster than
- SetUnitPosition
- ~90% slower than
SetUnitX
&SetUnitY
- ~90% slower than
- SetWidgetLife
- ~15-20% faster than
SetUnitState(u, UNIT_STATE_LIFE, 5)
- ~15-20% faster than
- GetWidgetLife
- ~20% faster than
GetUnitState(u, UNIT_STATE_LIFE)
- [Results]
- ~20% faster than
- GetWidgetX
- ~7-9% slower than
GetUnitX
- ~2-4% slower than
GetItemX
- ~7-9% slower than
Other comparisons
- Group Enumeration (Test Code)
ForGroup
is always the slowest way to enumerate through a unit group. TheFirstOfGroup
method is the fastest except in cases where the unit group has less than a few units. In that case placing your actions inside the enum filter will prove to be considerably faster. In cases where you want to keep the unit group you should swap groups. See vJass Optimization: Using a First of Group Loop for Enumeration
- Recursive Calls
Recursive function calls (like many BJ's) have a relatively significant impact on performance. For exampleGetHandleId
was ~24-28% faster thanGetHandleIdBJ
and it increases within each recursion. - Hashtable vs. Game Cache
Hashtables are faster, nothing too surprising here.
All variables used in my tests were just 1 character long and they were globals as opposed to local. There are too many small tests to include here but they are simple and I'm sure there were no errors.SaveInteger
(hashtable) was ~35-40% faster thanStoreInteger
(game cache). The same goes forSaveStr
vs.StoreString
while booleans may be a tiny bit slower.SaveUnitHandle
was only ~8-12% faster thanStoreUnit
which is a bit odd.
The same speeds mostly still apply for loading, respectively. However when comparingLoadUnitHandle
vs.RestoreUnit
the latter is ~40-45% slower.
JASS:
library Stopwatch initializer onInit
//===========================================================================
//! textmacro STOPWATCH_BENCHMARK_LOCAL_VARIABLES
local real c
//! endtextmacro
//! textmacro STOPWATCH_BENCHMARK_TEST_1
set c = Pow(5, 2)
//! endtextmacro
//! textmacro STOPWATCH_BENCHMARK_TEST_2
set c = (5 * 5)
//! endtextmacro
//! textmacro STOPWATCH_BENCHMARK_INIT
//! endtextmacro
globals
private constant integer ITERATIONS = 1000 // how many times to run each test
private constant string TEST_1 = "Pow(5, 2)"
private constant string TEST_2 = "(5 * 5)"
private constant boolean USE_SLEEP = false // add TriggerSleepAction's between tests
private constant boolean STACK = true // stack iterations
// personal variables here
endglobals
//===========================================================================
globals
private integer C=1 // stack count
private real array R // results
endglobals
// Declare the StopWatch natives
native StopWatchCreate takes nothing returns integer
native StopWatchTicks takes integer id returns integer
native StopWatchMark takes integer id returns integer
native StopWatchDestroy takes integer id returns nothing
private function Actions takes nothing returns nothing
local integer sw
local integer i
local string output = ""
//! runtextmacro STOPWATCH_BENCHMARK_LOCAL_VARIABLES()
// Disable the trigger so it can't be interrupted
call DisableTrigger(GetTriggeringTrigger())
static if (USE_SLEEP) then
call TriggerSleepAction(0)
endif
set i = 0
set sw = StopWatchCreate() // Create the StopWatch
loop
exitwhen i == ITERATIONS // Run test #1 X amount of times
//! runtextmacro STOPWATCH_BENCHMARK_TEST_1()
set i = i + 1
endloop
// If stacking is enabled, the results will add
static if (STACK) then
set R[0] = R[0] + StopWatchTicks(sw)
set R[3] = R[3] + StopWatchMark(sw)
else
set R[0] = StopWatchTicks(sw)
set R[3] = StopWatchMark(sw) // the length in milliseconds it took to run
endif
call StopWatchDestroy(sw)
static if (USE_SLEEP) then
call TriggerSleepAction(0)
endif
set output = "|cff008200===========================================================================|r\n"
set output = output + "|cffffcc00" + I2S(ITERATIONS * C) + "|r iterations of " + TEST_1 + " took |cffffcc00" + I2S(R2I(R[3])) + "|r milliseconds to finish.\n"
static if (USE_SLEEP) then
call TriggerSleepAction(0)
endif
// Set the iteration count to 0
set i = 0
set sw = StopWatchCreate()
loop
exitwhen i == ITERATIONS
// This is where test #2 is being executed
//! runtextmacro STOPWATCH_BENCHMARK_TEST_2()
set i = i + 1
endloop
static if (STACK) then
set R[1] = R[1] + StopWatchTicks(sw)
set R[4] = R[4] + StopWatchMark(sw)
else
set R[1] = StopWatchTicks(sw)
set R[4] = StopWatchMark(sw)
endif
call StopWatchDestroy(sw)
// Enable the trigger
call EnableTrigger(GetTriggeringTrigger())
set output = output + "|cffffcc00" + I2S(ITERATIONS * C) + "|r iterations of " + TEST_2 + " took |cffffcc00" + I2S(R2I(R[4])) + "|r milliseconds to finish.\n\n"
// Display the results
if (R[0] > R[1]) then
set R[2] = 100 - (R[1]/R[0] * 100)
set output = output + TEST_2 + " was " + R2S(R[2]) + "% |cff80ff80faster|r than " + TEST_1 + "\n\n"
else
set R[2] = 100 - (R[0]/R[1] * 100)
set output = output + TEST_1 + " is " + R2S(R[2]) + "% |cff80ff80faster|r than " + TEST_2 + "\n\n"
endif
static if (STACK) then
set C=C+1
endif
set output = output + "|cff008200===========================================================================|r\n\n\n\n\n"
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, output)
endfunction
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i == 15
call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
set i = i + 1
endloop
call TriggerAddAction(t, function Actions)
//! runtextmacro STOPWATCH_BENCHMARK_INIT()
endfunction
//===========================================================================
endlibrary
JASS:
scope Stopwatch initializer onInit
globals
private constant integer ITERATIONS = 4000
endglobals
private function Actions takes nothing returns boolean
local integer sw
local integer i
local real array ticks
local string output
set i = 0
set sw = StopWatchCreate()
loop
exitwhen i == ITERATIONS
// TEST 1 HERE
set i = i + 1
endloop
set ticks[0] = StopWatchTicks(sw)
set output = I2S(ITERATIONS) + " iterations of Test #1 took " + I2S(StopWatchMark(sw)) + " milliseconds to finish.\n"
call StopWatchDestroy(sw)
set i = 0
set sw = StopWatchCreate()
loop
exitwhen i == ITERATIONS
// TEST 2 HERE
set i = i + 1
endloop
set ticks[1] = StopWatchTicks(sw)
set output = output + I2S(ITERATIONS) + " iterations of Test #2 took " + I2S(StopWatchMark(sw)) + " milliseconds to finish.\n\n"
call StopWatchDestroy(sw)
if (ticks[0] > ticks[1]) then
set ticks[2] = 100 - (ticks[1]/ticks[0] * 100)
set output = output + "Test #2 was " + R2S(ticks[2]) + "% faster than Test #1\n\n"
else
set ticks[2] = 100 - (ticks[0]/ticks[1] * 100)
set output = output + "Test #1 is " + R2S(ticks[2]) + "% faster than Test #2\n\n"
endif
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, output)
return false
endfunction
//===========================================================================
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
call TriggerAddCondition(t, function Actions)
endfunction
endscope
Last edited: