Skip to content

Perf-regression: cut sampler hot-path overhead (partial closure of 86aj0hfmc) - #31

Merged
jayakasadev merged 1 commit into
mainfrom
followup/perf-regression-medium-mixed
Jun 11, 2026
Merged

Perf-regression: cut sampler hot-path overhead (partial closure of 86aj0hfmc)#31
jayakasadev merged 1 commit into
mainfrom
followup/perf-regression-medium-mixed

Conversation

@jayakasadev

Copy link
Copy Markdown
Owner

Summary

Two hot-path simplifications in the SNMALLOC_PROFILE=ON path:

  1. Sampler::record_alloc — hoisted sampler_reentered() check out of the fast path into record_alloc_slow. Saves one TLS load + one mispredictable branch per allocation. Slow path detects re-entry on entry and bails without resetting the countdown; sample weighting (rate - bytes_until_sample + requested_size) absorbs the overshoot.

  2. record_dealloc<Config> — reordered so the slab-metadata probe + atomic-slot peek run BEFORE ReentrancyGuard construction. Common case (object never sampled) now skips the TLS store-store-load round-trip.

Results

group ratio_idle (before → after) ratio_active (before → after)
small_allocs 0.9955 → 1.0016 0.9907 → 1.0085
medium_allocs 1.0493 → 1.0128 1.0423 → 1.0037
mixed 1.0276 → 1.0052 1.0387 → 1.0293
max 1.0493 → 1.0128 1.0423 → 1.0293

Status — PARTIAL closure

The literal acceptance band <= 1.01 on all 6 cells is met on 4 of 6. medium/idle (1.28%) and mixed/active (2.93%) remain over target. The harness variance is larger than the residual measurement gap (other back-to-back runs of the same code showed swings to 1.198, 1.252, 1.281 — bimodal under macOS scheduler).

Closing the last <3% gap requires either:

  • Linux performance-core-pinned re-run with taskset + cpufreq=performance, OR
  • Raising sample_size / measurement_time in the bench harness so it resolves sub-1% (harness change — out of scope for this PR)

Both options flagged as follow-up in docs/heap-profiling-benchmarks.md and the ClickUp ticket.

Closes the dominant gap on 86aj0hfmc (max overhead halved). The ticket stays open until Linux pinned re-run lands.

Test plan

  • All func-profile_* tests pass under SNMALLOC_PROFILE=ON and OFF
  • func-profile_overhead-fast ratio on/off = 0.766 (still well under the test's 5% bound)
  • func-profile_e2e, profile_h3_h4, profile_integration, profile_remote_dealloc, profile_streaming all green
  • snmalloc-rs cargo test --features profiling --release (30/30)

…6aj0hfmc)

- src/snmalloc/profile/sampler.h: hoist the per-thread `sampler_reentered()`
  check from `Sampler::record_alloc` into `record_alloc_slow`. The hot
  countdown is now a single TLS decrement plus a signed compare; the
  reentrancy check only runs on the ~1-in-512-KiB fraction of allocations
  that already cost a slow-path transition. Sample weighting unchanged --
  the `rate - hot_.bytes_until_sample + requested_size` formula already
  absorbs the overshoot when the counter ticks negative under re-entry.
- src/snmalloc/profile/record.h: reorder `record_dealloc<Config>` so the
  cheap slab-metadata probe and atomic-slot peek run before the
  `ReentrancyGuard` is constructed. The common-case (object on a slab
  with no installed lazy backing, or slab installed but specific object
  never sampled) now skips the TLS store-store-load round-trip from the
  guard.
- docs/heap-profiling-benchmarks.md: re-publish bench numbers after the
  fix. Idle ratios dropped from a max of 1.0493 to 1.0128 on this host,
  with two of three groups under 1.01. Documented the cross-run bimodal
  variance (20-80% on individual variants between back-to-back runs)
  that prevents this harness on this host from credibly resolving the
  remaining <3% gap on mixed/active.

ClickUp: 86aj0hfmc
@jayakasadev
jayakasadev merged commit 9a30e5d into main Jun 11, 2026
157 of 210 checks passed
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