diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 7f01d9da..89644b32 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -35,13 +35,21 @@ - Phase 6-2: +5.18% - **累積**: ベースラインから約 +16-17% の性能向上 -### Next: TBD(Phase 6 完了、次の芯を検討中) +### Phase 7 FRONT-FASTLANE-FREE-HOTCOLD-ALIGNMENT: FastLane Free Hot/Cold Alignment — ❌ NO-GO / FROZEN -現状の候補(優先順): -1) **Phase 7: FastLane Free Hot/Cold Alignment** - - FastLane free が `free_tiny_fast()`(monolithic)固定で、既存の勝ち箱 `free_tiny_fast_hot()`(Hot/Cold + DUALHOT)が効かない “ねじれ” を解消する。 - - 指示書: `docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md` - - A/B: `HAKMEM_FREE_TINY_FAST_HOTCOLD=0/1`(同一バイナリ) +結果: Mixed 10-run mean **-2.16%** 回帰。Hot/Cold split は wrapper 経由では有効だが、FastLane の超軽量経路では分岐/統計/TLS の固定費が勝ち、monolithic の方が速い。 + +- A/B 結果: `docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_AB_TEST_RESULTS.md` +- 指示書(記録): `docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md` +- 対処: Rollback 済み(FastLane free は `free_tiny_fast()` 維持) + +### Next: Phase 8(次の芯) + +優先候補(GO を狙う小パッチ): +1) **Phase 8: FREE-STATIC-ROUTE ENV cache hardening** + - 症状: `HAKMEM_FREE_STATIC_ROUTE=1` を `bench_profile` で設定しても、プロセス初期の malloc/free で gate が先に 0 をキャッシュしてしまい、D1 が効かないことがある(`[FREE_STATIC_ROUTE] enabled` が出ない/`tiny_route_for_class` が perf に残る)。 + - 狙い: 既存の勝ち箱(Phase 3 D1)を “本当に” 有効化し、free の `tiny_route_for_class()` 固定費を削る。 + - 指示書: `docs/analysis/PHASE8_FREE_STATIC_ROUTE_ENV_CACHE_FIX_1_NEXT_INSTRUCTIONS.md` ## 更新メモ(2025-12-14 Phase 5 E5-3 Analysis - Strategic Pivot) diff --git a/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_AB_TEST_RESULTS.md b/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_AB_TEST_RESULTS.md new file mode 100644 index 00000000..1e907435 --- /dev/null +++ b/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_AB_TEST_RESULTS.md @@ -0,0 +1,220 @@ +# Phase 7: FastLane Free Hot/Cold Alignment A/B テスト結果 + +## 実装概要 + +**目的**: Phase 6 で FastLane free が `free_tiny_fast()`(monolithic)固定になっている不整合を解消し、既存の勝ち箱である `free_tiny_fast_hot()`(Hot/Cold + DUALHOT)を FastLane からも使えるようにする整合性修正。 + +**変更箇所**: `core/box/front_fastlane_box.h`(Phase 6-2 DeDup path) + +**変更内容**: +```c +// 既存(monolithic 固定) +int result = free_tiny_fast(ptr); + +// 変更後(hot/cold alignment) +int result = hak_free_tiny_fast_hotcold_enabled() ? free_tiny_fast_hot(ptr) : free_tiny_fast(ptr); +``` + +## A/B テスト結果(Mixed 10-run clean env) + +### A: hot/cold OFF(monolithic `free_tiny_fast()`) + +``` +HAKMEM_FREE_TINY_FAST_HOTCOLD=0 scripts/run_mixed_10_cleanenv.sh +``` + +| Run | Throughput (ops/s) | +|-----|-------------------| +| 1 | 46,492,972 | +| 2 | 47,132,053 | +| 3 | 46,330,554 | +| 4 | 47,504,224 | +| 5 | 47,520,766 | +| 6 | 47,614,031 | +| 7 | 46,634,189 | +| 8 | 47,837,066 | +| 9 | 46,866,762 | +| 10 | 47,671,133 | + +**統計**: +- **Mean**: 47,160,375 ops/s +- **Median**: 47,318,139 ops/s +- **Stdev**: 544,734 ops/s (1.16%) + +### B: hot/cold ON(`free_tiny_fast_hot()` 使用) + +``` +HAKMEM_FREE_TINY_FAST_HOTCOLD=1 scripts/run_mixed_10_cleanenv.sh +``` + +| Run | Throughput (ops/s) | +|-----|-------------------| +| 1 | 46,415,509 | +| 2 | 46,427,235 | +| 3 | 46,444,216 | +| 4 | 45,939,083 | +| 5 | 46,310,220 | +| 6 | 45,688,278 | +| 7 | 45,986,410 | +| 8 | 46,372,681 | +| 9 | 45,450,960 | +| 10 | 46,378,735 | + +**統計**: +- **Mean**: 46,141,333 ops/s +- **Median**: 46,341,451 ops/s +- **Stdev**: 354,939 ops/s (0.77%) + +### 性能差分 + +- **絶対値**: -1,019,042 ops/s +- **パーセンテージ**: **-2.16%** + +## 判定 + +**NO-GO (-1.0% 以下の回帰)** + +FastLane free 経路で hot/cold split(`free_tiny_fast_hot()`)を使用すると、**-2.16%** の回帰が発生。 + +## 健康診断結果 + +``` +scripts/verify_health_profiles.sh +``` + +- **MIXED_TINYV3_C7_SAFE**: 46,760,625 ops/s (正常) +- **C6_HEAVY_LEGACY_POOLV1**: 21,800,899 ops/s (正常) + +健康診断は両プロファイルとも正常に動作。 + +## 原因分析 + +### 1. Hot/Cold split のオーバーヘッド + +`free_tiny_fast_hot()` は以下の追加オーバーヘッドを含む: + +1. **統計カウンタ**: `FREE_TINY_FAST_HOTCOLD_STAT_INC()` マクロ(複数箇所) +2. **Cold path への分岐**: `free_tiny_fast_cold()` へのコールオーバーヘッド +3. **TLS アクセス**: 統計カウンタ用の TLS 変数アクセス + +### 2. FastLane DeDup 経路の特性 + +Phase 6 の FastLane free DeDup 経路は: + +- **ヘッダ検証を 1 回だけ実施**(FastLane 内で完結) +- **最小限の分岐**で高速化を狙う設計 +- **monolithic `free_tiny_fast()` の方が I-cache locality が良好** + +Hot/Cold split は wrapper 経路(複数分岐あり)では有効だが、FastLane の超軽量経路では逆効果。 + +### 3. DUALHOT との整合性問題 + +指示書では「既存の勝ち箱を FastLane に通す」とあるが、実際には: + +- **wrapper 経路**: 複数分岐 → hot/cold split で I-cache 改善 → 勝ち +- **FastLane 経路**: 単一分岐 → hot/cold split で I-cache 悪化 → 負け + +環境の違いにより、同じ最適化が逆効果になるケース。 + +## 次のステップ + +### Option 1: Rollback(推奨) + +`HAKMEM_FREE_TINY_FAST_HOTCOLD=0` をデフォルトに戻す。 + +- FastLane free は monolithic `free_tiny_fast()` のまま(Phase 6 の勝ち筋維持) +- wrapper 経由の free は引き続き hot/cold split 可能(環境変数で切り替え) + +### Option 2: 条件付き hot/cold split + +FastLane 経路では強制的に monolithic を使い、wrapper 経由の場合のみ hot/cold split を有効化: + +```c +// FastLane 経路では常に monolithic(統計オーバーヘッド回避) +int result = free_tiny_fast(ptr); +``` + +wrapper 側: +```c +// wrapper 経由では hot/cold split 可能 +if (hak_free_tiny_fast_hotcold_enabled()) { + return free_tiny_fast_hot(ptr); +} else { + return free_tiny_fast(ptr); +} +``` + +### Option 3: 研究継続(FastLane 専用 hot/cold) + +FastLane 専用の軽量 hot/cold split を設計: + +- 統計カウンタを削除(DEBUG ビルドのみ) +- cold path を inline 化して分岐コストを最小化 +- DUALHOT 最適化のみを適用(C0-C3 直接 legacy fallback) + +ただし、追加研究コストに見合う効果が出るかは不明。 + +## Rollback 手順 + +現在の実装を Phase 6 の状態に戻す: + +```c +// core/box/front_fastlane_box.h(Phase 6-2 DeDup path) +// 変更前に戻す +int result = free_tiny_fast(ptr); +``` + +再ビルド: +```sh +make clean && make bench_random_mixed_hakmem +``` + +確認: +```sh +HAKMEM_FREE_TINY_FAST_HOTCOLD=0 scripts/run_mixed_10_cleanenv.sh +``` + +## Rollback 実施 + +`front_fastlane_box.h` を Phase 6 の状態に戻しました: + +```c +// Phase 6-2: DeDup path (eliminate duplicate header validation) +// Conditions: +// 1. Free DeDup enabled (ENV=1) +// 2. All classes enabled (mask=0xFF, no gradual rollout) +if (__builtin_expect(front_fastlane_free_dedup_enabled() && front_fastlane_class_mask() == 0xFF, 1)) { + // Direct call to free_tiny_fast() (handles all validation internally) + // free_tiny_fast() is static inline in malloc_tiny_fast.h, no extern needed + int result = free_tiny_fast(ptr); + if (__builtin_expect(result, 1)) { + FRONT_FASTLANE_STAT_INC(free_hit); + return true; // Handled + } + // Not handled → fallback + FRONT_FASTLANE_STAT_INC(free_fallback_failure); + return false; +} +``` + +**確認テスト**: +```sh +./bench_random_mixed_hakmem 20000000 400 5 +# Throughput = 47.9M ops/s (正常) +``` + +## 結論 + +Phase 7 の FastLane free hot/cold alignment は **-2.16% の回帰(NO-GO)** が発生し、Rollback を実施。 + +**原因**: FastLane の超軽量経路(DeDup)では、hot/cold split の統計カウンタと分岐オーバーヘッドが逆効果。wrapper 経由の複雑経路では有効な最適化だが、FastLane の単純経路では monolithic の方が高速。 + +**推奨**: Phase 6 の勝ち筋(monolithic `free_tiny_fast()`)を維持。wrapper 経由は引き続き hot/cold split 可能(環境変数制御)。 + +**教訓**: 同じ最適化でも、経路の複雑さ(分岐数、I-cache locality)により効果が逆転するケースがある。FastLane は「最小限の分岐」が勝ちパターン。 + +**整合性問題への対処**: +- 当初の狙い「wrapper と FastLane の整合性」は、性能回帰により見送り +- FastLane と wrapper は異なる最適化戦略を持つ独立した経路として扱う +- wrapper: 複雑経路 → hot/cold split で I-cache 改善 +- FastLane: 単純経路 → monolithic で分岐最小化 diff --git a/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md b/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md index ca2a8411..d0632fd8 100644 --- a/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md +++ b/docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_NEXT_INSTRUCTIONS.md @@ -1,5 +1,14 @@ # Phase 7: FastLane Free Hot/Cold Alignment(次の指示書) +## Status(2025-12-14) + +**❌ NO-GO / FROZEN**(Mixed 10-run mean **-2.16%** 回帰、Rollback 実施済み) + +- A/B 結果: `docs/analysis/PHASE7_FRONT_FASTLANE_FREE_HOTCOLD_1_AB_TEST_RESULTS.md` +- 結論: FastLane free は monolithic `free_tiny_fast()` を維持し、wrapper 経由は引き続き `HAKMEM_FREE_TINY_FAST_HOTCOLD=1` で hot/cold を使う(経路ごとに最適化戦略を分ける)。 + +このドキュメントは「試した設計の記録」として保持する(再挑戦するなら FastLane 専用の statsless/hintless hot/cold を別箱で設計し直す)。 + ## 0. 目的(狙い) Phase 6 で FastLane(default ON)+ Free DeDup(default ON)まで本線化できた。次は **FastLane free が `free_tiny_fast()`(monolithic)固定になっている不整合**を解消し、既存の勝ち箱である **`free_tiny_fast_hot()`(Hot/Cold + DUALHOT)** を FastLane からも使えるようにする。 @@ -96,4 +105,3 @@ scripts/verify_health_profiles.sh - さらに戻すなら - `HAKMEM_FRONT_FASTLANE_FREE_DEDUP=0` - `HAKMEM_FRONT_FASTLANE=0` - diff --git a/docs/analysis/PHASE8_FREE_STATIC_ROUTE_ENV_CACHE_FIX_1_NEXT_INSTRUCTIONS.md b/docs/analysis/PHASE8_FREE_STATIC_ROUTE_ENV_CACHE_FIX_1_NEXT_INSTRUCTIONS.md new file mode 100644 index 00000000..6a9c4231 --- /dev/null +++ b/docs/analysis/PHASE8_FREE_STATIC_ROUTE_ENV_CACHE_FIX_1_NEXT_INSTRUCTIONS.md @@ -0,0 +1,105 @@ +# Phase 8: FREE-STATIC-ROUTE ENV cache hardening(次の指示書) + +## 0. 目的(狙い) + +Phase 3 D1(`HAKMEM_FREE_STATIC_ROUTE=1`)は「`tiny_route_for_class()` の固定費を消す」勝ち箱だが、**プロセス初期の malloc/free(main 前)で ENV gate が先に 0 をキャッシュ**すると、`bench_profile` が後から `putenv()` で `HAKMEM_FREE_STATIC_ROUTE=1` を設定しても D1 が効かないことがある。 + +この Phase は **“既に採用している最適化が確実に効く状態” を作る**(= 本線品質)ことが目的。 + +## 1. 症状(観測) + +- `core/bench_profile.h` は `HAKMEM_FREE_STATIC_ROUTE=1` をセットしているのに、実行ログに `[FREE_STATIC_ROUTE] enabled` が出ないことがある。 +- perf で `tiny_route_for_class` が残る(例: self ~2–3%)。 + +## 2. 根本原因 + +`core/box/tiny_free_route_cache_env_box.h` の gate が **“ENV 未設定 → 即 0 を確定”**してしまうため。 + +- `bench_profile` の `putenv()` より前に `tiny_free_static_route_enabled()` が 1 回でも呼ばれると、 + - `g_free_static_route_enabled = 0` が確定し、以後 `getenv()` を見ない。 +- その後 `bench_profile` が `HAKMEM_FREE_STATIC_ROUTE=1` を設定しても、hot path は OFF のまま。 + +(同型の問題を避けるため、`HAKMEM_TINY_ALLOC_DUALHOT` や `HAKMEM_FREE_TINY_FAST_HOTCOLD` は “probe window” を持っている。) + +## 3. 方針(Box Theory) + +### 箱 + +- L0: `FreeStaticRouteEnvGateBox`(この Phase) + - 「ENV を読む/キャッシュする」をここに閉じ込める + - `bench_profile` から **refresh** できるようにする(戻せる/同期できる) + +### 境界 + +- `tiny_free_static_route_enabled()` は **hot inline** のまま維持 +- `bench_profile` から `*_refresh_from_env()` を 1 回だけ呼べるようにする(変換点 1 箇所) + +## 4. 実装指示(小パッチ順) + +### Patch 1: ENV gate を “refresh 可能” にする(推奨) + +対象: `core/box/tiny_free_route_cache_env_box.h` + +やること: +- header 内 `static int g_free_static_route_enabled` を廃止し、**単一のグローバル状態**に寄せる + - `extern _Atomic int g_free_static_route_enabled;`(-1/0/1) +- `tiny_free_static_route_refresh_from_env()` を追加 + - `g_free_static_route_enabled = -1` に戻して次回 `getenv()` させる(Fail-Fast: “確信がないなら読み直す”) + - 可能なら refresh 内で `getenv()` して 0/1 を確定してもよい(どちらでも OK、ただし hot path に影響させない) + +新規: `core/box/tiny_free_route_cache_env_box.c` +- `g_free_static_route_enabled` の定義と refresh 実装 + +### Patch 2: bench_profile の “ENV 反映” に組み込む + +対象: `core/bench_profile.h` + +`bench_apply_profile()` の `bench_setenv_default()` 群の後にある refresh 群に追加: +- `tiny_free_static_route_refresh_from_env();` + +目的: +- `putenv()` で設定した値が gate に確実に反映される(main 前のキャッシュ事故を無効化) + +### Patch 3: 可視化(最小) + +- `[FREE_STATIC_ROUTE] enabled` は “1回だけ” 出るように維持(多重出力は避ける) +- 追加カウンタを増やさない(必要なら 1 個だけ) + +## 5. A/B(同一バイナリ) + +### Mixed 10-run(clean env) + +Baseline: +```sh +HAKMEM_FREE_STATIC_ROUTE=0 scripts/run_mixed_10_cleanenv.sh +``` + +Optimized: +```sh +HAKMEM_FREE_STATIC_ROUTE=1 scripts/run_mixed_10_cleanenv.sh +``` + +判定(Mixed 10-run mean): +- GO: **+1.0% 以上** +- NEUTRAL: **±1.0%** +- NO-GO: **-1.0% 以下** + +追加チェック(必須): +- `HAKMEM_FREE_STATIC_ROUTE=1` で `[FREE_STATIC_ROUTE] enabled` が出ること + +### perf(任意) + +期待: +- `tiny_route_for_class` が top から落ちる/低下する + +## 6. 健康診断(必須) + +```sh +scripts/verify_health_profiles.sh +``` + +## 7. Rollback + +- `HAKMEM_FREE_STATIC_ROUTE=0` +- もしくは Patch 1/2 を revert +