Skip to content

node:perf_hooks — performance object, User Timing, PerformanceObserver + granular node-suite - #1321

Merged
proggeramlug merged 2 commits into
mainfrom
feat/perf-hooks-node-suite
May 22, 2026
Merged

node:perf_hooks — performance object, User Timing, PerformanceObserver + granular node-suite#1321
proggeramlug merged 2 commits into
mainfrom
feat/perf-hooks-node-suite

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

What

Implements node:perf_hooks natively and adds a granular parity suite for it. Before this, only the syntactic performance.now() special case existed — the imported performance binding was a boolean stub and everything else (mark/measure/PerformanceObserver/timeOrigin/…) was missing.

Tests (decomposed from Node v25.8.0)

19-file granular suite under test-parity/node-suite/perf_hooks/, derived from Node's test-perf-hooks-usertiming.js, test-performance-measure.js, test-performance-global.js, and test-perf-hooks-eventlooputilization.js. Each is a single-behavior print-and-diff case, validated byte-for-byte against node --experimental-strip-types.

./run_parity_tests.sh --suite node-suite --module perf_hooks → 19/20 PASS.

Covered: imports/typeof shapes · now (number + monotonic) · timeOrigin · mark (shape, name coercion, startTime/detail options) · measure (positional marks + {start,end,duration} options, exact Node arithmetic incl. startTime: -1) · getEntriesByType/getEntriesByName · clearMarks/clearMeasures · eventLoopUtilization shape · PerformanceObserver (constructor, observe({entryTypes}), async callback delivery, list.getEntries(), disconnect) · constants.NODE_PERFORMANCE_GC_*.

How

  • New crates/perry-runtime/src/perf_hooks.rs: per-thread timeline, User Timing, ELU, and a PerformanceObserver registry with async delivery via a single setTimeout(flush, 0) (callback gets a list object). GC root scanner keeps stored detail values + observer callbacks alive.
  • perf_hooks added to NATIVE_MODULES + RUNTIME_ONLY_MODULES so its named imports bind to real namespace objects (root cause of the old boolean stub).
  • dispatch_native_module_method / get_native_module_constant / is_native_module_callable_export gain perf_hooks / perf_observer / perf_observer_list arms.
  • HIR lowers performance.<method>() to the perf_hooks NativeMethodCall; codegen routes performance.* and observer methods to the js_perf_* helpers.

Deferred (1/20)

observer/entry-types asserts typeof obs.observe === "function". Perry lowers a member read on a native-class instance as a method call, so typeof obs.observe misroutes. The call forms all work (observe-marks, the async-delivery test, passes). This is a Perry-core member-dispatch limitation, not perf_hooks-specific → filed as #1320 and recorded in known_failures.json.

Notes

  • Full node-suite regression: 563/582 (96.7%); the other failures are pre-existing gaps in events/timers/console/assert/buffer (untouched here).
  • No version bump / CHANGELOG entry — left for the maintainer to fold in at merge (per the external-contributor PR convention), to avoid patch-version collisions.
  • cargo fmt --all -- --check clean; perry-api-manifest manifest-consistency test passes.

#1304 vendored optional_frameworks

Folds two PRs that merged post-v0.5.1022 without version bumps. See
CHANGELOG.md for the rollup.
@proggeramlug
proggeramlug force-pushed the feat/perf-hooks-node-suite branch from 646b0b6 to 30c0ad8 Compare May 22, 2026 09:17
…ormanceObserver

Implement node:perf_hooks natively (previously only the syntactic
performance.now() special case existed; the imported `performance` binding
was a boolean stub).

Runtime (crates/perry-runtime/src/perf_hooks.rs):
- `performance` is a real object: typeof "object", now/timeOrigin, and
  mark/measure/getEntries/getEntriesByName/getEntriesByType/clearMarks/
  clearMeasures over a per-thread timeline. measure() implements Node's full
  positional + options (start/end/duration/detail) arithmetic.
- eventLoopUtilization() returns { idle, active, utilization }.
- PerformanceObserver: new/observe/disconnect/takeRecords + async callback
  delivery via a single setTimeout(flush, 0); the callback receives a list
  object with getEntries/getEntriesByType/getEntriesByName.
- constants.NODE_PERFORMANCE_GC_*.
- GC root scanner keeps stored detail values + observer callbacks alive.

Wiring:
- Add perf_hooks to NATIVE_MODULES + RUNTIME_ONLY_MODULES so the named
  imports bind to real namespace objects instead of stub funcs.
- dispatch_native_module_method + get_native_module_constant +
  is_native_module_callable_export gain perf_hooks / perf_observer /
  perf_observer_list arms.
- HIR module_static.rs lowers performance.<method>() to the perf_hooks
  NativeMethodCall; codegen routes performance.* and observer methods to the
  js_perf_* runtime helpers.

Tests: 19-file granular node-suite under test-parity/node-suite/perf_hooks/,
decomposed from Node v25.8.0's perf_hooks tests. 19/20 pass. The lone
deferral, observer/entry-types (`typeof obs.observe`), is blocked by a
Perry-core limitation (member reads on native-class instances lower as calls)
tracked in #1320 + known_failures.json.
@proggeramlug
proggeramlug force-pushed the feat/perf-hooks-node-suite branch from 30c0ad8 to bf71a9c Compare May 22, 2026 09:27
@proggeramlug
proggeramlug merged commit f28221f into main May 22, 2026
9 checks passed
@proggeramlug
proggeramlug deleted the feat/perf-hooks-node-suite branch May 22, 2026 09:33
proggeramlug added a commit that referenced this pull request May 22, 2026
Follow-up to #1321 (the perf_hooks implementation). Adds 13 granular
node-suite cases plus the runtime behavior they require:

- mark/measure instanceof PerformanceEntry / PerformanceMark / PerformanceMeasure
- getEntries() unfiltered; getEntriesByName / getEntriesByType no-match
- measure({ start, duration, detail }) detail handling
- observer: observe 'measure', takeRecords(), and multiple entryTypes in one
  delivery
- eventLoopUtilization() first-call shape
- input validation matching Node: performance.mark() / clearMarks() throw a
  TypeError on a Symbol name; mark() throws on a non-numeric startTime
- getEntries* and observer lists now return entries ordered by startTime
  (Node returns the timeline sorted, stable on ties)

31/33 pass. Two deferrals, recorded in test-parity/known_failures.json:
observer/entry-types (typeof obs.observe — native-class member reads lower as
calls, #1320) and global/performance-identity (globalThis.performance identity,
#1327).
proggeramlug added a commit that referenced this pull request May 22, 2026
…odeTiming, toJSON, resource-timing, single-type observe) (#1342)

Follow-up to #1321/#1328. Adds 11 granular cases covering the rest of the
node:perf_hooks surface. New passing: observer observe({type}) single-type,
eventLoopUtilization(b,a) two-arg diff, getEntriesByName(name,type).

8 new cases pin gaps, each tracked by its own granular issue + known_failures:
- timerify (#1335), monitorEventLoopDelay/createHistogram (#1336),
  nodeTiming (#1337), toJSON (#1338), clearResourceTimings/
  setResourceTimingBufferSize (#1339), mark detail structured-clone (#1340),
  PerformanceObserver.supportedEntryTypes.includes (#1341).
proggeramlug added a commit that referenced this pull request May 22, 2026
…sweep (#1414)

Rolls up 26 PRs that merged to main post-v0.5.1023 without version
bumps:

- node:crypto gap-fixes (#1386 #1393 #1394 #1402 #1405): randomInt,
  timingSafeEqual, getHashes/getCiphers, sha224/sha384, base64 digest,
  Buffer hash input, no-arg digest() → Buffer, pbkdf2Sync digest arg,
  scryptSync.
- node:perf_hooks (#1321 + #1328 #1342 coverage): performance + User
  Timing + PerformanceObserver native impl, granular node-suite +
  edge-case coverage.
- #1090 GC checkpoint runtime work (#1324).
- #1311 geisterhand on iOS (#1316 #1383 #1384 #1385).
- #1312 process.env.X (unset) is nullish undefined (#1314).
- #1319 thread-safety hardening for cross-thread runtime statics.
- #1322 exact-head GC evidence packet.
- #1323 wasm timers dispatch through mem_call bridge (#1329).
- #1317 node:timers/promises shadow-segfault fix (#1326).
- #1330 node:process suite (#1331).
- #1292 bcrypt.hash() returns String (#1307).
- #1293 fastify .json()/.body external-fastify dispatch (#1308).
- #1296 app pattern performance gaps.
- #1297 diagnostics_channel parity.
- #1301 iOS App Groups capability (#1313).
- #1318 #1325 os/methods/modern-methods static dispatch.
- #1315 expanded Node parity test coverage.
- #1382 ui-ios stdlib pump for async fetch.
- #1392 ui-wasm reactive state + setText (#1404).
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.

1 participant