Skip to content

fix(ext/node): improve perf_hooks timerify and add missing exports#33581

Merged
bartlomieju merged 4 commits intomainfrom
fix/perf-hooks-timerify
Apr 27, 2026
Merged

fix(ext/node): improve perf_hooks timerify and add missing exports#33581
bartlomieju merged 4 commits intomainfrom
fix/perf-hooks-timerify

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

Summary

  • Rewrites performance.timerify to match Node.js behavior: constructor
    support via new.target, correct .name ('timerified <name>') and
    .length preservation, proper ERR_INVALID_ARG_TYPE validation, and
    optional histogram option
  • Exports timerify and eventLoopUtilization as named exports from the
    perf_hooks module, matching the Node.js API surface

Fixes 4 node_compat tests (14 -> 10 failing in the perf_hooks suite):

  • test-perf-hooks-timerify-return-value
  • test-perf-hooks-timerify-multiple-wrapping
  • test-perf-hooks-timerify-invalid-args
  • test-perf-hooks-timerify-error

Test plan

  • ./x test-compat parallel::test-perf-hooks-timerify-return-value passes
  • ./x test-compat parallel::test-perf-hooks-timerify-multiple-wrapping passes
  • ./x test-compat parallel::test-perf-hooks-timerify-invalid-args passes
  • ./x test-compat parallel::test-perf-hooks-timerify-error passes
  • Full parallel::test-perf-hooks suite: 10/14 failing (was 14/14)

Rewrites timerify to match Node.js behavior:
- Support constructor calls via new.target
- Preserve function .name (prefixed with 'timerified ') and .length
- Validate arguments with proper ERR_INVALID_ARG_TYPE errors
- Accept optional histogram option with validation

Also exports timerify and eventLoopUtilization as named exports
from the perf_hooks module, matching Node.js API surface.

Fixes 4 node_compat tests:
- test-perf-hooks-timerify-return-value
- test-perf-hooks-timerify-multiple-wrapping
- test-perf-hooks-timerify-invalid-args
- test-perf-hooks-timerify-error
Copy link
Copy Markdown
Contributor

@lunadogbot lunadogbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the four enabled tests pass against this diff: timerified.name === 'timerified ' + fn.name (chained as timerified timerified m), length preservation, new.target routing for class constructors, and ERR_INVALID_ARG_TYPE for non-function fn and non-record histogram. Two questions inline -- one about the silent loss of the measure entry that the previous impl emitted, one about a potential TypeError: Cannot read properties of null when options is non-undefined-but-null. Neither blocks the upstream test fix.

Comment thread ext/node/polyfills/perf_hooks.js
Comment thread ext/node/polyfills/perf_hooks.js
@bartlomieju
Copy link
Copy Markdown
Member Author

Thanks for the review!

Re: null options -- Good catch. Added a guard so timerify(fn, null) now throws ERR_INVALID_ARG_TYPE for "options". Pushed in 787795c.

Re: loss of measure entry -- The old performance.measure() call was already non-standard: Node.js emits entries with entryType: 'function', not 'measure'. So the previous behavior was incorrect (it created measure-type entries that no real Node.js code would expect). Removing it is the right thing; proper 'function'-type entry emission is tracked in the TODO for a follow-up.

Copy link
Copy Markdown
Contributor

@fibibot fibibot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API-shape improvements all match Node's lib/internal/perf/timerify.js:

  • validateFunction(fn, 'fn') → equivalent to the new ERR_INVALID_ARG_TYPE throw ✓
  • validateObject(options, 'options') → equivalent ✓
  • options.histogram validation with the RecordableHistogram arg-type message ✓
  • new.target constructor handling (Node uses ReflectConstruct(fn, args, fn), you use new fn(...args) — same observable behavior) ✓
  • name = 'timerified ${fn.name}' and length = fn.length
  • The four target tests are about exactly this API shape, so they'll pass.

But there's a real semantic regression vs the old code that's worth calling out — see inline.

CI is red on dprint formatting (the long if (options !== undefined ...) line wants to wrap onto multiple lines). ./tools/format.js will fix it; full failure at https://github.com/denoland/deno/actions/runs/25001671896/job/73213243736.

Comment thread ext/node/polyfills/perf_hooks.js
Comment thread ext/node/polyfills/perf_hooks.js Outdated
const end = performance.now();

performance.measure(`timerify(${fn.name || "anonymous"})`, { start, end });
if (options !== undefined && (typeof options !== "object" || options === null)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI lint fails here — dprint wants this if condition wrapped:

if (
  options !== undefined && (typeof options !== "object" || options === null)
) {
  throw new ERR_INVALID_ARG_TYPE("options", "Object", options);
}

./tools/format.js will auto-fix. Full output at https://github.com/denoland/deno/actions/runs/25001671896/job/73213243736 (3 platforms all show the same one-file diff).

@bartlomieju
Copy link
Copy Markdown
Member Author

Fixed the formatting -- pushed in 319d669.

Re: the behavioral regression -- agreed this is a defensible tradeoff. The old 'measure' entries were wrong-typed vs Node (which uses 'function' entryType), so anyone relying on them was depending on non-standard behavior that would break when we add proper Node-fidelity 'function' entries anyway.

I'd prefer option 1 (lean into Node fidelity) as a follow-up PR rather than complicating this one -- proper 'function' entry emission needs PerformanceObserver integration with the right entry type, constructor arg tracking, and histogram recording, which is the scope of the tier 2 timerify work. The TODO is tagged to @bartlomieju for tracking.

@bartlomieju bartlomieju merged commit b1b72e5 into main Apr 27, 2026
220 of 222 checks passed
@bartlomieju bartlomieju deleted the fix/perf-hooks-timerify branch April 27, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants