Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- JIT M3: cache one idle native entry handle per runtime with epoch-based
invalidation (ABI minor 20), remove native-return queue allocation, and reuse
CALL feedback storage. Reuse validated bytecode boundaries during helper PC
checks. Add acquisition metrics, lifecycle regressions, and
paired generic-call diagnostics. See `docs/M3.md`.

### Deprecated

### Removed
Expand Down
15 changes: 15 additions & 0 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ it is a designated compute kernel and must enter its requested native tier.
zero-entry samples remain visible as an explicit fail-closed gap instead of
being reported as native performance.

`generic-call-entry` isolates the generic native-call boundary with a batched
short callee taking `(Int32, Bool)`. The Bool argument excludes the numeric
direct-call signature used by `call-heavy`. The Tier 1 integration test verifies
one `CALL` helper invocation per iteration and native callee entry, so a future
specialization change cannot silently turn this into a direct-call benchmark.
Its checksum is `seed + iterations`. It is non-designated because automatic
mode may demote this call-only workload. Compare it with `call-heavy` and
`fibonacci-recursive` when optimizing entry overhead; zero native entries are
fallback evidence, not an improvement in native entry cost.

New evidence includes `native_acquisitions`: successfully acquired backend
handles, including OSR. Native executions that reuse a C entry handle increase
`native_entries` without another acquisition. Older reports omit this optional
counter; Bun reports it as `null`.

## Representative performance matrix

The default run also covers the broader JavaScript surface below. Every case
Expand Down
2 changes: 2 additions & 0 deletions benchmarks/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub struct SampleEvidence {
pub elapsed_ns: u64,
pub checksum: String,
pub native_entries: Option<u64>,
#[serde(default)]
pub native_acquisitions: Option<u64>,
pub native_exits: Option<u64>,
pub fallback_count: Option<u64>,
pub retry_count: Option<u64>,
Expand Down
7 changes: 4 additions & 3 deletions benchmarks/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ fn render(data: &BenchmarkFile) -> (String, bool) {
let t2 = mode(data, "tier2");
let auto = mode(data, "automatic");
let bun = mode(data, "bun");
let mut out=format!("# JIT performance report\n\nStatus: generated from tracked raw `jit-benchmark-v1` evidence. Source `{}` (dirty: {}), QuickJS `{}`; target `{}`; CPU `{}`; power `{}`. Bun: `{}` at `{}` (SHA-256 `{}`).\n\nCommand: `{}`. Schema SHA-256 `{}`; suites lock SHA-256 `{}`.\n\nSampling: {} discarded warmup processes, {} interleaved paired fresh processes, {} interleaved one-second throughput windows, {} joint paired bootstrap resamples.\n\n## Workloads\n\nA JIT ratio is reported only when that mode actually entered native code; fallback-only timing is shown as `N/A (no native entry)`. Bun remains an external engine comparison.\n\n| workload (suite) | interpreter median ns | Tier1 | Tier2 | automatic | Bun | T1/T2 entries | fallback/retry | checksum |\n|---|---:|---:|---:|---:|---:|---:|---:|---|\n",data.provenance.source_revision,data.provenance.source_dirty,data.provenance.quickjs_revision,data.provenance.target,data.provenance.cpu.replace('\n'," "),data.provenance.power_mode,data.provenance.bun_version.as_deref().unwrap_or("N/A"),data.provenance.bun_path.as_deref().unwrap_or("N/A"),data.provenance.bun_sha256.as_deref().unwrap_or("N/A"),data.provenance.command.join(" "),data.provenance.schema_sha256,data.provenance.suites_lock_sha256,data.policy.latency_warmups,data.policy.latency_processes,data.policy.throughput_windows,data.policy.bootstrap_resamples);
let mut out=format!("# JIT performance report\n\nStatus: generated from tracked raw `jit-benchmark-v1` evidence. Source `{}` (dirty: {}), QuickJS `{}`; target `{}`; CPU `{}`; power `{}`. Bun: `{}` at `{}` (SHA-256 `{}`).\n\nCommand: `{}`. Schema SHA-256 `{}`; suites lock SHA-256 `{}`.\n\nSampling: {} discarded warmup processes, {} interleaved paired fresh processes, {} interleaved one-second throughput windows, {} joint paired bootstrap resamples.\n\n## Workloads\n\nTier1/Tier2 columns require an entry in the requested tier; automatic accepts either native tier. Without that evidence, timing is shown as `N/A (no qualifying native entry)`. Bun remains an external engine comparison.\n\n| workload (suite) | interpreter median ns | Tier1 | Tier2 | automatic | Bun | T1/T2 entries | fallback/retry | checksum |\n|---|---:|---:|---:|---:|---:|---:|---:|---|\n",data.provenance.source_revision,data.provenance.source_dirty,data.provenance.quickjs_revision,data.provenance.target,data.provenance.cpu.replace('\n'," "),data.provenance.power_mode,data.provenance.bun_version.as_deref().unwrap_or("N/A"),data.provenance.bun_path.as_deref().unwrap_or("N/A"),data.provenance.bun_sha256.as_deref().unwrap_or("N/A"),data.provenance.command.join(" "),data.provenance.schema_sha256,data.provenance.suites_lock_sha256,data.policy.latency_warmups,data.policy.latency_processes,data.policy.throughput_windows,data.policy.bootstrap_resamples);
let mut checksums = true;
let mut strict_native = true;
let mut automatic_policy = false;
Expand Down Expand Up @@ -566,7 +566,7 @@ fn fmt_jit_speedup(
Some(candidate) if candidate.samples.iter().any(|sample| entries(sample) > 0) => {
fmt(speedup(base, Some(candidate)))
}
Some(_) => "N/A (no native entry)".into(),
Some(_) => "N/A (no qualifying native entry)".into(),
None => "—".into(),
}
}
Expand Down Expand Up @@ -599,6 +599,7 @@ mod tests {
elapsed_ns: b,
checksum: c.into(),
native_entries: Some(1),
native_acquisitions: Some(1),
native_exits: Some(1),
fallback_count: Some(0),
retry_count: Some(0),
Expand Down Expand Up @@ -749,7 +750,7 @@ mod tests {
}
assert_eq!(
fmt_jit_speedup(&base, Some(&fallback), |s| s.native_entries.unwrap_or(0)),
"N/A (no native entry)"
"N/A (no qualifying native entry)"
);
fallback.samples[0].native_entries = Some(1);
assert_eq!(
Expand Down
Loading
Loading