lastrun timer should compensate cb runtime #1

Closed
bbkr opened this Issue Oct 31, 2011 · 5 comments

Comments

Projects
None yet
2 participants

bbkr commented Oct 31, 2011

Currently by assigning "$e{'lastrun'} = clock();" in run-timers interval of the timer is shifted by time to run callback itself.

For example if you set interval = 1s and your &cb takes 0.5s:

  • you expect per hour 3600 calls with 50% loop usage
  • you get 2700 calls per hour with 0.25% loop usage

IMO more correct is to write $e{'lastrun'} += $e{'interval'}, even if new lastrun value is lower than current clock(). Overloading event loop is nasty (lastrun timer may be permanently behind clock()) but it helps to better utilize CPU.

Owner

tadzik commented Oct 31, 2011

$e{'lastrun'} += $e{'interval'} fails the first callback, given that $e{'lastrun'} is initialized with zero. Movingd $e{'lastrun'} = clock(); before the callback fixes it, but can make a callback called not often enough, if, for some reason, the previous event takes an unusually long amount of time. Consider for example timed event A (interval 2) and a random-ish event B

With $e{'lastrun'} = clock() before the callback, situation goes as follows:

  • A gets called, lastrun becomes n
  • A gets called, lastrun becomes n + 2
  • B gets called a call takes 4 seconds
  • A gets called, lastrun becomes n + 6 (B took too much time)

With $e{'lastrun'} += $e{'interval'}, it could possibly turn out like this

  • A gets called, lastrun becomes n
  • A gets called, lastrun becomes n + 2
  • B gets called a call takes 4 seconds
  • A gets called, lastrun becomes n + 4
  • On the next opportunity, after a fraction of second A gets called once again, lastrun becomes n + 6, but the interval between this call and the last one is much, much shorter than 2 seconds (virtually 0 seconds given the perfect event loop and other conditions).

What do you think?

bbkr commented Oct 31, 2011

To avoid stacking the same event that is few cycles behind schedule you can modify lastrun assignment:

$e{'lastrun'} = ( $e{'lastrun'}+$e{'interval'} < clock() ?? clock() !! $e{'lastrun'}+$e{'interval'});

So it doesn't spawn next timer with assumed interval if it will be for sure behind schedule...

Let's simulate:

  • clock = n+100, lastrun = n+20, interval = 2s. Next timer call will be on n+102, because n+22 is already late.
  • clock=n+100, lastrun = n+99, itnerval = 2s. Next timer call will be on n+101.

Both examples are immune to long time spent in &cb (their or others).

And such assignment should be after &cb call.

Owner

tadzik commented Oct 31, 2011

IIUC that could be written as
$e{'lastrun'} = ($e<lastrun> + $e<interval>) max clock()
But I don't think it will ever evaluate to ($e<lastrun> + $e<interval>), given that we only enter this branch of code if clock() > $e<lastrun> + $e<interval>. What am I missing?

bbkr commented Oct 31, 2011

You're right. That was not correct formula, it should check 2 intvals ahead (one that we know already passed because we're in "if" section, and proper prediction). However it complicates the code.

So far the best solution is to move $e{'lastrun'} = clock() before the callback so that it ignores callback time. That solves issue from first post.

Owner

tadzik commented Oct 31, 2011

Okay, thanks for your input; will fix that in a second.

tadzik closed this in 1178476 Oct 31, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment