docs: freeze Phase 7 FastLane free hot/cold; add Phase 8 env cache fix

This commit is contained in:
Moe Charm (CI)
2025-12-14 18:34:08 +09:00
parent 7a3702e069
commit 17aaa90981
4 changed files with 348 additions and 7 deletions

View File

@ -35,13 +35,21 @@
- Phase 6-2: +5.18%
- **累積**: ベースラインから約 +16-17% の性能向上
### Next: TBDPhase 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

View File

@ -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 OFFmonolithic `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.hPhase 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 で分岐最小化

View File

@ -1,5 +1,14 @@
# Phase 7: FastLane Free Hot/Cold Alignment次の指示書
## Status2025-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 で FastLanedefault ON+ Free DeDupdefault 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`

View File

@ -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/freemain 前)で 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 ~23%)。
## 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-runclean 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