| 11-07-2008, 11:05 AM | #1 |
EDIT : The code is below, here : http://www.wc3campaigns.net/showpost...8&postcount=12 It would be great if someone could make a benchmark test, japi doesn't work with me. It's just for a personal using. Even if it's the fastest system on the known world, don't worry i won't never submit it as a resource for these reasons : - There are already many timers systems ... - It's not really friendly user What you mustn't do, or break the system : - Remove a condition without the function OT_End in this condition. - Don't use the textmacro OT_Init just after the locals declaration (you must use it only ONE time in a same condition). Thx for your comments. EDIT : Yes i know i should make debug things, but that's not the question yet. |
| 11-07-2008, 12:37 PM | #2 |
Where is the part where it actually executes some code? |
| 11-07-2008, 01:03 PM | #3 |
Hmm good point :p I think i will copy Captain Griffen's test for his system. I will edit the post (but not today i haven't the time, probably tomorrow). |
| 11-07-2008, 05:49 PM | #4 |
Hmm it's different to TT and Rapid Timers, i don't use a function to evaluate the conditions. So it's hard to test, or maybe calling TriggerEvaluate would be an enough good estimation ? |
| 11-07-2008, 08:20 PM | #5 |
A safe benchmark would be having both systems have the same outcome, even if one system requires a different approach. I can get japi to work, so if you can post or pm me both scripts, ill benchmark them (too lazy to figure what needs to be setup). |
| 11-12-2008, 07:44 PM | #6 |
I can not imagine a correct benchmark to compare this system with the other 2 (TT and Rapid Timers). I think my system would be faster to perform functions, but rather (very?) slow to remove a condition, especially if the latter is at the top of the list and there are many conditions added to the trigger. Without doing everything, could you give me your opinion, and guide me on how to achieve a proper benchmark? |
| 11-12-2008, 10:02 PM | #7 |
Benchmark it...you can do it. Just look at how I benchmarked TT against RT. |
| 11-13-2008, 03:35 PM | #8 |
Correct me if i'm wrong, i can test the adding conditions but for running condition i don't use any function, the trigger is running with an event. So it's not the same and i think call a TriggerEvaluate should be slower than it is, no ? And for removing a condition i use also a Timer(0.0) so can i do it properly? |
| 11-13-2008, 04:12 PM | #9 |
Unless the execution cost increases differently between timer executed triggers and triggerevaluates, then there is no problem. |
| 11-13-2008, 04:22 PM | #10 |
I just noticed that the variable i was never declared, it's inside function Remove, anyways good luck. |
| 11-13-2008, 05:27 PM | #11 | |
Quote:
I didn't see him, i will edit my message when the benchmark code will be done. [ I ] without space like that : ([i]) -> [i] Anyway i don't need luck just someone to test :p @Captain Griffen : But is there a way to test it ? For the benchmark i will assume that there was no difference. |
| 11-15-2008, 04:15 PM | #12 |
I hope the execution time of calling TriggerEvaluate is the same as perfom the trigger evaluation with the timer expire event. The libraries you need for the benchmark : OT:library OT initializer init globals private constant real TIME_OUT= 0.03125 private triggercondition array Trig_cond public trigger Trig // public for the benchmark private timer Tim private timer Tim_remove private integer array Link private integer Count= -1 private integer Index= -1 private conditionfunc C_init private integer array Ia_remove private triggercondition Trig_condInit= null private integer I_tmp private integer J_tmp private integer I= 0 endglobals private function Remove takes nothing returns nothing local integer i= 0 local integer j= Ia_remove[1] loop exitwhen i== I set i= i+1 call TriggerRemoveCondition(Trig,Trig_cond[Ia_remove[i]]) if Ia_remove[i] > Ia_remove[i-1] +1 then set I_tmp= Ia_remove[i-1]+1 set J_tmp= Ia_remove[i] loop set Trig_cond[j]= Trig_cond[I_tmp] set Link[j]= Link[I_tmp] set j= j+1 set I_tmp= I_tmp +1 exitwhen I_tmp == J_tmp endloop endif endloop set i= Ia_remove[i] loop exitwhen i == Count set i= i+1 set Trig_cond[j]= Trig_cond[i] set Link[j]= Link[i] set j= j+1 endloop set Index= -1 set Count= Count-I set I= 0 if Count == -1 then //call PauseTimer(Tim) endif endfunction private function InitPerform takes nothing returns boolean if I > 0 then call TimerStart(Tim_remove,0.,false,function Remove) else set Index= -1 endif return false endfunction // You MUST use this function ONE TIME at the begin of your Condition // ( just after the locals declaration ) function OT_Init takes nothing returns nothing set Index= Index+1 endfunction function OT_Add takes conditionfunc b , integer i returns nothing // use this function to add your condition to the timer expiration if Count== -1 then //call TimerStart(Tim,TIME_OUT,true,null) endif call TriggerRemoveCondition(Trig,Trig_condInit) set Count= Count+1 set Trig_cond[Count]= TriggerAddCondition(Trig,b) set Link[Count]= i set Trig_condInit= TriggerAddCondition(Trig,C_init) endfunction function OT_End takes nothing returns nothing // use this function in your condition to remove it set I= I+1 set Ia_remove[ I ]= Index endfunction function OT_GetLink takes nothing returns integer // use this function to get the integer attached to the condition return Link[Index] endfunction public function init takes nothing returns nothing set Trig= CreateTrigger() set Tim= CreateTimer() set Tim_remove= CreateTimer() set C_init=Condition(function InitPerform) call TriggerRegisterTimerExpireEvent(Trig,Tim) set Ia_remove[0]= 8192 endfunction endlibrary TT://============================================================================== // TT -- TIMER TICKER SYSTEM BY COHADAR -- v3.4 //============================================================================== // // PURPOUSE OF TT: // * Passing data to timers // * using only one timer for all actions // // PROS: // * It is ridiculously easy to use. // * It is faster than ABC (and any other attaching system) // // CONS: // * It can be used only for high-frequency timers // This method fails if PERIOD > 0.1 second // // FUNCTIONS: // * TT_Start(userFunc, struct) // TT_GetData() -> struct // // * userFunc is a user function that takes nothing and return boolean // it will be periodically called by the system until it returns true. // // * TT_GetData() is a function that can be used inside userFunc // TT_GetData() will return struct passed to Start function // // DETAILS: // * All user functions are stored in an array. // Timer will call all those functions each period. // // * While user function returns false timer will continue to call it each period // Once user function returns true it will be removed from system // // REQUIREMENTS: // * NewGen v4c and above (there might be some problems with older NewGen's) // // THANKS TO: // * Vexorian - he was nagging me so much about how attaching to timers is bad // that I finally had to do something about it. // // HOW TO IMPORT: // * Just create a trigger named TT // * convert it to text and replace the whole trigger text with this one // //============================================================================== library TT initializer Init globals // List of recommended periods: // 0.04 = 25 calls per second // 0.03125 = 32 calls per second // 0.025 = 40 calls per second // 0.02 = 50 calls per second public constant real PERIOD = 0.03125 // One Timer to rule them all, One Timer to find them, // One Timer to call them all and in the jass bind them // In the land of warcraft where the desyncs lie. private timer Timer = CreateTimer() private integer Data private integer Counter = 0 private trigger array Triggz private integer array Dataz endglobals //============================================================================== public function Handler takes nothing returns nothing local trigger swap local integer i = Counter loop exitwhen i<=0 set Data = Dataz[i] if TriggerEvaluate(Triggz[i]) then set swap = Triggz[i] call TriggerClearConditions(swap) set Triggz[i] = Triggz[Counter] set Triggz[Counter] = swap set Dataz[i] = Dataz[Counter] set Counter = Counter - 1 endif set i = i - 1 endloop // who can guess why am I not nulling swap here? endfunction //============================================================================== public function Start takes code userFunc, integer data returns nothing debug if userFunc == null then debug call BJDebugMsg("ERROR: TT_Start - null userFunc") debug return debug endif set Counter = Counter + 1 if Triggz[Counter] == null then set Triggz[Counter] = CreateTrigger() endif call TriggerAddCondition(Triggz[Counter], Condition(userFunc)) set Dataz[Counter] = data endfunction //============================================================================== // Call this function only inside the userFunc you passed to Start //============================================================================== public function GetData takes nothing returns integer return Data endfunction //============================================================================== private function Init takes nothing returns nothing //call TimerStart(Timer, PERIOD, true, function Handler) endfunction endlibrary //============================================================================== // END OF TIMER TICKER SYSTEM //============================================================================== CGTT:library CGTT initializer Init globals private timer tim private constant real INTERVAL = 0.03125 private integer last = 0 private integer first = 0 private integer array listLink private triggercondition array listCond private integer next = 1 private integer array stackLink private integer previousLink = 0 private integer currentLink = 0 private trigger trig private integer array integerValue endglobals public function Ex takes nothing returns nothing local integer i local triggercondition condTemp set listLink[0] = first set currentLink = 0 call TriggerEvaluate(trig) if last != currentLink and first != 0 then // you may wish to comment this out or use it as debug, but the cost is very low and very advantageous call BJDebugMsg("The timer event system has failed, likely due to not getting the index (possible double free). " + I2S(last) + ", " + I2S(currentLink)) endif set i = next loop set condTemp = listCond[i] exitwhen condTemp == null call TriggerRemoveCondition(trig, condTemp) set i = stackLink[i] endloop endfunction //! textmacro CGTimerIndexCode set previousLink = currentLink set currentLink = listLink[currentLink] //! endtextmacro function GetThisTimerEventIndex takes nothing returns integer //! runtextmacro CGTimerIndexCode() return currentLink endfunction function GetThisTimerEventInteger takes nothing returns integer //! runtextmacro CGTimerIndexCode() return integerValue[currentLink] endfunction function RemoveThisTimerEvent takes nothing returns nothing set stackLink[currentLink] = next set next = currentLink // put into stack if currentLink == last then if currentLink == first then set first = 0 set last = 0 else set currentLink = previousLink set last = previousLink endif elseif currentLink == first then set first = listLink[currentLink] set listLink[previousLink] = first set currentLink = previousLink else set listLink[previousLink] = listLink[currentLink] // remove from linked list set currentLink = previousLink // incase it comes up endif endfunction //! textmacro CGTimerAddCode if first == 0 then set first = next set last = next set next = stackLink[next] else set listLink[last] = next set last = next set next = stackLink[next] endif set listCond[last] = TriggerAddCondition(trig, cond) //! endtextmacro function AddTimerEvent takes conditionfunc cond returns integer //! runtextmacro CGTimerAddCode() return last endfunction function AddTimerEventAttach takes conditionfunc cond, integer value returns integer //! runtextmacro CGTimerAddCode() set integerValue[last] = value return last endfunction private function Init takes nothing returns nothing local integer i = 1 set tim = CreateTimer() set trig = CreateTrigger() //call TimerStart(tim, INTERVAL, true, function Ex) loop exitwhen i >= 8191 set stackLink[i] = i + 1 set i = i + 1 endloop endfunction endlibrary Benchmark:library Benchmark initializer Init needs OT , TT , CGTT globals constant integer CONDITIONS_ADDED= 200 integer array cdw real MULTIPLIER = 1000. real cgc = 0. real cgt = 0. real ttc = 0. real ttt = 0. real otc = 0. real ott = 0. integer sw endglobals function TestCG takes nothing returns boolean local integer i = GetThisTimerEventInteger() set cdw[i] = cdw[i] - 1 if cdw[i] <= 0 then call RemoveThisTimerEvent() endif return false endfunction function TestTT takes nothing returns boolean local integer i = TT_GetData() set cdw[i] = cdw[i] - 1 return cdw[i] <= 0 endfunction function TestOT takes nothing returns boolean local integer i call OT_Init() set i= OT_GetLink() set cdw[i] = cdw[i] - 1 if cdw[i] <= 0 then call OT_End() endif return false endfunction function CG takes nothing returns nothing local real r = StopWatchMark(sw) call CGTT_Ex() //call AddTimerEventAttach(Condition(function TestCG), 0) set r = StopWatchMark(sw) - r set cgt = cgt + r * MULTIPLIER set cgc = cgc + 1. call BJDebugMsg("CG: " + R2S(cgt/cgc)) endfunction function TT takes nothing returns nothing local real r = StopWatchMark(sw) call TT_Handler() //call TT_Start(function TestTT, 0) set r = StopWatchMark(sw) - r set ttt = ttt + r * MULTIPLIER set ttc = ttc + 1. call BJDebugMsg("TT: " + R2S(ttt/ttc)) endfunction function OT takes nothing returns nothing local real r = StopWatchMark(sw) call TriggerEvaluate(OT_Trig) //call OT_Add(function TestOT, 0) set r = StopWatchMark(sw) - r set ott = ott + r * MULTIPLIER set otc = otc + 1. call BJDebugMsg(" ") //call BJDebugMsg("OT: " + R2S(ott/otc)) endfunction function CGTT takes nothing returns nothing local real t local real r = StopWatchMark(sw) call CGTT_Ex() set r = StopWatchMark(sw) - r set t = r * MULTIPLIER set r = StopWatchMark(sw) call TT_Handler() set r = StopWatchMark(sw) - r set r = r * MULTIPLIER call BJDebugMsg("CG: " + R2S(t)) call BJDebugMsg("TT: " + R2S(r)) endfunction function CGOT takes nothing returns nothing local real t local real r = StopWatchMark(sw) call CGTT_Ex() set r = StopWatchMark(sw) - r set t = r * MULTIPLIER set r = StopWatchMark(sw) call TriggerEvaluate(OT_Trig) set r = StopWatchMark(sw) - r set r = r * MULTIPLIER call BJDebugMsg("CG: " + R2S(t)) call BJDebugMsg("OT: " + R2S(r)) endfunction function TTCG takes nothing returns nothing local real t local real r = StopWatchMark(sw) call TT_Handler() set r = StopWatchMark(sw) - r set t = r * MULTIPLIER set r = StopWatchMark(sw) call CGTT_Ex() set r = StopWatchMark(sw) - r set r = r * MULTIPLIER call BJDebugMsg("TT: " + R2S(t)) call BJDebugMsg("CG: " + R2S(r)) endfunction function TTOT takes nothing returns nothing local real t local real r = StopWatchMark(sw) call TT_Handler() set r = StopWatchMark(sw) - r set t = r * MULTIPLIER set r = StopWatchMark(sw) call TriggerEvaluate(OT_Trig) set r = StopWatchMark(sw) - r set r = r * MULTIPLIER call BJDebugMsg("TT: " + R2S(t)) call BJDebugMsg("OT: " + R2S(r)) endfunction function setup takes nothing returns nothing local integer i = 0 loop exitwhen i >= CONDITIONS_ADDED call AddTimerEventAttach(Condition(function TestCG), i*2) call TT_Start(function TestTT, i*2+1) call OT_Add(Condition(function TestOT),i+CONDITIONS_ADDED*2) set cdw[i*2] = GetRandomInt(1, 20) set cdw[i*2+1] = cdw[i*2] set cdw[i+CONDITIONS_ADDED*2] = cdw[i*2] set i = i + 1 endloop //call BJDebugMsg("setup "+I2S(i)) endfunction //=========================================================================== function VS takes nothing returns nothing local string s= StringCase(GetEventPlayerChatString(),true) call ExecuteFunc(s) endfunction private function Init takes nothing returns nothing local trigger trig= CreateTrigger() call TriggerRegisterPlayerChatEvent(trig, Player(0), "CGTT", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "CGOT", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "OTCG", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "OTTT", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "TTCG", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "TTOT", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "CG", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "TT", true) call TriggerRegisterPlayerChatEvent(trig, Player(0), "OT", true) call TriggerAddAction(trig,function VS) call setup() set sw = StopWatchCreate() call BJDebugMsg("init done") endfunction endlibrary Plz try it with 50 and 200 conditions added Don't forget to disable war3err and the debug mode. Thx in advance. |
| 11-16-2008, 04:09 PM | #13 |
tried to benchmark but the OT_Remove function kept reaching the oplimit (I'm guessing cause of a bad loop). No idea how the system works, but ill see if I can fix it. |
| 11-16-2008, 04:55 PM | #14 | |
Quote:
I will fix that and pm you. |
| 11-16-2008, 06:03 PM | #15 |
Yeah, all I needed for TimerUtils was for someone to rob the function names and make new functions that are incompatible with it, nice... |
