Skip to content

Performance pass: nanobench migration, measured optimizations, wider gates#18

Merged
NiceAndPeter merged 3 commits into
mainfrom
perf-pass
Jul 19, 2026
Merged

Performance pass: nanobench migration, measured optimizations, wider gates#18
NiceAndPeter merged 3 commits into
mainfrom
perf-pass

Conversation

@NiceAndPeter

Copy link
Copy Markdown
Owner

Performance assessment + optimization pass. Full plan context: replace ctrack, document current state with generated tables, land only measured wins, widen the CI perf gates.

Benchmarking: ctrack → nanobench

  • One table per operation, native implementation first — the relative column reads directly as the bound-vs-native ratio. Hardware counters (ins/cyc/branch-miss) when the kernel allows.
  • Constant memory (drops ctrack's print-and-clear workaround for ~30 GB RSS), 12 s full run, cycling input pools instead of foldable constant operands.
  • New coverage: cross-grid assignment, comparison, casts, dot, ++, /=, store-from-double vs store-from-fraction.
  • perf_report target regenerates the committed docs/performance.md (same pattern as accuracy_report).

Measured optimizations (ins/op exact; ns on the bench host)

target before after
++/-- (new point-bound += fast branch) 76.8 ns / 1255 ins 9.3 ns / 135 ins
transform(v += 1_b) per element 100 ns / 1592 ins 5.9 ns / 102 ins
same-notch index comparison (new value-index arm) 75.9 ns / 1104 ins 11.7 ns / 225 ins
Q8.8 store from double (abs_fractioncountr_zero) 2532 ins 1266 ins
math::abs / math::floor 1696 / 1867 ins 1048 / 1219 ins
fp add/mul (skip provably-dead snap_double) accuracy tables regenerate bit-identical

Honest non-wins, handled per the plan's revert rule: the to_fixed constexpr bindings measured neutral at GCC -O3 (kept — guarantees the fold on MSVC/debug, matches the existing sqrt2_w pattern); the /= outer-zero-check removal was reverted (it carries the compound-form report semantics; caught by test_compound_assign). The related assign_op_result nullopt guard stays as a robustness fix for non-throwing handlers.

Wider CI gates

  • perf_workload now has 5 key-selectable deterministic workloads: integer_qformat (existing), integer_mul, qformat_div, cross_grid_assign, checked_add; the CI cachegrind step loops all keys. New keys bootstrap their baselines on this run (gcc-14 artifact flow, as with the original key) — review and commit the uploaded perf-baseline artifact to arm them.
  • Codegen guard additionally asserts bnd_perf_mul_fast (four-quadrant integer multiply) is call-free at -O2.

Docs

Generated docs/performance.md committed; README §Performance reduced to headline ratios + link; docs/fixed-point.md's stale (contradictory) table removed.

Verification

429/429 ctest (unit, examples, compile-fail, amalgamate, codegen) · 418/418 under BND_MATH_FIXED · fuzz clean on three seeds (~340 M property checks) · docs/accuracy.md regenerates bit-identical after the fp/cmath changes · clang-tidy clean under the CI filter · amalgamation regenerated.

🤖 Generated with Claude Code

Peter Neiss and others added 3 commits July 19, 2026 09:44
…gates

Benchmarking: replace ctrack with ankerl::nanobench (v4.3.11). One table
per operation with the native implementation as first row, so the relative
column reads directly as the bound-vs-native ratio; hardware perf counters
(instructions/cycles/branch misses); constant memory (no print-and-clear
workaround); cycling input pools instead of constant operands (which let
both sides fold). New coverage: cross-grid assignment, comparison, casts,
dot, ++, /=, store-from-double vs -fraction. `bench <md> [<json>]` writes
the report; the perf_report target regenerates the committed
docs/performance.md (same pattern as accuracy_report).

Optimizations (measured before/after with the new bench, ins/op exact):
- operator+= gets a point-bound fast branch: a just<v>/1_b rhs whose value
  is a whole number of notches adds a compile-time raw delta (encoding
  cancels every Lower term). ++/--: 76.8 -> 9.3 ns, 1255 -> 135 ins (8.3x);
  transform(v += 1_b): 100 -> 5.9 ns/elem (17x).
- comparison: new integer value-index arm for same-notch integer-backed
  operands (compile-time bias + raw): 75.9 -> 11.7 ns, 1104 -> 225 ins.
- abs_fraction: countr_zero shift instead of the per-bit strip loop —
  Q8.8 store from double halves (2532 -> 1266 ins); math::abs/floor ~1.6x.
- fp add/mul skip the provably-dead snap_double (results are exact by
  construction under the double/float-exact gate) — docs/accuracy.md
  regenerates bit-identical.
- to_fixed constants in sin/exp/log bound as constexpr locals (neutral at
  GCC -O3, guarantees the fold on MSVC/debug; matches the sqrt2_w pattern).
- assign_op_result: nullopt from a reported failure leaves the value
  unchanged instead of dereferencing (robust under non-throwing handlers).
  The /= outer zero check stays: it carries the compound-form report
  semantics (binary / uses the nullopt vocabulary) and measured neutral.

Gates: perf_workload gains key-selectable workloads (integer_qformat,
integer_mul, qformat_div, cross_grid_assign, checked_add); check_perf.py
passes the key to the binary; CI loops all keys (new baselines bootstrap
on CI's gcc-14 via the existing arm-the-gate artifact flow). Codegen guard
additionally asserts bnd_perf_mul_fast is call-free.

Docs: generated docs/performance.md committed; README performance section
reduced to headline ratios + link; stale fixed-point.md table removed.

Verified: 429/429 ctest, 418/418 under BND_MATH_FIXED, fuzz clean on three
seeds (~340M checks), accuracy tables bit-identical, codegen guard green,
amalgamation regenerated, clang-tidy clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AppleClang/libc++ does not provide <algorithm> transitively where
libstdc++ does; abs_fraction's shared-factor shift now uses a ternary
instead of pulling a new include into the core header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous commit's amalgamation accidentally swept in local
work-in-progress from detail/addition.hpp and detail/assignment.hpp
that is not part of this PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@NiceAndPeter
NiceAndPeter merged commit fe19691 into main Jul 19, 2026
21 checks passed
@NiceAndPeter
NiceAndPeter deleted the perf-pass branch July 19, 2026 18:13
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