ReviewOS

zig-utils/zig-js

Profiler: keep native tiers active during CPU sampling

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

Parent: #501 Related: #404

Executed problem

The private CPU profiler installs Context.profile_statement_hook. On current main (f9ed7030), that changes execution rather than observing it:

  • Context.interpreter() publishes no jit_owner whenever profile_statement_hook != null;
  • vm.statementHooksRequireBytecode() rejects native entry and optimizer OSR for the same hook;
  • the existing vm: optimizer executes multiple iterations after a hot backedge test explicitly proves that adding a profile hook leaves optimizer_native_attempts unchanged and refuses both OSR and entry execution.

The profiler therefore cannot satisfy #501's inspector/native agreement requirement: collected inspector samples necessarily describe bytecode/tree execution even when the same workload normally runs in baseline or optimizer code.

Scope

  • Keep debugger and host-statement hooks on the current exact bytecode path.
  • Allow the observation-only CPU profile hook to retain baseline and optimizer eligibility.
  • Sample managed baseline execution at its existing exact checkpoint island using the published bytecode offset and statement registry.
  • Preserve exact source URL, script, line, column, activation chain, sampling interval, and profile output schemas.
  • Let optimizer checkpoint/side-exit paths resume through the ordinary exact bytecode statement boundary; do not create profiler-only optimizer codegen.
  • Preserve disabled-profile hot paths and native step/budget/GC/termination semantics.

Acceptance

  • A focused native-tier witness records profile samples while baseline/optimizer execution counters remain nonzero on supported hosts.
  • Native checkpoint samples carry the exact source statement selected by the checkpoint bytecode offset.
  • Debugger and host hooks still refuse native execution.
  • Existing Home/Bun CPU-profile fixtures, native forced-on/off differentials, and unsuppressed TSan coverage pass.
  • Documentation states that profiling observes the active tier and identifies the checkpoint sampling boundary without overstating timer precision.

Guardrails

No profiler-only codegen, periodic signal thread, guessed PC/source mapping, forced deoptimization on every statement, disabled JIT during profiling, or output-schema change.

9 days ago

Implemented in f5c638e1.

CPU profiling now preserves baseline and optimizer eligibility. Managed baseline checkpoints carry their owning chunk, publish the exact exit_ip, and resolve that bytecode offset through the ordinary statement registry before copying the activation chain. Optimizer checkpoint exits continue through the exact VM statement boundary. Debugger and host hooks still refuse native execution.

Validation:

  • focused optimizer hook witness: pass;
  • focused context witness: baseline and optimizer counters both advance while the hook observes the native loop source row;
  • focused context witness under unsuppressed TSan: pass;
  • Home and Bun private CPU-profile fixtures: Debug, ReleaseSafe, and TSan pass, with 538/538 and 484/484 ABI inventories classified;
  • full unit gate: 2,584 passed, 1 skipped, 0 failed, 0 leaked across 10 shards;
  • docs: 378 links resolve and the pinned BunPress manifest/build passes.

The Test262 corpus is absent from this checkout, so no conformance-flip count is claimed. This change affects profiler scheduling and source attribution, not JavaScript semantics.

Sign in to comment on this issue.