# Phase 42 — Runtime-first(perf → asm)最適化手順 Phase 40/41 の教訓: - **asm に存在する ≠ 実行される**(dead code でも callsite は残り得る) - “gate 定数化/削除” は **layout tax** で符号反転する Phase 42 は手順を固定して、**実行されている hot spot だけ**を触る。 --- ## 目的 FAST build(`make perf_fast`)の Mixed で、実行中の固定税(gate/branch/indirection)を削って **+0.5% 以上**を狙う。 判定(build-level / FAST): - **GO**: +0.5% 以上(Mixed 10-run mean) - **NEUTRAL**: ±0.5% - **NO-GO**: -0.5% 以下(revert) ※ **layout リスクが高い変更**(関数の大きな再配置、広範囲の `#if` 追加、dead code 除去など)は閾値を **+1.0%** に引き上げる。 --- ## Step 0: ベースライン固定(必須) 1) `make perf_fast` を 1回回して baseline(FAST)を記録。 2) baseline を `docs/analysis/PHASE42_RUNTIME_FIRST_METHOD_RESULTS.md` に貼る(まずは baseline だけ)。 --- ## Step 1: Runtime profiling(実行中の Top を確定) 目的: 「実行されていない最適化」を踏まない。 1) perf record(FAST binary) ```sh perf record -F 99 -g -- ./bench_random_mixed_hakmem_minimal 20000000 400 1 ``` 2) perf report(実行されている上位だけを見る) ```sh perf report --no-children | head -120 ``` ルール: - **Top 50 に入っていないものは触らない** - gate の候補は「関数名」で perf 上位に出たものだけ(例: `*_enabled`, `*_mode`, `*_snapshot`) --- ## Step 2: asm inspection(Top 50 の候補だけ) 目的: “既に最適化されている/呼び出しが消えている” を避ける。 ```sh objdump -d ./bench_random_mixed_hakmem_minimal | rg -n "|call.*" -n ``` 判定: - **asm で branch/call が見える** → Step 3 へ - **asm に出ない**(inlined/消滅)→ skip(触らない) --- ## Step 3: 最小パッチで “呼び出し回数” を減らす(優先) いきなり gate を定数化しない。まず “呼び出さない形” にする。 典型: - 悪い: `if (gate() && cheap_pred) ...`(常に gate が呼ばれる) - 良い: `if (cheap_pred && gate()) ...`(cheap で弾けるなら gate を呼ばない) これは layout 変化が小さく、勝ちやすい。 --- ## Step 4: 最後の手段として定数化(BENCH_MINIMAL 限定) 条件: - Step 1 で “実行されている” - Step 2 で asm に branch/call が残っている - Step 3 で削れない(cheap_pred が無い) 実装: - `#if HAKMEM_BENCH_MINIMAL` の中だけで return constant(Standard/OBSERVE は無傷) --- ## Step 5: A/B(FAST 10-run) 必ずこれを正として使う: - `make perf_fast` 結果(mean/median)を `docs/analysis/PHASE42_RUNTIME_FIRST_METHOD_RESULTS.md` に追記して確定判定。