ReviewOS

zig-utils/zig-gc

Perf: tune the nursery floor from object-churn evidence

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

Consumer benchmark: zig-utils/zig-js#62 Follow-up to zig-utils/zig-js#79.

Problem

zig-js bounded object_churn allocates millions of short-lived ordinary objects with only a 256-object live ring. Survivors promoted per minor cycle are far below Heap.min_nursery_threshold_bytes, so nextNurseryThreshold repeatedly clamps to the fixed 4 MiB floor. The profile remains dominated by collectYoung / sweepPhaseLocked / backing frees.

Experiment

  • compare the current 4 MiB floor/default with an 8 MiB floor/default in the generic collector;
  • keep all adaptive growth/decay, promotion accounting, young-prefix bounds, remembered edges, and full-collection behavior unchanged;
  • use an untouched current zig-js main runner versus a runner rebuilt only against the candidate zig-gc;
  • run seven alternating process pairs, three timed object_churn samples each, with exact checksum validation;
  • inspect nursery telemetry and run focused zig-gc nursery tests before any full suite.

Acceptance

  • meaningful and consistent direct object_churn reduction, not a single noisy sample;
  • exact checksums across all A/B samples;
  • adaptive nursery tests updated to express the selected floor rather than hiding drift;
  • zig-gc full tests and zig-js focused GC/harness tests pass before landing;
  • reject and fully revert if fewer cycles merely trade into worse per-cycle latency or memory behavior.
9 days ago

Rejected after two-sided alternating A/B through zig-js object_churn; no code retained.

Baseline was the untouched 97bff723 runner with the current 4 MiB nursery floor. Each candidate rebuilt only against this zig-gc constant change. Seven alternating process pairs used three samples/process and preserved checksum 1030552128 in all 42 samples per variant.

  • 8 MiB floor/default: 0/7 pair wins; all-sample and median-of-process-medians 230.937416 -> 244.108875 ms (+5.70% time).
  • 2 MiB floor/default: 0/7 pair wins; median-of-process-medians 224.973958 -> 264.624209 ms (+17.62% time).

The 4 MiB floor is therefore locally optimal for this bounded high-churn workload: a larger young working set costs more than fewer boundaries save, while doubling boundary frequency is substantially worse. The zig-gc tree is fully reverted and clean. Future improvements must reduce per-cell sweep/free work rather than globally retune cycle frequency.

Sign in to comment on this issue.