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 6 days
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/index.php?topic=5012.0

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