-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
setTimeout callback executed before delay elapses #10154
Comments
Cannot reproduce locally on a FC25 system. A possible explanation is that Date.now() is backed by a CLOCK_REALTIME time source (gettimeofday) whereas node/libuv uses a CLOCK_MONOTONIC clock. If ntpdate is adjusting the system clock, you might see <= 0 intervals between two Date.now() calls. What happens when you use |
For code with // main.js
const timeJustBeforeCallingSetTimeout = process.hrtime();
setTimeout(() => {
const delayBetweenMainCodeAndCallbackExecutionInNanoSec =
process.hrtime(timeJustBeforeCallingSetTimeout)[1];
console.log(delayBetweenMainCodeAndCallbackExecutionInNanoSec);
}, 1); # bash script that runs js code 1000 times
rm -f results.txt
for ((n=0;n<1000;n++))
do
node main.js >> results.txt
done
cat results.txt | grep '^.\{6\}$' | wc -l |
@marzelin Could you try |
When time difference is measured with // main.js
const timeJustBeforeCallingSetTimeout = process.binding('timer_wrap').Timer.now();
setTimeout(() => {
const callbackExecutionTime = process.binding('timer_wrap').Timer.now();
console.log(callbackExecutionTime - timeJustBeforeCallingSetTimeout);
}, 1); # bash script that runs js code 1000 times and counts cases where time difference is 0
rm -f results.txt
for ((n=0;n<1000;n++))
do
node main.js >> results.txt
done
cat results.txt | grep 0 | wc -l |
@bnoordhuis any idea? |
@marzelin Are you running Ubuntu inside a VM or a container? I know VirtualBox has (had?) clock skew bugs in the past, perhaps other products do too. |
@bnoordhuis Ubuntu is loaded directly by UEFI, no VMs are involved. On Windows 10 (same PC and node version) results are similar. |
I have been able to reproduce this a few times now (over 100,000s of runs) but so far I've only been able to establish that the kernel seems to return early from the epoll_wait() system call for no discernible reason whatsoever. This is with a stock 4.8.8-300.fc25.x86_64 kernel. @marzelin Re: Windows: did you test with Date.now(), Timer.now() or process.hrtime()? |
@bnoordhuis All of them, but I did only a few tests there. |
I'm coming around to the idea that this might be a hardware issue. I've so far only been able to reproduce on one system and I noticed that this system's hardware clock drifts by one or two seconds every few hours. @marzelin Can you post the output of:
Your system probably only has one hardware clock. Try switching to different sources (e.g. from tsc to hpet) and see if the problem goes away. EDIT: Oh, and please disable anything that syncs the clock; ntpd, ntpdate cron jobs, etc. |
$ cat /sys/devices/system/clocksource/clocksource*/available_clocksource
tsc hpet acpi_pm
$ cat /sys/devices/system/clocksource/clocksource*/current_clocksource
tsc I've got the same results when |
I did some other tests and it seems like So for example if we have point in time: |
Edit: |
@bnoordhuis any further thoughts? |
I'm still investigating this although I probably won't revisit it until January. You can assign it to me if you want. |
I suspect that this is because we track loop->time in libuv in milliseconds. |
Can you bring this up on the libuv repo? Thanks!
…On Thu, Jan 12, 2017 at 10:53 PM, John Barboza ***@***.***> wrote:
I suspect that this is because we track loop->time in libuv in
milliseconds.
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000
So the difference between 2 different loop->time values could potentially
show a 1 millisecond difference even when 1 nanosecond has passed.
This could be fixed by tracking loop->time in nanoseconds instead of
milliseconds.
I tested this change and it seems to fix the issue (no more 0 second
delays).
Let me know if this solution makes sense.
***@***.***
<jBarz@84fbba5>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#10154 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AATYGBCyzKHaiXbrsoMEy9vfQ6ne5YjIks5rRwNJgaJpZM4LFyZq>
.
--
/Saúl
bettercallsaghul.com
|
I have submitted a PR on the libuv repo |
Should this be closed (or at least labeled |
Labeled |
Looks like I have the same issue which stability reproduced on the following test: 'use strict';
const assert = require('assert');
const DELAY = 10;
function call() {
const start = process.hrtime();
setTimeout(() => {
const diff = process.hrtime(start);
const [seconds, nanoseconds] = diff;
const ms = seconds * 1e3 + nanoseconds * 1e-6;
console.log(ms);
assert(ms >= DELAY);
call();
}, DELAY);
}
call();
Next 3 consecutive runs:
|
@Trott Could you revisit this issue? Looks like this issue can be solved on nodejs side libuv/libuv#1191 (comment). |
@ikokostya Your repro triggers the assertion for me on Node.js 8.4.0 but not on 9.0.0-pre (current master branch). Any chance you can compile from the master branch or grab the most recent nightly and see if it's fixed for you there? |
The same error:
|
Interesting that I can't replicate on macOS. @Fishrock123 @misterdjules Any thoughts on the fix for #10154 (comment) suggested by @jBarz at libuv/libuv#1191 (comment)? |
Any news? I still get error for |
@bnoordhuis Can anything be done here? |
@jBarz Per libuv/libuv#1191 (comment), do you want to open a pull request here? |
@bnoordhuis @jBarz I'm not sure the proposed fix there solves the issue. We already have something very similar (setting |
I've tried the fix myself and it seems to resolve the issue. @apapirovski Are you able to recreate the error using @ikokostya test case with the proposed fix? You're right, the case is not |
@jBarz yeah, I see what you mean now. Not a huge fan of adding 1ms to all timers (the magic number is a bit of a code smell) that run through that block but I'm not really seeing another solution. I suppose it depends on whether we consider this important to fix or if infrequent 1ms inaccuracy is acceptable. FWIW it should happen a lot less now than it used to when this issue was made. |
Yea, I agree that adding 1ms to all timers is not ideal. |
Okay, I'll close this out then. |
This can be fixed by: #20555 (I've had the test case running for an hour with no failures. Pretty sure it resolves the issue.) Edit: I've taken out that bit because it made that PR too big but it'll be fixed in a follow-up PR. Either way, I'm keeping this open since it can be solved by Node.js. |
Refactor Timers to behave more similarly to Immediates by having a single uv_timer_t handle which is stored on the Environment. No longer expose timers in a public binding and instead make it part of the internalBinding. PR-URL: #20894 Fixes: #10154 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
This is no longer necessary in the only place it was used (timers). PR-URL: #20894 Fixes: #10154 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
The timers directory test, utilizing FakeTime, has not worked in quite a while and is not truly testing Node.js behaviour. If a similar test is necessary it would be better suited to libuv on which Node.js relies for timers functionality. PR-URL: nodejs#20894 Fixes: nodejs#10154 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
The timers directory test, utilizing FakeTime, has not worked in quite a while and is not truly testing Node.js behaviour. If a similar test is necessary it would be better suited to libuv on which Node.js relies for timers functionality. PR-URL: #20894 Fixes: #10154 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Backport-PR-URL: #22039 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Minwoo Jung <minwoo@nodesource.com>
In the modified test file, sleep() is backed by setTimeout(), and some Node runtimes might execute setTimeout callback before the specified delay, meaning that tmi.getValue() will occasionally return `9`. This produces a flaky test. An extra ms leeway in the assertion works round the issue. nodejs/node#10154 Test name updated to reflect that the timer's accuracy does not have single-digit precision
When the delay is set to
1
, for about 5% of cases the logged time between executingsetTimeout()
and the callback execution is0
.When the delay value is set to
2
, there are no cases where the logged time is less than 2, which is an expected behavior.The text was updated successfully, but these errors were encountered: