-
Notifications
You must be signed in to change notification settings - Fork 7.3k
setTimeout drifts after busy wait #8105
Comments
Win8, node 0.10.29:
|
Linux, node 0.10.30:
WIth v0.13.0-pre, the same as gist. |
Upgraded to 0.10.29 on OSX, to compare with Win8. Same result as 0.10.27:
|
normal behavior if your cpu is busy. chrome while cpu is busy:
what is not normal is the first idle being below 100ms, either 0 or 1 on my computer. ubuntu/10.30:
|
@almike Also I can control the drift precisely: if I change the busy wait to X ms, the abnormal |
what happens if you run it for a longer time?
also not sure if that is normal:
gives:
the first timeout is 63ms but it should be equal or above 100 |
Result:
|
Also, if I use |
ah so your idle time is actually busy time + idle time on your computer. |
Can you update the test to use process.hrtime() for comparison with |
If date was not updated during busy loop The Chromium link points to another problem, related to timezone offsets. |
@trevnorris The problem does not seem to be with |
but later if it happens in the loop, I thought it could be some caching for optimization... but you are right I looked at that chromium diff the changes do not match the title. |
ok, tried with v0.10.26. still on ubuntu:
seems ok @ v0.10.30, except for the first timeout which is triggered too fast. |
My results: 0.10.28:
0.10.30:
0.11.13
|
For reference I'm leaving this modified script. Will revisit later: "use strict";
function millis(hr) {
return hr[0] * 1e3 + ((hr[1] / 1e6) >>> 0);
}
function busyWait(ms, busyWaitCb) {
process._rawDebug('>>> busyWait begin');
var hr0 = process.hrtime();
while (ms > millis(process.hrtime(hr0)));
process._rawDebug('>>> busyWait end');
busyWaitCb();
}
function idleWait(ms, idleWaitCb) {
process._rawDebug('>>> idleWait begin');
setTimeout(idleSetTimeout, ms, idleWaitCb);
setImmediate(runSetImmediate);
process._rawDebug('>>> idleWait end');
}
function idleSetTimeout(idleWaitCb) {
process._rawDebug('>>> idleSetTimeout');
idleWaitCb();
}
function runSetImmediate() {
process._rawDebug('>>> runSetImmediate');
}
(function combined(a) {
busyWait(300, function busyWaitCb() {
idleWait(100, function idleWaitCb(){
a < 50 && combined(++a);
});
});
}(0)); |
I'm seeing this behavior in another use-case, which smells the same to me because the drifts are exactly the same as the sleep/work happening inside the timeout function. Mine is perhaps a bit simpler to understand than the ping-ponging/nesting of the original bug/gist. mine is: https://gist.github.com/natbro/bf872ac473a1bba04008. as you can see i'm just chaining setTimeout()'s and putting sleep (or any activity) within the callback. i see drift of exactly the amount of sleep/work i did within the callback, i.e. if i do 100ms of work in the callback and at the callback's tail use setTimeout() to run the callback again 200ms later it actually won't fire until 300ms later. although i thought this was the busy-sleep, it reproduced with other long-running computations, wasn't GC and wasn't other CPU activity. eventually on a whim i cleared the current timeout (the one i was within) before chaining to the next callback and the drift disappeared. I am reading through the node.js sources but haven't found anything suspicious in the timer.js/Timer class yet, but that's where I suspect the problem is given this is happening platform-agnostic. |
Fixed by d38e865. Released in v0.10.39 and v0.12.5. |
nice fix - thanks & sorry i didn't spot it. |
@natbro No worries, and thank you for investigating and reporting your findings 👍 |
if you call
setTimeout
after a busy wait the delay can be much longer than expected.I created a gist: https://gist.github.com/bjouhier/c7adb5f54caf9fc86d6e
OSX 10.9.4, node 0.10.27
The text was updated successfully, but these errors were encountered: