Which could be more efficient/better performance?

Coding Help

11 years
Hello guys,
I have problems when people say my map is kinda laggy
As far as I know my code is leak free. However, I noticed that I put too much system inside which gives a lot pressure to the CPU (especially periodic calls + groupenums calls).
So, before I refine my codes, I need some suggestion

I will give examples from each category and you guys just point out, which is more efficient method to use and give better performance.
If there is another better method that I didn't know or some of my methods are wrong, tell me!

1. Periodic Calls

a. Using Timer
Code (jass) Select
1
function RunThis takes nothing returns nothing
2
    // code here
3
endfunction
4
5
function InitTrig_test takes nothing returns nothing
6
    local timer t = CreateTimer(  )
7
    call TimerStart(t,0.25,true,function RunThis)
8
endfunction


b. Using Trigger
Code (jass) Select
1
function RunThis takes nothing returns boolean
2
    // code here
3
    return false
4
endfunction
5
6
function InitTrig_test takes nothing returns nothing
7
    local trigger t = CreateTrigger(  )
8
    call TriggerRegisterTimerEvent(t,0.25,true)
9
    call TriggerAddCondition(t,Condition(function RunThis))
10
endfunction


2. Group Execution

a. Blizz-way (Filtering then Execute)
Code (jass) Select
1
function GroupExecuteUnits takes nothing returns nothing
2
    //execute each valid unit
3
endfunction
4
5
function GroupFilter takes nothing returns boolean
6
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTriggerUnit()))
7
endfunction
8
9
function GroupExec takes nothing returns nothing
10
    local group g = CreateGroup()
11
    local unit c = GetTriggerUnit()
12
    local real x = GetUnitX(c)
13
    local real y = GetUnitY(c)
14
    call GroupEnumUnitsInRange(g,x,y,300,Filter(function GroupFilter))
15
    call ForGroup(g, function GroupExecuteUnits)
16
    call DestroyGroup(g)
17
    set g = null
18
    set c = null
19
endfunction


b. In one function way
Code (jass) Select
1
function GroupExec takes nothing returns nothing
2
    local group g = CreateGroup()
3
    local unit c = GetTriggerUnit()
4
    local real x = GetUnitX(c)
5
    local real y = GetUnitY(c)
6
    local unit temp
7
    call GroupEnumUnitsInRange(g,x,y,300,null)
8
    loop
9
        set temp = FirstOfGroup(g)
10
    exitwhen temp == null
11
        if IsUnitEnemy(temp,GetOwningPlayer(c)) then
12
            //execute each valid unit
13
        endif
14
        call GroupRemoveUnit(g,temp)
15
    endloop
16
    call DestroyGroup(g)
17
    set g = null
18
    set c = null
19
endfunction


c. What-i-am-currently-using way
Code (jass) Select
1
function GroupFilter takes nothing returns boolean
2
    if IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTriggerUnit())) then
3
        //execute each valid unit
4
    endif
5
    return false
6
endfunction
7
8
function GroupExec takes nothing returns nothing
9
    local group g = CreateGroup()
10
    local unit c = GetTriggerUnit()
11
    local real x = GetUnitX(c)
12
    local real y = GetUnitY(c)
13
    local filterfunc ff = Filter(function GroupFilter)
14
    call GroupEnumUnitsInRange(g,x,y,300,ff)
15
    call DestroyGroup(g)
16
    call DestroyFilter(ff)
17
    set ff = null
18
    set g = null
19
    set c = null
20
endfunction


3. Multi-Instancing]

a. Indexing (in this case, one timer for all instances)
Code (jass) Select
1
function Execute takes nothing returns nothing
2
    local integer i = 1
3
    loop
4
    exitwhen i > udg_INDEX
5
        set udg_Durations[i] = udg_Durations[i] - TimerGetTimeout(udg_Time)
6
        if udg_Durations[i] > 0 then
7
            //do a heal/damage to udg_Units[i]
8
        else
9
            if i != udg_INDEX then
10
                set udg_Durations[i] = udg_Durations[udg_INDEX]
11
                set udg_Units[i] = udg_Units[udg_INDEX]
12
            endif
13
            set udg_INDEX = udg_INDEX - 1
14
            set i = i - 1
15
        endif
16
        set i = i + 1
17
    endloop
18
19
    if udg_INDEX == 0 then
20
        call PauseTimer(udg_Time)
21
    endif
22
endfunction
23
24
function Register takes unit u, real duration returns nothing
25
    set udg_INDEX = udg_INDEX + 1
26
    set udg_Units[udg_INDEX] = u
27
    set udg_Durations[udg_INDEX] = duration
28
    if udg_INDEX == 1 then
29
        call TimerStart(udg_Time,0.5,true,function Execute)
30
    endif
31
endfunction


b. Keying To Handle (in this case, one timer for one instance)
Code (jass) Select
1
function Execute takes nothing returns nothing
2
    local timer t = GetExpiredTimer()
3
    local integer key = GetHandleId(t)
4
    local unit u = LoadUnitHandle(udg_HashTable,key,0)
5
    local real duration = LoadReal(udg_HashTable,key,1)
6
    
7
    ////do a heal/damage to unit "u"
8
    
9
    set duration = duration - TimerGetTimeout(t)
10
    call SaveReal(udg_HashTable,key,0,duration)
11
    if duration <= 0 then
12
        call FlushChildHashtable(udg_HashTable,key)
13
        call PauseTimer(t)
14
        call DestroyTimer(t)
15
    endif
16
    set u = null
17
    set t = null
18
endfunction
19
20
function Register takes unit u, real duration returns nothing
21
    local timer t = CreateTimer()
22
    local integer key = GetHandleId(t)
23
    call SaveUnitHandle(udg_HashTable,key,0,u)
24
    call SaveReal(udg_HashTable,key,1,duration)
25
    call TimerStart(t,0.5,true,function Execute)
26
endfunction

Note: the periodic method can be replaced by trigger periodic method

==============================================

THANKYOU
PS: I haven't run these codes
11 years
I'm elaborating an answer for you, hopefully this night I'll have some ideas for you :)
11 years
Thanks admin  ;)

I am desperately need some references to enhance performance of systems in my map
Since ppl with low-spec PC keep struggling with my map
11 years
edited 11 years
The first thing is to start using some libraries to speed up your code, the first one is an indexing library like ALLOC: https://wc3modding.info/5012/snippet-allocloop-aka-alloc-2/

With this one the allocation of things would be dramatically increased. And it works because it's slower to create/destroy handles than reusing it.

I'll post some examples about what you can do with this baby.

Let's start with timers:

Code (jass) Select
1
    function RunThis takes nothing returns nothing
2
        // code here. The timer hancle can be managed in this function to destroy or pause...
3
    endfunction
4
     
5
    function InitTrig_test takes nothing returns nothing
6
        call TimerStart(CreateTimer(),0.25,true,function RunThis) // with this you save a variable assignation...
7
    endfunction


Using periodic triggers is a BIG no no. triggers are not recyclable as timers. And for time recycling there's a tool called timerutils.

About Unit grouping, the fastest way is the one you posted:

Code (jass) Select
1
    function GroupExec takes nothing returns nothing
2
        // As you can see, I use an already created group, a bj one in order to make it faster in use, and you don't need to destroy it, it's cleaned up by the same loop...
3
        local unit c = GetTriggerUnit()
4
        local real x = GetUnitX(c)
5
        local real y = GetUnitY(c)
6
        local unit temp
7
        call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,300,null)
8
        loop
9
            set temp = FirstOfGroup(bj_lastCreatedGroup)
10
        exitwhen temp == null
11
            if IsUnitEnemy(temp,GetOwningPlayer(c)) then
12
                //execute each valid unit
13
            endif
14
            call GroupRemoveUnit(bj_lastCreatedGroup,temp)
15
        endloop
16
        set c = null
17
    endfunction
11 years
Answered some parts... :)
11 years
edited 11 years
Quote from: moyack on February 21, 2015, 05:14:13 PM
The first thing is to start using some libraries to speed up your code, the first one is an indexing library like ALLOC: https://wc3modding.info/5012/snippet-allocloop-aka-alloc-2/
With this one the allocation of things would be dramatically increased. And it works because it's slower to create/destroy handles than reusing it.
Will alloc's allocate will instantly override current allocate method on struct?

Quote
Let's start with timers:

Code (jass) Select
1
    function RunThis takes nothing returns nothing
2
        // code here. The timer hancle can be managed in this function to destroy or pause...
3
    endfunction
4
     
5
    function InitTrig_test takes nothing returns nothing
6
        call TimerStart(CreateTimer(),0.25,true,function RunThis) // with this you save a variable assignation...
7
    endfunction


Using periodic triggers is a BIG no no. triggers are not recyclable as timers. And for time recycling there's a tool called timerutils.

I had used recycling system like Vex timerutils and dummy system in my map, but sometimes it is bugged, I don't know whether it is my fault or system's fault.
One of bug is when I use a recycled timer.
Timer that is retrieved for me is still currently being used with other instances (still active). So, I took a safe way to use default create and destroy.

Quote
About Unit grouping, the fastest way is the one you posted:

Code (jass) Select
1
    function GroupExec takes nothing returns nothing
2
        // As you can see, I use an already created group, a bj one in order to make it faster in use, and you don't need to destroy it, it's cleaned up by the same loop...
3
        local unit c = GetTriggerUnit()
4
        local real x = GetUnitX(c)
5
        local real y = GetUnitY(c)
6
        local unit temp
7
        call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,300,null)
8
        loop
9
            set temp = FirstOfGroup(bj_lastCreatedGroup)
10
        exitwhen temp == null
11
            if IsUnitEnemy(temp,GetOwningPlayer(c)) then
12
                //execute each valid unit
13
            endif
14
            call GroupRemoveUnit(bj_lastCreatedGroup,temp)
15
        endloop
16
        set c = null
17
    endfunction


Aw..
By judging on how you replace my g var, I conclude that it is better to using global variable than local variable, since globals are reusable and creates less handle (locals create one handle per creation)
Am I right?


Edit: http://www.thehelper.net/threads/new-leak-found-keeping-references-to-destroyed-objects.122136/
Got something interesting here, which telling us to null global/local handle var as soon as possible to reset handle ID counter

============================

Well looks like I will moving again from vanilla JASS to vJass one
Gracias admin ;D