• 🏆 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!

GetUnitX/Y vs GetWidgetX/Y

Status
Not open for further replies.
Level 19
Joined
Mar 18, 2012
Messages
1,716
Lately many users started replacing GetUnitX/Y with GetWidgetX/Y.

The argument was handle > agent > widget whereas handle > agent > widget > unit. The first impression may be GetUnitX is faster than GetWidgetX, but can someone prove this assumption?

If I remember correctly, old benchmarking showed GetUnitX is faster than GetWidgetX.
 
Messages of Bowser
Bowser499 said:
GetWidgetX/Y is faster than GetUnitX/Y. It was benchmarked by me multiple times. The key is here:
Jass:
JASS:
type unit extends widget
type widget extends agent
type agent extends handle
The widget type is one level higher than unit so it will execute faster.

Use can test the benchmark to see Frames time and minmaxavg too.
 
JASS:
function Test1 takes nothing returns nothing
      local integer i = 0
      local unit u = CreateUnit(Player(0),'hfoo',0.,0.,0.)
        
      loop
          set i = i + 1
              call GetUnitX(u)
              call BJDebugMsg(I2S(i))
      endloop
        
      set u = null
endfunction

function Test2 takes nothing returns nothing
      local integer i = 0
      local unit u = CreateUnit(Player(0),'hfoo',0.,0.,0.)
        
      loop
          set i = i + 1
              call GetWidgetX(u)
              call BJDebugMsg(I2S(i))
      endloop
        
      set u = null
endfunction

Run both of them. Greater number of iterations means more fast function.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
There is no obvious reason why GetUnitX/Y are faster, and why GetItemX/Y are slower. It has to do with how WC3 processes the bytecode internally which is of course a mystery to all who are not looking at the proprietary source code which is hidden to all eyes except for Blizzard internal, and probably no one currently there even understands that source code because they fired all those guys.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Test!

Where's the screenshot?
EDIT:
Tested using this:
JASS:
globals
    unit U
    integer N=0
    integer M=0
    constant timer t=CreateTimer()
    constant timer t1=CreateTimer()
    constant timer t2=CreateTimer()
endglobals

function a takes nothing returns nothing
    loop
        call GetUnitX(U)
        set N=N+1
    endloop
endfunction

function b takes nothing returns nothing
    loop
        call GetWidgetX(U)
        set M=M+1
    endloop
endfunction

function display takes nothing returns nothing
    local string msg="GetUnitX: "+I2S(N)+" ** GetWidgetX: "+I2S(M)
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,msg)
endfunction

function Stato takes nothing returns nothing
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,"Test Stato!")
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,"GetUnitX started!")
    call TimerStart(t1,0.1,false,function a)
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,"GetWidgetX started!")
    call TimerStart(t2,0.2,false,function b)
    call TimerStart(t,1.0,false,function display)
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60.00,"Test End!")
endfunction



//===========================================================================
function InitTrig_Init takes nothing returns nothing
    set U=CreateUnit(Player(0),'hfoo',0,0,0)
    call TimerStart(t,1.00,false,function Stato)
endfunction

Result: both managed to loop 30,000 times

attachment.php


Conclusion: Loops aren't good benchmarking tools.
Run both of them. Greater number of iterations means more fast function.
Sorry, but you were wrong.
 

Attachments

  • Test.JPG
    Test.JPG
    61.5 KB · Views: 315
  • TestMap.w3x
    12.3 KB · Views: 50
Last edited:
Level 22
Joined
Sep 24, 2005
Messages
4,821
The developers left a lot of junk when they released the editor. Oh, and the loop argument is no longer valid.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
I did as written here:

http://www.hiveworkshop.com/forums/lab-715/preloadgenstart-241159/

JASS:
function a takes nothing returns nothing
    local integer i=1000
    loop
        exitwhen (i<1)
        call GetUnitX(udg_u)
        set i=i-1
    endloop
endfunction

function bla takes nothing returns nothing
    local integer i=15000
    
    
    local trigger t=CreateTrigger()
    call TriggerAddCondition(t, Condition(function a))
    
    set udg_u=CreateUnit(Player(0), 'hpea', 0, 0, 0)

    call PreloadGenStart()
    
    loop
        exitwhen (i<1)
        call TriggerEvaluate(t)
        set i=i-1
    endloop
    
    call PreloadGenEnd("benchmark.txt")
    
    call BJDebugMsg("ende")
endfunction

One time with GetUnitX, one time with GetWidgetX, one time without anything between in order to subtract the framework expense. The results are pretty stable if you do not do anything else in background.

