HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Creating an Op Counter

03-28-2008, 07:33 PM#1
Strilanc
I'm trying to write something to count the operations used by a given function. The idea is to use TriggerEvaluate to call on a new op count, run the function, then count how many iterations in a loop before the op limit is hit. I use different sized loops to be more accurate (one loop with one increment takes 7 operations per iteration).

I'm having trouble. In particular, the game tends to crash. For example, if you raise the constant NUM_TESTS_$func$ above 2 (to use more loop sizes) while testing DoNothing, the game crashes.

Collapse JASS:
//code to perform test
//! runtextmacro CreateOpCounter("DoNothing")

function Trig_Tester_Actions takes nothing returns nothing
    call BJDebugMsg(I2S(CountOperations_DoNothing()))
    //returns 0 for num test = 2, CRASH for more
endfunction
//===========================================================================
function InitTrig_Tester takes nothing returns nothing
    set gg_trg_Tester = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( gg_trg_Tester, 1.00 )
    call TriggerAddAction( gg_trg_Tester, function Trig_Tester_Actions )
endfunction

Collapse JASS:
//the macro to create the test for a function
//accurate to within about +- 4
//! textmacro CreateOpCounter takes func
    globals
        constant integer OVERHEAD_OPS_$func$ = 7
        constant integer OP_LIMIT_$func$ = 300000
        constant integer NUM_TESTS_$func$ = 1
        boolean OpCounterStarted_$func$ = false
        integer OpCounter_$func$
        trigger array OpCountCallers_$func$
    endglobals
    
    function countOps1_$func$ takes nothing returns boolean
        call $func$()
        loop
            set OpCounter_$func$ = OpCounter_$func$ + 7 //6 operations (get, get, add, set, ???, ???)
        endloop //1 operation (jump)
        return true
    endfunction
    function countOps2_$func$ takes nothing returns boolean
        call $func$()
        loop
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 7 //6 operations (get, get, add, set, ???, ???)
        endloop //1 operation (jump)
        return true
    endfunction
    function countOps3_$func$ takes nothing returns boolean
        call $func$()
        loop
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 7 //6 operations (get, get, add, set, ???, ???)
        endloop //1 operation (jump)
        return true
    endfunction
    function countOps4_$func$ takes nothing returns boolean
        call $func$()
        loop
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 6 //6 operations (get, get, add, set, ???, ???)
            set OpCounter_$func$ = OpCounter_$func$ + 7 //6 operations (get, get, add, set, ???, ???)
        endloop //1 operation (jump)
        return true
    endfunction
        
    function initOpCounter_$func$ takes nothing returns nothing
        set OpCountCallers_$func$[1] = CreateTrigger()
        //call TriggerAddCondition(OpCountCallers_$func$[1], Condition(function countOps1_$func$))
        call TriggerAddAction(OpCountCallers_$func$[1], function countOps1_$func$)
        
        set OpCountCallers_$func$[2] = CreateTrigger()
        //call TriggerAddCondition(OpCountCallers_$func$[2], Condition(function countOps2_$func$))
        call TriggerAddAction(OpCountCallers_$func$[2], function countOps2_$func$)
        
        set OpCountCallers_$func$[3] = CreateTrigger()
        //call TriggerAddCondition(OpCountCallers_$func$[3], Condition(function countOps3_$func$))
        call TriggerAddAction(OpCountCallers_$func$[3], function countOps3_$func$)
        
        set OpCountCallers_$func$[4] = CreateTrigger()
        //call TriggerAddCondition(OpCountCallers_$func$[4], Condition(function countOps4_$func$))
        call TriggerAddAction(OpCountCallers_$func$[4], function countOps4_$func$)
    endfunction

    function CountOperations_$func$ takes nothing returns integer
        local integer i
        local integer total = 0
        if not OpCounterStarted_$func$ then
            set OpCounterStarted_$func$ = true
            call initOpCounter_$func$()
        endif
        set i = 1
        loop
            exitwhen i > NUM_TESTS_$func$
            
            set OpCounter_$func$ = OVERHEAD_OPS_$func$
            call TriggerExecute(OpCountCallers_$func$[i])
            call BJDebugMsg(I2S(OpCounter_$func$))
            set total = total + OP_LIMIT_$func$ - OpCounter_$func$
            
            set i = i + 1
        endloop
        return total / NUM_TESTS_$func$
    endfunction
//! endtextmacro
03-29-2008, 01:19 AM#2
PipeDream
If you're interested in the answer and not the process of finding out, use grimoire's bytecode tracer.
04-09-2008, 05:28 PM#3
Strilanc
I was thinking more along the lines of detecting modifications to existing functions, as a map protection measure. Grimoire wouldn't be useful for that, because the other players won't have it.

(Although a crash would *technically* count as detecting the modification, I just want to show a message, not kill the game)
04-09-2008, 07:27 PM#4
Toadcop
Strilanc Forget it... it doesnt work accurate. so it will be no problem to trix such kind of "protection". (i have made some test while ago...)

but if you want to spend some time on theorie (like AMHS xD omg rolf pizdiec...) so go on ^^ gl hf
04-09-2008, 09:21 PM#5
Strilanc
What do you mean it isn't accurate? It's accurate to 6 operations (+- crash), and any 'cheat' modifications people do will modify it by more than that. You might as well say handle count isn't accurate because you can get around that.
04-09-2008, 10:35 PM#6
Toadcop
1. it's easy to remove this code.
2. simply use ExecuteFunc() to inject your stuff.

Quote:
It's accurate to 6 operations
it depends what you are doing. how i know (info by PipeDream) the limit is 300K of byte code operations.
ah what ever do you what you want =)
04-09-2008, 10:58 PM#7
Vexorian
You should take a look to Code2I's results and what they depend of.
04-10-2008, 01:42 AM#8
PandaMine
There really isn't a point in this, wc3err does the job much better
04-10-2008, 01:47 AM#9
Strilanc
Quote:
Originally Posted by PandaMine
There really isn't a point in this, wc3err does the job much better

I repeat myself:
Quote:
Originally Posted by Strilanc
I was thinking more along the lines of detecting modifications to existing functions, as a map protection measure. Grimoire wouldn't be useful for that, because the other players won't have it.
04-10-2008, 01:53 AM#10
PandaMine
Hmm you may have something there, many people have been looking for a system to protect alterations to jass script

HOWEVER

you have to take into consideration wc3mapoptimizer and it has to be incredibly accurate. It also doesn't stop people from actually taking the OP counter script out of the map and doing some more alterations (although it does destroy the use of cheat code injectors)
04-10-2008, 02:11 AM#11
Strilanc
Quote:
Originally Posted by PandaMine
Hmm you may have something there, many people have been looking for a system to protect alterations to jass script

HOWEVER

you have to take into consideration wc3mapoptimizer and it has to be incredibly accurate. It also doesn't stop people from actually taking the OP counter script out of the map and doing some more alterations (although it does destroy the use of cheat code injectors)

All valid points. But every protection method can be removed by someone with enough knowledge. The idea is to put that threshold above what most users can do.

Power Towers uses this 'type' of protection, but with handles. I haven't seen a hacked version in the wild that didn't trip the "this map has been modified" message. (This probably has a lot to do with the fact that I only show a message instead of forcefully ending the game)
04-10-2008, 02:59 AM#12
Vexorian
Quote:
you have to take into consideration wc3mapoptimizer
This is easier than it sounds, you just need to optimize it in two different steps.