Align the icount marker's format string and re-record the Hexagon baselines - #52
Merged
Merged
Conversation
…elines The family migration's renames changed the length of exception-message literals, .rodata shifted, and each workload's *_ICOUNT_DONE format string landed at an alignment where static musl's memcpy (printf copies the format's literal runs with it) takes a shorter path: every Hexagon count fell by 47-87 instructions with every shipped function identical, and the committed baselines were left high by those amounts (PLAN.md section 7). A sweep of one-byte .rodata shifts (0-13 bytes injected ahead of the workload's literals with -include) reproduces the dependence with period 4 on the unaligned string and shows a 64-byte-aligned format string invariant at every shift, so the three workload mains now print through an alignas(64) constexpr format string. The variant that also gave stdout an aligned static buffer was rejected: the extra statics in main flipped GCC's inlining of run<float>() on the Arm legs and moved bridge's float counts by 0.3-0.6 % with no change to the measured code (recorded in async/docs/PERFORMANCE.md as a finding). Measured locally on toolchains that match the committed baselines to the instruction (the unchanged tree counts +0 on every target): M33 and M55 exact (+0) on all 34 workloads; Hexagon async pipelines -95, kernels +7/+7/+38, bridge -211 (Q15/Q31) and -242 (float). Hexagon baselines re-recorded with icount.py --update; the engine README tables regenerated; the book's quoted snippet and the plans' records updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015VR1VC4SDGxHZQQsQvPBaA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The first code follow-up
PLAN.mdstep 5 lists after the migration (async/PLAN.md§4 item 6): the three icount workload mains print their*_ICOUNT_DONEline through analignas(64)constexpr format string, and the Hexagon baselines of both engines are re-recorded. The engine README tables are regenerated from the baselines, the book's quoted snippet is updated, and the family plan,async/PLAN.md,bridge/PLAN.md§7 andasync/docs/PERFORMANCE.mdrecord the measurement. Harness only: no shipped code changes.Why
The migration's renames changed the length of exception-message literals,
.rodatashifted, and each workload's format string landed at an alignment where static musl'smemcpy(whichprintfuses for the format's literal runs) takes a shorter path. Every Hexagon count fell by 47–87 instructions with every shipped function counting identically (the migration's per-function proof,PLAN.md§7), and the committed baselines were left high by those amounts, inside the ±3 % gate. A marker whose cost depends on where the linker put an unrelated literal is noise the exact (--exact) comparisons cannot tolerate.Verification
All measured here, on toolchains that match the committed baselines to the instruction (the unchanged tree counts +0 on every target: Hexagon kernels, M33 and M55 spot checks).
.rodataahead of the workload's literals (-includeof a usedstatic const char[]) moves the unaligned tree's counts with period 4:up_q15_se+7 / −107 / −204 / −47 for shifts 0–3, then repeating at 4–7;pipeline_q15−88 / +34 / 0 / −87 likewise.up_q15_se27,424,077;pipeline_q15204,476,476).icount.py --exactagainst the committed baselines passes on M33 and M55 for all 34 workloads of both engines (+0 each).icount.py --update): async pipelines −95, kernels +7/+7/+38; bridge −211 (Q15/Q31), −242 (float). The CI ratchet on this PR is the first run of the new baselines on the runner image.-Wall -Wextra -Wconversion -Wformat=2 -Werrorbuilds the two workload TUs and the comparison TU (cmp_main.cpp, engine 0);pre-commitclean;mdbook buildclean;update_icount_docs.pyproduces exactly the committed README tables.Notes for the reviewer
stdouta 64-byte-aligned static buffer viasetvbuf. On Hexagon it was equally invariant, but on both Arm legs the two extra statics inmainflipped GCC's decision to inlinerun<float>()(per-function attribution:main29.2 M → 21,run<float>0 → 28.95 M) and movedbridge's float counts by −0.3…−0.6 % on M55 and +0.0005…+0.014 % on M33 with no change to the measured code. The format-only fix leaves the Arm legs at +0. The finding (a harness edit that changesmain's size can move Arm baselines through the workload function's inlining alone; pinningrun<S>()out of line would re-record every baseline) is inasync/docs/PERFORMANCE.mdas deferred.SRT_ICOUNT_DONE/RATIO_ICOUNT_DONEare unchanged (CLAUDE.md).async/PLAN.md§4 item 6, bringingbench/icount/under clang-tidy, is left for its own PR.🤖 Generated with Claude Code
https://claude.ai/code/session_015VR1VC4SDGxHZQQsQvPBaA
Generated by Claude Code