ReviewOS

zig-utils/zig-js

Perf: elide unrestricted owner checks in fused allocation loops

#81
Closed chris opened this 9 days ago ·
9 days ago

Parent: #62 Follows: #74, #76

Evidence

A 5-second 1 ms symbolized sample of current main e78ae6c4 on the bounded object_churn kernel attributes 434 of 3,810 top-of-stack samples (~11.4%) to Interpreter.checkRestricted. It is the third-largest entry after VM dispatch and nursery sweeping. The quick object-allocation loop repeats that non-inlined error/TLS path for every dense replacement even though ordinary arrays have restricted_to == 0.

The first experiment moved the full check before the fused slice, but the VM's current safepoint step budget admits only one 61-step allocation iteration per slice. That variant therefore did not reduce check frequency and was rejected after a 2/7-pair result (+0.72% median time).

Refined scope

  • load restricted_to directly in the quick loop and skip the non-inlined checkRestricted/thread-ID path when the owner is zero;
  • retain the full ownership check and exact error-step accounting for restricted arrays;
  • retain ordinary bytecode fallback for synchronized/escaped execution;
  • preserve exact bytecode steps, OOM resumption state, dense-store barriers, and restricted-object failure behavior;
  • do not change the shared JavaScript/JSC workload source.

Acceptance criteria

  • Record and reject the ineffective slice-level hoist with exact A/B evidence.
  • Focused VM coverage proves the quick allocation loop still runs and preserves exact results/steps.
  • Restricted receivers still fail without mutating the dense element.
  • A current-main vs candidate alternating A/B preserves checksum 1030552128 and shows a repeatable direct object_churn win.
  • A post-change profile removes checkRestricted from the unrestricted per-cell hot path.
  • Run the full unit and comparison-harness suites only after a measured win.
  • Commit references this issue and is pushed as Chris without coauthors.
9 days ago

Rejected the first implementation and kept it out of git: seven alternating process pairs, three samples/process, exact checksum in all 42 samples. The candidate won 2/7 pairs and the median of process medians moved 226.628333 ms -> 228.256666 ms (+0.72%). The sample budget allows one allocation iteration per fused slice, so moving the same check to slice entry did not reduce its frequency. Scope is now narrowed to an explicit owner-zero fast guard that avoids the function/TLS path entirely while preserving the full rare restricted case.

9 days ago

Implemented and pushed to main in 8fc4c5a.

Evidence:

  • Two independent 7-pair alternating A/B batches, with three timed samples per process and exact checksum 1030552128 for all 84 samples.
  • Batch 1: 3/7 pair wins; median of process medians improved from 226.274584 ms to 224.222042 ms, 0.91% lower.
  • Batch 2: 6/7 pair wins; median improved from 233.157833 ms to 224.901500 ms, 3.54% lower.
  • Combined: 9/14 pair wins; median improved from 227.507 ms to 224.5395 ms, 1.30% lower.
  • A post-change 3-second symbolized sample removed Interpreter.checkRestricted entirely from the object_churn collapsed hot list.
  • Focused unrestricted and restricted-receiver regression tests passed.
  • Batched validation passed: 758/758 unit tests, zero skipped, zero failed, zero leaked; benchmark comparison harness 7/7.

The accepted implementation keeps the full acquire ownership check and exact error-step accounting for restricted arrays, while unrestricted arrays avoid entering the non-inlined error/TLS path. The earlier slice-hoist candidate remains rejected and uncommitted as documented above.

9 days ago

Completed by 8fc4c5a on main.

Sign in to comment on this issue.