• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] [PROVED] Parameters are faster than declaring/nulling locals

Status
Not open for further replies.

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
[PROVED] Benchmarks are unreliable.

The following benchmark results show something that should be quite revolutionary for current JASS coding:

JASS:
    private function calla2 takes unit u returns nothing
    endfunction
    private function calla1 takes nothing returns nothing
        call calla2(null)
    endfunction
    // the above function, though it involves a call, is consistently faster than
    // the below function.  The R2S strings that the benchmark results in
    // show, on average 6.5 for the double-function, and 7.5 for the below function.
    // that means that passing a single unit through a parameter is about 13%
    // faster than declaring that unit as a local and then nulling it.  Further tests
    // that involve four variables instead of just one, increased the gap so that
    // the double-function parameter call was consistently 22-25% faster than the
    // declaring/nulling of its counterpart.
    private function callb takes nothing returns nothing
        local unit u
        set u = null
    endfunction

JASS:
library Benchmark initializer OnInit
    ///////////////////////////////////////////////
    // Native declarations for stopwatch natives //
    //  - Requires no modified common.j import   //
    ///////////////////////////////////////////////
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
 
    /////////////////////////
    // Benchmarking script //
    /////////////////////////
 
    // Initialisation
    globals
        // ...
    endglobals
 
    private function Init takes nothing returns nothing
        // things required to be performed once before your test
    endfunction
 
    // Tests
    globals
    private constant string TITLE_A="Test A Name"
    //! textmacro Benchmark__TestA
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
        call calla1()
    //! endtextmacro
    private constant string TITLE_B="Test B Name"
    //! textmacro Benchmark__TestB
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
        call callb()
    //! endtextmacro
    endglobals
 
    private function calla2 takes unit u returns nothing
    endfunction
    private function calla1 takes nothing returns nothing
        call calla2(null)
    endfunction
 
    private function callb takes nothing returns nothing
        local unit u
        set u = null
    endfunction
 
    // execution
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        loop
            exitwhen i==0
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local integer i=100
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
 
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
 
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg(TITLE_A+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
 
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg(TITLE_B+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
    endfunction
 
    ///////////////////////////////
    // Registers the OnEsc event //
    ///////////////////////////////
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary
 
Last edited:
Level 12
Joined
Apr 15, 2008
Messages
1,063
I used JASS Benchmark to test this and the result was the exact opposite, parameter version beeing ~40% slower (for one-parameter, the difference becoming smaller with more parameters)

I am not sure about precision of such benchmarks, because some test I did indicated that putting a long comment (2-3x more lines than the function has) inside the function will increase execution speed of the function by 10-40% :grin:
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
I can confirm this
my benchmark setup:
JASS:
function a takes unit u returns nothing
endfunction

function b takes nothing returns nothing
    local unit u = udg_u
    set u = null
endfunction
  • a
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Set i = 0
      • Custom script: loop
      • Custom script: exitwhen udg_i == 5000
      • Custom script: call a(udg_u) or call b()
      • Set i = (i + 1)
      • Custom script: endloop
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i2 Less than 1000
        • Then - Actions
          • Set i2 = (i2 + 1)
          • Trigger - Run (This trigger) (ignoring conditions)
        • Else - Actions
          • Set i2 = 0
empty loop: 2 seconds
passing parameter: 5 seconds
creating local variable, setting it to a global one and nulling it: 7 seconds

this was measured with a manual stopwatch and will be different on other pcs

edit:
20 lines of
JASS:
//1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
didn't have any measurable effects

edit2:
what the fuck
minimizing and maximizing wc3 leaks at least a Megabyte of memory o_O (edit4: of course I am talking about minimizing AND maximizing both together so in the end I end up with at least one more mb of ram)

edit3:
I called function b without the set u = null a million times and it did not leak or leak that less that I could not measure it so it is crap to say that one has to null locals because of leak
however it might be safer if there is a max handle limit or something like that
 
Last edited:
Level 12
Joined
Apr 15, 2008
Messages
1,063
Ehm... the thing with comments was to illustrate that these benchmarks often produce wrong results (it's obviously nonsence), however it really gave me that result (with 2-3 times comment lines than program lines, it was faster, otherwise slower)
Minimizing and maximizing does leak? For me, it always decreases used memory by ~100 MB
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,199
JumpTo instructions with a JumpTo on a variable to return it would be the fastest possible function like extending that could occur as there would be no stack dumping and stuff which occurs with function calls. The problem however is this function would inherit the current variables which could be an advantage and a disdvantage and that is not including the logical one of JASS not having axcess to those instructions.

Calling will always have a slow down effect due to stack dumping. Having been unable to find the compiled jass script in memory, I can not tell you exactly how parameters and variables are done in JASS.

The reason why globals are faster is because their addresses are probably near static once defined and that they never go through allocation and dealocation like locals do. Additionally they never have to be dumped onto a stack as they are not part of the current execution level.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
Who cares.
AFAIK globals are faster than both.
No, actually locals are about 85-90% faster than globals =)



localVSglobal.jpg


JASS:
library Benchmark initializer OnInit
    ///////////////////////////////////////////////
    // Native declarations for stopwatch natives //
    //  - Requires no modified common.j import   //
    ///////////////////////////////////////////////
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
 
    /////////////////////////
    // Benchmarking script //
    /////////////////////////
 
    // Initialisation
    globals
        // ...
        private unit v
    endglobals
 
    private function Init takes nothing returns nothing
        // things required to be performed once before your test
    endfunction
 
    // Tests
    globals
    private constant string TITLE_A="local"
    //! textmacro Benchmark__TestA
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
        set u = null
    //! endtextmacro
    private constant string TITLE_B="global"
    //! textmacro Benchmark__TestB
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
        set v = null
    //! endtextmacro
    endglobals
 
    // execution
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        local unit u
        loop
            exitwhen i==0
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local integer i=100
        local unit u
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
 
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
 
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cff66ddff"+TITLE_A+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
 
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cffddff66"+TITLE_B+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
    endfunction
 
    ///////////////////////////////
    // Registers the OnEsc event //
    ///////////////////////////////
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary


This next test actually showed setting a local to local is consistently 105-110% faster than setting a global to a global.


JASS:
library Benchmark initializer OnInit
    ///////////////////////////////////////////////
    // Native declarations for stopwatch natives //
    //  - Requires no modified common.j import   //
    ///////////////////////////////////////////////
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
    
    /////////////////////////
    // Benchmarking script //
    /////////////////////////
    
    // Initialisation
    globals
        // ...
        private unit v
        private unit h = CreateUnit(Player(15),'hfoo',0.,0.,0.)
    endglobals
    
    private function Init takes nothing returns nothing
        // things required to be performed once before your test
    endfunction
    
    // Tests
    globals
    private constant string TITLE_A="global to global"
    //! textmacro Benchmark__TestA
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
    //! endtextmacro
    private constant string TITLE_B="local to local"
    //! textmacro Benchmark__TestB
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
    //! endtextmacro
    endglobals
    
    // execution
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        local unit u
        local unit j = h
        loop
            exitwhen i==0
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local integer i=100
        local unit u
        local unit j = h
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
    
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cff66ddff"+TITLE_A+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cffddff66"+TITLE_B+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
    endfunction
    
    ///////////////////////////////
    // Registers the OnEsc event //
    ///////////////////////////////
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,199
Hmm I wonder how thats justified... By the looks of it it may be that all globals are pointers to the actual data they store as apposed to locals which point directly to the data they store.

It might also be due to how they are cached. Whereas globals get forced to RAM always, locals might always remain in cache due to their small scope size.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
locals are faster than globals

which does not matter that much anymore since you found out that parameters are even faster :grin:

This next test actually showed setting a local to local is consistently 105-110% faster than setting a global to a global.

I got 19 sec for locals and 21 for globals
however this might turn out much worse since you have to create and remove/null/destroy locals all day long and can only use them locally :bored:
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
which does not matter that much anymore since you found out that parameters are even faster :grin:
Well, setting a parameter/referencing it within a function is the same speed as using a local/referencing it within a function. The only thing that makes parameters faster is that you don't have to null them.

I got 19 sec for locals and 21 for globals
Using a manual stopwatch, right? I ran this test hundreds of times yesterday using stopwatch natives, and even tried switching things around. local/parameter lookups are about twice as fast as global lookups.

Interestingly, I found about a 5% speed difference between arrays and globals, while Hashtables are about 400% slower than either of them.
 
Interestingly, I found about a 5% speed difference between arrays and globals, while Hashtables are about 400% slower than either of them.

Are you sure you're doing the right tests? I've tested hashtables vs. arrays and it has been consistently arrays, but only 75% faster. :bored:

EDIT3: Ok, I've fixed it. Here are my results from spamming ESC:
JASS:
library Benchmark initializer OnInit
    ///////////////////////////////////////////////
    // Native declarations for stopwatch natives //
    //  - Requires no modified common.j import   //
    ///////////////////////////////////////////////
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
    
    /////////////////////////
    // Benchmarking script //
    /////////////////////////
    
    // Initialisation
    globals
        // ...
        unit h
        unit u 
    endglobals
    
    private function Init takes nothing returns nothing
        set u = CreateUnit(Player(15),'hfoo',1000,1000,0)
        // things required to be performed once before your test
    endfunction
    // Tests
    globals
    private constant string TITLE_A="Globals"
    //! textmacro Benchmark__TestA
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
        set h = u
    //! endtextmacro
    private constant string TITLE_B="Local Variables"
    //! textmacro Benchmark__TestB
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
        set x = u
    //! endtextmacro
    endglobals
    
    // execution
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        loop
            exitwhen i==0
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local unit x
        local integer i=100
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
    
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cff66ddff"+TITLE_A+" : "+R2S(StopWatchMark(sw)*100)+"|r")
        call StopWatchDestroy(sw)
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cffddff66"+TITLE_B+" : "+R2S(StopWatchMark(sw)*100)+"|r")
        call StopWatchDestroy(sw)
    endfunction
    
    ///////////////////////////////
    // Registers the OnEsc event //
    ///////////////////////////////
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary
attachment.php


Those are my results. Yeah, it varies for the most part, but globals are a bit faster when you add in the fact that local agents need to be nulled. =P Not to mention locals are constantly redeclared, whereas globals are declared once.
 

Attachments

  • TestBenchGlobLoc2.jpg
    TestBenchGlobLoc2.jpg
    113.1 KB · Views: 255
At the moment, it is all we have though. They might be reliable or they might not be, even little things can screw it up or change the tests completely, especially when executed 10,000 or 100,000 times. :grin:

I've added some comments to differentiate between mine and yours:
JASS:
library Benchmark initializer OnInit
    ///////////////////////////////////////////////
    // Native declarations for stopwatch natives //
    //  - Requires no modified common.j import   //
    ///////////////////////////////////////////////
    native StopWatchCreate  takes nothing returns integer
    native StopWatchMark    takes integer stopwatch returns real
    native StopWatchDestroy takes integer stopwatch returns nothing
    
    /////////////////////////
    // Benchmarking script //
    /////////////////////////
    
    // Initialisation
    globals
        // ...
        private unit v
        private unit h = CreateUnit(Player(15),'hfoo',0.,0.,0.)
        //you create the unit in your global block, I made mine in the Init function
        //I don't think the unit is made when done like this, not sure though
    endglobals
    
    private function Init takes nothing returns nothing
        // things required to be performed once before your test
    endfunction
    
    // Tests
    globals
    private constant string TITLE_A="global to global"
    //! textmacro Benchmark__TestA
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
        set v = h
    //! endtextmacro
    private constant string TITLE_B="local to local"
    //! textmacro Benchmark__TestB
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
        set u = j
    //! endtextmacro
    endglobals
    
    // execution
    private function TestA1000 takes nothing returns nothing
        local integer i=100 // hence 1,000 execs
        local unit u //in TestA, you add these
        local unit j = h //when you shouldn't, since we are testing
        //for globals instead of locals =P
        loop
            exitwhen i==0
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestA() // 1
            //! runtextmacro Benchmark__TestA() // 2
            //! runtextmacro Benchmark__TestA() // 3
            //! runtextmacro Benchmark__TestA() // 4
            //! runtextmacro Benchmark__TestA() // 5
            //! runtextmacro Benchmark__TestA() // 6
            //! runtextmacro Benchmark__TestA() // 7
            //! runtextmacro Benchmark__TestA() // 8
            //! runtextmacro Benchmark__TestA() // 9
            //! runtextmacro Benchmark__TestA() // 10
        endloop
    endfunction
    private function TestB1000 takes nothing returns nothing
        local integer i=100
        local unit u
        local unit j = h //local to global, why not just use global directly?
        //well, I guess that is part of the test but.. I dunno.
        loop
            exitwhen i==0 // hence 1,000 execs
            set i=i-1
            // Repeat x10
            //! runtextmacro Benchmark__TestB() // 1
            //! runtextmacro Benchmark__TestB() // 2
            //! runtextmacro Benchmark__TestB() // 3
            //! runtextmacro Benchmark__TestB() // 4
            //! runtextmacro Benchmark__TestB() // 5
            //! runtextmacro Benchmark__TestB() // 6
            //! runtextmacro Benchmark__TestB() // 7
            //! runtextmacro Benchmark__TestB() // 8
            //! runtextmacro Benchmark__TestB() // 9
            //! runtextmacro Benchmark__TestB() // 10
        endloop
    endfunction
    
    private function OnEsc takes nothing returns nothing
        local integer sw
        local integer i
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestA1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cff66ddff"+TITLE_A+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
        
        set i=0
        set sw=StopWatchCreate()
        loop
            set i=i+1
            call TestB1000.evaluate() // x10 - 10,000 executions altogether.
            exitwhen i==10
        endloop
        call BJDebugMsg("|cffddff66"+TITLE_B+": "+R2S(StopWatchMark(sw)*100))
        call StopWatchDestroy(sw)
    endfunction
    
    ///////////////////////////////
    // Registers the OnEsc event //
    ///////////////////////////////
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t,function OnEsc)
        call Init()
    endfunction
endlibrary
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
I added the declarations to both functions to create a control group. I wanted to test only the speed of the "set this = that", and in a true controlled environment, you need to have an isolated test so if one has more scope than the other, there's an imbalance (hence why I did it that way). Obviously when factoring in 10,000 calls, that one little thing makes no difference, but it is still good scientific practice.

#2 I was setting a local to a local because I had the idea that it takes longer for the game to look up a global than it does a local, so I wanted to see how much faster it would be that way.
 
Ah, yeah, I misinterpreted your test. I thought you meant in general about using a global vs. local. It is weird though, since I think with local declarations in both I still returned global being faster (or well, there was a bit more variance, but globals were faster a bit more than locals being faster than globals). Although, I'm not positive.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
I always get the same results on my pc :p
you just can't beat a manual stopwatch with code when testing code speed
and this crappy custom script I use is very likely to work correctly because if I break the execution limit it will be obvious and if something else happens the game will just shut down until everything is adjusted correctly (e.g. game breaks when calling the same trigger 10k times and if I execute more than 60k+ functions at the same time the rest will just be skipped due to the operation limit)
anyway I think the only perfect way to test if something is fast is to run the spell/code/whatever a few 100 times at once and see if this or that changes the /fps but that would be too much of a hassle

nevertheless thanks for testing everything
 
Status
Not open for further replies.
Top