According to that and assuming it's linear, it's 974026 times call GetWidgetX(udg_u) per second to 1102941 times call GetUnitX(udg_u) per second for me.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
JASS:
library leakTest1 initializer onInit
    globals
        private timer t = CreateTimer()
        private constant integer dummies = 1
        private constant integer events = 50
        private integer c = 0
        private trigger acquire = CreateTrigger()
    endglobals
    
    private function acquireItem takes nothing returns boolean
        //local unit u
        local integer i = events
        loop
            /*
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            call GetWidgetX(udg_u)
            */
            
            
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            call GetUnitX(udg_u)
            
            
            exitwhen i == 0
            set i = i - 1
        endloop
        //set u = null
        return false
    endfunction

    private function leaks takes nothing returns nothing
        local integer i = dummies
        
        loop
            exitwhen i == 0
            call KillUnit(CreateUnit(Player(0), 'hfoo', 0, 0, 0))
            set c = c + 1
            set i = i - 1
        endloop
    endfunction
    
    private function pauseResume takes nothing returns nothing
        if ModuloInteger(GetTriggerExecCount(GetTriggeringTrigger()) , 2) == 1 then
            call BJDebugMsg("started")
            //call TimerStart(t, 0.01, true, function leaks)
            call TimerStart(t, 0.001, true, function acquireItem)
        else
            call BJDebugMsg("paused, " + "dummies created: " + I2S(c))
            call PauseTimer(t)
        endif
    endfunction

    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t, function pauseResume)
        call TriggerRegisterAnyUnitEventBJ(acquire, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(acquire, function acquireItem)
    endfunction
endlibrary

My max FPS is limited to 60. With GetWidgetX, the FPS was 43-48. With GetUnitX, constant 60. Measured with the in-game /fps command. The unit was patrolling.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
This changes the owner of a unit and uses an event to detect the ownership change
JASS:
library leakTest1 initializer onInit
    globals
        private timer t = CreateTimer()
        private constant integer dummies = 1
        private constant integer events = 350
        private integer c = 0
        private trigger acquire = CreateTrigger()
        private unit hero
        private boolean boo = false
    endglobals
    
    private function acquireItem takes nothing returns boolean
        local unit u
        local integer i = events
        loop
            
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            set u = GetChangingUnit()
            
            exitwhen i == 0
            set i = i - 1
        endloop
        call ReviveHero(hero, 0, 0, false)
        set u = null
        return false
    endfunction

    private function leaks takes nothing returns nothing
        set boo = not boo
        if boo then
            call SetUnitOwner(hero, Player(0), false)
        else
            call SetUnitOwner(hero, Player(1), false)
        endif
        set c = c + 1
    endfunction
    
    private function pauseResume takes nothing returns nothing
        if ModuloInteger(GetTriggerExecCount(GetTriggeringTrigger()) , 2) == 1 then
            call BJDebugMsg("started")
            call TimerStart(t, 0.005, true, function leaks)
            //call TimerStart(t, 0.001, true, function acquireItem)
        else
            call BJDebugMsg("paused, " + "dummies created: " + I2S(c))
            call PauseTimer(t)
        endif
    endfunction

    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t, function pauseResume)
        call TriggerRegisterPlayerUnitEvent(acquire, Player(0), EVENT_PLAYER_UNIT_CHANGE_OWNER, null)
        call TriggerAddCondition(acquire, function acquireItem)
        set hero = CreateUnit(Player(0), 'Hpal', 0, 0, 0)
    endfunction
endlibrary

GetTriggerUnit -> constant 60 fps
GetChangingUnit -> ~23 fps

I would assume the same goes for dying unit, might test it later
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
with owner change event:
GetChangingUnit -> 11.8 seconds/15mio calls
GetTriggerUnit -> 7.9 seconds/15mio calls

with unit's death event:
GetDyingUnit -> 7.5 seconds/15mio calls
GetTriggerUnit -> 7.9 seconds/15mio calls
GetKillingUnit -> 11.3 seconds/15mio calls

JASS:
function a takes nothing returns nothing
    local integer i=1000

    loop
        exitwhen (i<1)
        //call GetWidgetX(udg_u)
        call GetKillingUnit()
        set i=i-1
    endloop
endfunction

function death takes nothing returns nothing
    local integer i=15000
    
    local trigger t=CreateTrigger()
    call TriggerAddCondition(t, Condition(function a))

    call PreloadGenStart()

    loop
        exitwhen (i<1)
        call TriggerEvaluate(t)
        set i=i-1
    endloop
    
    call PreloadGenEnd("benchmark.txt")
    
    call BJDebugMsg("ende")
endfunction

function b takes nothing returns nothing    
    set udg_u=CreateUnit(Player(0), 'hpea', 0, 0, 0)
    
    call KillUnit(udg_u)
endfunction

//===========================================================================
function InitTrig_Nahkampf_Initialisierung takes nothing returns nothing
    set gg_trg_Nahkampf_Initialisierung = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Nahkampf_Initialisierung, Player(0) )
    call TriggerAddAction( gg_trg_Nahkampf_Initialisierung, function b )
    
    set udg_ownerchangetrig=CreateTrigger()
    call TriggerRegisterPlayerUnitEvent(udg_ownerchangetrig, Player(0), EVENT_PLAYER_UNIT_DEATH, null)
    call TriggerAddAction( udg_ownerchangetrig, function death )
endfunction

the code for unit changing owner was analogue.

Ps: GetTriggerUnit is not recommended for its speed advantage but for its universality.
 
Status
Not open for further replies.
Top