Skip to content

Commit

Permalink
make fasttimers independent from performance.now
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Aug 25, 2024
1 parent b802be6 commit ad339a2
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 6 deletions.
12 changes: 6 additions & 6 deletions lib/util/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ const nativeSetTimeout = global.setTimeout
const nativeClearTimeout = global.clearTimeout

/**
* The fastNow variable is used to store a current time in milliseconds
* since the process started.
* The fastNow variable contains the internal fast timer clock value.
*
* @type {number}
*/
Expand Down Expand Up @@ -118,12 +117,13 @@ const ACTIVE = 1
*/
function onTick () {
/**
* The fastNow variable is used to store the current time in milliseconds
* since the process started.
* Increment the fastNow value by the TICK_MS value, despite the actual time
* that has passed since the last tick. This approach ensures independence
* from the system clock and delays caused by a blocked event loop.
*
* @type {number}
*/
fastNow = Math.trunc(performance.now())
fastNow += TICK_MS

/**
* The `idx` variable is used to iterate over the `fastTimers` array.
Expand Down Expand Up @@ -363,7 +363,7 @@ module.exports = {
}
},
/**
* The now method returns the value of the cached performance.now() value.
* The now method returns the value of the internal fast timer clock.
*
* @returns {number}
*/
Expand Down
22 changes: 22 additions & 0 deletions test/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { tspl } = require('@matteo.collina/tspl')
const { describe, test } = require('node:test')

const timers = require('../lib/util/timers')
const { eventLoopBlocker } = require('./utils/event-loop-blocker')

describe('timers', () => {

Check failure on line 9 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (22, macos-latest) / Test with Node.js 22 on macos-latest

timers

Error [ERR_TEST_FAILURE]: Promise resolution is still pending but the event loop has already resolved at process.emit (node:events:520:28) { code: 'ERR_TEST_FAILURE', failureType: 'cancelledByParent', cause: 'Promise resolution is still pending but the event loop has already resolved' }

Check failure on line 9 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (20, macos-latest) / Test with Node.js 20 on macos-latest

timers

Error [ERR_TEST_FAILURE]: Promise resolution is still pending but the event loop has already resolved at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'cancelledByParent', cause: 'Promise resolution is still pending but the event loop has already resolved' }

Check failure on line 9 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (21, macos-latest) / Test with Node.js 21 on macos-latest

timers

Error [ERR_TEST_FAILURE]: Promise resolution is still pending but the event loop has already resolved at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'cancelledByParent', cause: 'Promise resolution is still pending but the event loop has already resolved' }

Check failure on line 9 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (18, macos-latest) / Test with Node.js 18 on macos-latest

timers

Error [ERR_TEST_FAILURE]: Promise resolution is still pending but the event loop has already resolved at process.emit (node:events:517:28) { failureType: 'cancelledByParent', cause: 'Promise resolution is still pending but the event loop has already resolved', code: 'ERR_TEST_FAILURE' }
test('timers exports a clearTimeout', (t) => {
Expand Down Expand Up @@ -100,6 +101,27 @@ describe('timers', () => {
timers.clearTimeout(timer)
})

test('a FastTimer will only increment by the defined TICK_MS value', async (t) => {
t = tspl(t, { plan: 2 })

const startInternalClock = timers.now()

// The long running FastTimer will ensure that the internal clock is
// incremented by the TICK_MS value in the onTick function
const longRunningFastTimer = timers.setTimeout(() => {}, 1e10)

eventLoopBlocker(1000)

// wait to ensure the timer has fired in the next loop
await new Promise((resolve) => setTimeout(resolve, 1))

t.strictEqual(timers.now() - startInternalClock, 499)
await new Promise((resolve) => setTimeout(resolve, 1000))
t.strictEqual(timers.now() - startInternalClock, 1497)

Check failure on line 120 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (22, macos-latest) / Test with Node.js 22 on macos-latest

a FastTimer will only increment by the defined TICK_MS value

[Error [ERR_TEST_FAILURE]: Expected values to be strictly equal: 998 !== 1497 ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: 998 !== 1497 at res.<computed> [as strictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at TestContext.<anonymous> (/Users/runner/work/undici/undici/test/timers.js:120:7) at runNextTicks (node:internal/process/task_queues:65:5) at process.processTimers (node:internal/timers:526:9) at async Test.run (node:internal/test_runner/test:879:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:590:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: 998, expected: 1497, operator: 'strictEqual' } }

Check failure on line 120 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (20, macos-latest) / Test with Node.js 20 on macos-latest

a FastTimer will only increment by the defined TICK_MS value

[Error [ERR_TEST_FAILURE]: Expected values to be strictly equal: 998 !== 1497 ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: 998 !== 1497 at res.<computed> [as strictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at TestContext.<anonymous> (/Users/runner/work/undici/undici/test/timers.js:120:7) at async Test.run (node:internal/test_runner/test:790:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:517:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: 998, expected: 1497, operator: 'strictEqual' } }

Check failure on line 120 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (21, macos-latest) / Test with Node.js 21 on macos-latest

a FastTimer will only increment by the defined TICK_MS value

[Error [ERR_TEST_FAILURE]: Expected values to be strictly equal: 998 !== 1497 ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: 998 !== 1497 at res.<computed> [as strictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at TestContext.<anonymous> (/Users/runner/work/undici/undici/test/timers.js:120:7) at runNextTicks (node:internal/process/task_queues:60:5) at process.processTimers (node:internal/timers:511:9) at async Test.run (node:internal/test_runner/test:640:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:382:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: 998, expected: 1497, operator: 'strictEqual' } }

Check failure on line 120 in test/timers.js

View workflow job for this annotation

GitHub Actions / test (18, macos-latest) / Test with Node.js 18 on macos-latest

a FastTimer will only increment by the defined TICK_MS value

[Error [ERR_TEST_FAILURE]: Expected values to be strictly equal: 998 !== 1497 ] { failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: 998 !== 1497 at res.<computed> [as strictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at TestContext.<anonymous> (/Users/runner/work/undici/undici/test/timers.js:120:7) at runNextTicks (node:internal/process/task_queues:60:5) at process.processTimers (node:internal/timers:509:9) at async Test.run (node:internal/test_runner/test:632:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:374:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: 998, expected: 1497, operator: 'strictEqual' }, code: 'ERR_TEST_FAILURE' }

timers.clearTimeout(longRunningFastTimer)
})

const getDelta = (start, target) => {
const end = process.hrtime.bigint()
const actual = (end - start) / 1_000_000n
Expand Down

0 comments on commit ad339a2

Please sign in to comment.