[Include] Timer Fix (seamlessly makes SetTimer very accurate)
#1

Note: The fixes2 or timerfix plugins takes care of this much better. Consider using it instead.

Hey,

I've recently been struggling with timers, and the fact that they aren't accurate by a damn sight. Here's an include that will make your timers accurate by ~5ms.

For example, it will turn this output from one 250ms timer and one 1500ms timer:
Код:
[17:54:33] Time since last call: 293ms (43 ms off)
[17:54:34] Time since last call: 292ms (42ms off)
[17:54:34] Time since last call: 292ms (42ms off)
[17:54:34] Time since last call: 292ms (42ms off)
[17:54:35] Time since last call: 292ms (42ms off)
[17:54:35] Time since last call: 1786ms (286ms off)
[17:54:37] Time since last call: 1756ms (256ms off)
[17:54:38] Time since last call: 1756ms (256ms off)
[17:54:40] Time since last call: 1756ms (256ms off)
[17:54:42] Time since last call: 1756ms (256ms off)
As you can see, the timer is roughly 25% off!

into this:
Код:
[17:55:11] Time since last call: 251ms (1ms off)
[17:55:11] Time since last call: 252ms (2ms off)
[17:55:12] Time since last call: 252ms (2ms off)
[17:55:12] Time since last call: 251ms (1ms off)
[17:55:12] Time since last call: 251ms (1ms off)
[17:55:12] Time since last call: 1498ms (2ms off)
[17:55:14] Time since last call: 1499ms (1ms off)
[17:55:15] Time since last call: 1499ms (1ms off)
[17:55:17] Time since last call: 1500ms (0ms off)
[17:55:18] Time since last call: 1499ms (1ms off)
Usage
You just have to add one single line of code after you included a_samp:
pawn Код:
#include <timerfix>
Limitations
You can, by default, have only 128 timers running at the same time. If you feel the need to increase this, define TIMER_FIX_TIMER_SLOTS before you include the script.
Something to keep in mind is this include causes PAWN to work harder; therefore, you shouldn't have loads of timers running at the same time as it will require higher CPU usage.

Compatibility
  • It works for SetTimer and SetTimerEx, though not with strings and arrays.
  • It works very well with y_timers.
Download
Here: timerfix.inc
Reply
#2

WOW, its great!
Reply
#3

That's awesome... I think I will use this. Thanks.

/second
Reply
#4

I saw this like a time ago but there wasn't some positive feedback about it D:
Reply
#5

Quote:
Originally Posted by costel_nistor96
Посмотреть сообщение
That's awesome... I think I will use this. Thanks.
Agreed, Definitely an improvement Thank you very much!
Reply
#6

Great, this will come in very handy, thank's for the share.
Reply
#7

SetTimerEx too?
Reply
#8

Quote:
Originally Posted by OKStyle
Посмотреть сообщение
SetTimerEx too?
Not yet!

Quote:

This works only for SetTimer at the moment. I'm working on support for SetTimerEx.

Reply
#9

Very useful release.

Perhaps this could help you developing "SetTimerEx":
pawn Код:
preventCrash(); public preventCrash()
{
    SetTimerEx("preventCrash", 0, 0, "");
}

stock SetTimerEx_(szFunc[], iInterval, iRepeating, szFormat[], { Float, _ }: ...)
{
    new
        iArgs = numargs() << 2,
        iStart,
        iEnd
    ;
    #emit CONST.PRI szFormat
    #emit STOR.S.PRI iStart
     
    #emit LOAD.S.PRI iArgs
    #emit ADD.C 8
    #emit STOR.S.PRI iEnd
   
    for(new i = iEnd; i >= iStart; i -= 4)
    {
        #emit LCTRL 5
        #emit LOAD.S.ALT i
        #emit ADD
        #emit LOAD.I
        #emit PUSH.PRI
    }
    #emit PUSH.S szFormat
    #emit PUSH.S iRepeating
    #emit PUSH.S iInterval
    #emit PUSH.S szFunc
    #emit PUSH.S iArgs
    #emit SYSREQ.C SetTimerEx
   
    for(iArgs = (iArgs >> 2) + 1; iArgs--; )
    {
        #emit STACK 4
    }
}
Reply
#10

Good job, been looking for something like this ^^. Thanks, hope you do it for SetTimerEx as well!
Reply
#11

Quote:
Originally Posted by RyDeR`
Посмотреть сообщение
Very useful release.

Perhaps this could help you developing "SetTimerEx":
pawn Код:
preventCrash(); public preventCrash()
{
    SetTimerEx("preventCrash", 0, 0, "");
}

stock SetTimerEx_(szFunc[], iInterval, iRepeating, szFormat[], { Float, _ }: ...)
{
    new
        iArgs = numargs() << 2,
        iStart,
        iEnd
    ;
    #emit CONST.PRI szFormat
    #emit STOR.S.PRI iStart
     
    #emit LOAD.S.PRI iArgs
    #emit ADD.C 8
    #emit STOR.S.PRI iEnd
   
    for(new i = iEnd; i >= iStart; i -= 4)
    {
        #emit LCTRL 5
        #emit LOAD.S.ALT i
        #emit ADD
        #emit LOAD.I
        #emit PUSH.PRI
    }
    #emit PUSH.S szFormat
    #emit PUSH.S iRepeating
    #emit PUSH.S iInterval
    #emit PUSH.S szFunc
    #emit PUSH.S iArgs
    #emit SYSREQ.C SetTimerEx
   
    for(iArgs = iArgs >> 2 + 1; iArgs--; )
    {
        #emit STACK 4
    }
}
Thanks. I'll see what I can make of it!
Reply
#12

Quote:
Originally Posted by Slice
Посмотреть сообщение
Not yet! I working on it
Then I should say "Thank you" =) Nice results.
Reply
#13

Quote:
Originally Posted by ******
Посмотреть сообщение
That is very good to hear, though for full disclosure I should point out that it will ONLY work with tasks as everything else uses "SetTimerEx" (often renamed to "O@" for technical reasons (length)). I can see the issue with "SetTimerEx" though - if you don't mind could I have a go at integrating this in to y_timers directly? It may make supporting SetTimerEx easier as there is already code for storing parameters (to fix strings and arrays).

I was going to suggest using a tick time of 0 for better results, but shouldn't make any difference given that the SA:MP server has a "Sleep(5)" call in it.
For some reason I didn't see your post until just now. As much as I'd love to blame the forum software, it was probably just my being tired.

Implementing it directly into YSI would be great! I was actually going to ask you about that. I'd like to port it to this include, though, for those who don't use YSI.
I experimented setting the tick timer to 1ms and sending RCON "sleep 1"; however, altering the sleep time causes timers to behave really strange.
Reply
#14

Doesn't look very effective having a timer with a loop every 5ms, and I also remember there was such a thread some time ago.
Reply
#15

Quote:
Originally Posted by wups
Посмотреть сообщение
Doesn't look very effective having a timer with a loop every 5ms, and I also remember there was such a thread some time ago.
The loop function takes 1.6 microseconds to execute (that's 0.0016 milliseconds). It's executed every 5ms, meaning it takes up something like 0.00032% of those 5ms. How is that in any way inefficient? Furthermore, when SetTimerEx is supported as well, one might even be able to speed up the server by changing the "sleep" server var (I will look into this).
Reply
#16

Quote:
Originally Posted by Slice
Посмотреть сообщение
The loop function takes 1.6 microseconds to execute (that's 0.0016 milliseconds). It's executed every 5ms, meaning it takes up something like 0.00032% of those 5ms. How is that in any way inefficient? Furthermore, when SetTimerEx is supported as well, one might even be able to speed up the server by changing the "sleep" server var (I will look into this).
1.6 microseconds with how many loops? how did you measure that time?
Reply
#17

Quote:
Originally Posted by wups
Посмотреть сообщение
1.6 microseconds with how many loops? how did you measure that time?
Default setting, 128. I started a couple timers, then used my benchmarking macros to run the function (ofcourse with CallLocalFunction disabled). It's a simple loop, what did you expect?
Reply
#18

Oh i will be using it of course thanks for sharing man.
Reply
#19

Quote:
Originally Posted by RyDeR`
Посмотреть сообщение
Very useful release.

Perhaps this could help you developing "SetTimerEx":
pawn Код:
preventCrash(); public preventCrash()
{
    SetTimerEx("preventCrash", 0, 0, "");
}

stock SetTimerEx_(szFunc[], iInterval, iRepeating, szFormat[], { Float, _ }: ...)
{
    new
        iArgs = numargs() << 2,
        iStart,
        iEnd
    ;
    #emit CONST.PRI szFormat
    #emit STOR.S.PRI iStart
     
    #emit LOAD.S.PRI iArgs
    #emit ADD.C 8
    #emit STOR.S.PRI iEnd
   
    for(new i = iEnd; i >= iStart; i -= 4)
    {
        #emit LCTRL 5
        #emit LOAD.S.ALT i
        #emit ADD
        #emit LOAD.I
        #emit PUSH.PRI
    }
    #emit PUSH.S szFormat
    #emit PUSH.S iRepeating
    #emit PUSH.S iInterval
    #emit PUSH.S szFunc
    #emit PUSH.S iArgs
    #emit SYSREQ.C SetTimerEx
   
    for(iArgs = iArgs >> 2 + 1; iArgs--; )
    {
        #emit STACK 4
    }
}
Not worked...
Reply
#20

If you actually read the post, you'd see that RyDeR` said:
Quote:

Perhaps this could help you developing "SetTimerEx":

Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)