Files
hakmem/PHASE_ML2_CHATGPT_RESPONSE_FASTLANE.md

273 lines
12 KiB
Markdown
Raw Normal View History

# PHASE ML2: 外部LLM回答Front FastLane / Layer Collapse
## 0. 位置づけ
- 本ドキュメントは、`PHASE_ML2_CHATGPT_QUESTIONNAIRE_FASTLANE.md` への外部レビュー回答を記録する。
- 次フェーズの設計/実装は、本回答を踏まえつつ **hakmem 側の既存 Box/ENV/命名**に合わせて落とし込む。
## 1. 外部回答の要点(抜粋)
### Q1: 優先順位
1. **A) Front FastLanefront層の Layer Collapse**
2. **B) ptr→meta O(1) を mid/pool に波及segment/mask**
3. **C) 触るメモリ削減geometry/metadata**
理由: 直近の学び(重複排除/ENV・TLS読み回数削減が勝ち筋、diet/別バイナリ比較は壊れやすい)と整合するため。
### 推奨案: A) Front FastLane の骨子
- wrapper→gate→policy→route を **Hot側で1箱に畳む**
- Cold側へ落ちるのは **単一フォールバック**境界1箇所
- “分岐形”より **分岐数/命令数/断片化**の削減を優先Zen で branch miss は飽和しやすい)
- A/B は **同一バイナリで ENV トグル**(削除/追加で別バイナリ比較にしない)
### GO/NO-GO提案
- Mixed 10-run mean:
- GO: **+1.0% 以上**
- NEUTRAL: **±1.0%**freeze
- NO-GO: **-1.0% 以下**rollback/freeze
### “mimalloc に追いつく”の現実ライン(提案)
- 多層構造wrapper→gate→policy→route→handlerを維持したままだと概ね **mimalloc の 5065%**が現実的。
- **70%+**を狙うなら、Front の collapseAに加えて、free側 ptr→meta を O(1) 化Bがほぼ必須。
## 2. 外部回答(原文)
以下は外部LLMの回答本文チャット貼り付けを、そのまま保持する。
---
はい、いま **hakmem_private** 側の資料は参照できています。少なくともご指定の **`AGENTS.md`Box Theory ルール)**、および Phase5 の A/B の学び別バイナリ比較が壊れる件、Mixed 10-run 手順)を repo から確認できました。
以下、**PHASE ML2 の指定フォーマット**1枚サマリ→Box図→API一覧→A/B手順→リスク対策で返します。
---
## 1. 1枚サマリ
* **Q1優先順位結論**
1位 **A) Front FastLanefront層の Layer Collapse**
2位 **B) ptr→meta O(1) を mid/pool に波及segment/mask**
3位 **C) 触るメモリ削減geometry/metadata**
理由は「ROI/リスク/工数」の積で、いまの学び“境界の冗長排除”が勝ち筋、dietは別バイナリ比較で壊れるに最も整合するのが A。
* **推奨案A: Front FastLaneの狙い**
wrapper→gate→policy→route の “細い箱列” を **Hot側で1箱に畳み**、**Cold側へ落ちるのは単一フォールバック**境界1箇所にする。
“分岐形”改善よりも **分岐数/命令数/コード断片化**を減らす方向Zenでmis予測は飽和しやすいに寄せる。
* **Box Theory 整合**
* 箱=責務分離、境界1箇所、ENVで戻せる、最小可視化、Fail-fast を保持AGENTSの5原則に沿う
* A/B は **同一バイナリでENVトグル**(別バイナリ比較は LTO/配置差に負ける)。
* **Q5mimallocに追いつく現実ライン**
* wrapper→gate→policy→route→handler を “階層のまま”維持すると、上限は概ね **mimallocの5065%** が現実的(あなたの現状 0.4台→0.5台を狙うのは十分射程)。
* **70%+** を狙うには、少なくとも
1. front層の collapseAに加えて、
2. free側 ptr→meta をmid/pool含めO(1) に寄せるB
がほぼ必須“直TLSバケット”に近い世界は meta 到達が勝負なので)。
---
## 2. Box 図ASCII
推奨:**A) Front FastLane**Layer Collapse。「概念上の箱」は維持しつつ、**Hotの入口だけ**を1本化します。
```
(ENV: HAKMEM_FRONT_FASTLANE=0/1)
+----------------+
| L0: EnvGateBox |
+----------------+
|
v
+------------------+ +-------------------------+
| malloc/free shim | --> | L1: FrontFastLaneBox |
| (very thin) | | - size->class->route |
+------------------+ | (1 LUT + 1 LUT) |
| - try alloc/free fast |
| - NO stats/NO learning |
+-------------------------+
| \
success --->| \ fail-fast / unknown
v v
+--------------------------+ +-------------------------+
| L1a: Hot Handlers | | L2: ColdFallbackIface |
| - Tiny/ULTRA/MID hot | | - cold_alloc(size,ci) |
| - per-thread freelists | | - cold_free(ptr) |
+--------------------------+ +-------------------------+
|
v
+-----------------------------+
| L3: Cold/Safe/Observable |
| Superslab/Tier/Guard/Stats |
| Policy/Learner snapshot swap|
+-----------------------------+
```
**“変換点は1箇所”** `FrontFastLaneBox -> ColdFallbackIface`**try→fallback** 接点に集約しますallocもfreeも同じ思想
---
## 3. API 一覧推奨案A
### 3.1 L0: EnvGateBox
目的:**同一バイナリ**で A/B、default OFF。
```c
// core/box/front_fastlane_env_box.h
static inline bool hak_front_fastlane_enabled(void); // ENV: HAKMEM_FRONT_FASTLANE=0/1 (default 0)
static inline uint32_t hak_front_fastlane_class_mask(void); // optional: which classes are handled
```
### 3.2 L1: FrontFastLaneBox入口の collapse
目的wrapper/gate/policy/route を “この箱の内部” に畳む呼び出し側から見ると1箱
```c
// core/box/front_fastlane_box.h
typedef struct HakFastlaneSnapshot {
// “Hot は snapshot を読むだけ”を守る
uint16_t max_fast_size; // e.g. 1024
uint32_t class_mask; // which classes use fastlane
const uint8_t* size_to_class_lut;// pointer to global LUT (no copy)
const uint8_t* class_to_route_lut;// route-kind per class
// optional: pointers to hot handler vtables (avoid re-reading globals)
} HakFastlaneSnapshot;
static inline const HakFastlaneSnapshot* hak_fastlane_snapshot(void);
// returns NULL => must fallback via ColdFallbackIface (single boundary)
static inline void* hak_fastlane_try_alloc(size_t size, const HakFastlaneSnapshot* s);
// returns true => handled; false => must fallback
static inline bool hak_fastlane_try_free(void* p, const HakFastlaneSnapshot* s);
```
### 3.3 L2: ColdFallbackIface境界1箇所
目的HotからColdへ落ちる “唯一の穴”。
```c
// core/box/front_fastlane_cold_iface_box.h
void* hak_cold_alloc_fallback(size_t size, uint32_t class_idx, uint32_t route_kind);
void hak_cold_free_fallback(void* p);
```
> ポイントHot側は「失敗したらこの2関数に落とす」以外の出口を持たない境界1箇所を強制
---
## 4. A/B 手順と閾値
### 4.1 原則(必読の前提の再確認)
* **同一バイナリでENVトグル**が原則(別バイナリ比較は LTO/配置差で壊れる)。
* perf の self% 追跡は有効だが、**頻度と二次効果**を外すとROIを誤る“5%ルール”などの運用指針が repo にある)。
* cleanenv の Mixed 10-run を回すexport済みENVが残ると比較が壊れる。スクリプトが既にある。
### 4.2 Phase 0〜2小パッチ順
**Phase 0完全OFFで導入安全**
* 追加:`front_fastlane_env_box.h` / `front_fastlane_box.h` / `front_fastlane_cold_iface_box.h`
* 既存経路は一切変えず、`if (hak_front_fastlane_enabled())` を wrapper に1箇所だけ置く。
* default: `HAKMEM_FRONT_FASTLANE=0`
**Phase 1allocのみ fastlane、対象クラス限定**
* `hak_fastlane_try_alloc()` を実装size→class→route の collapse
* まずは **“Tiny内で完結するクラスだけ”** に限定class_maskで制御
* fail は必ず `hak_cold_alloc_fallback()` に落とす境界1箇所
**Phase 2freeも fastlane、ただし Fail-fast 強め)**
* `hak_fastlane_try_free()` 実装。
* “判定が曖昧”なものは全部 fallback性能より安全優先で開始
### 4.3 A/B コマンドMixed 10-run
repo に **cleanenv 10-run** スクリプトがあるので、それを基準にします。
**A: FastLane OFFbaseline**
```sh
HAKMEM_FRONT_FASTLANE=0 scripts/run_mixed_10_cleanenv.sh
```
**B: FastLane ON**
```sh
HAKMEM_FRONT_FASTLANE=1 scripts/run_mixed_10_cleanenv.sh
```
**任意perf stat差分が出たら原因を見る**
```sh
HAKMEM_FRONT_FASTLANE=0 perf stat -e cycles,instructions,branches,branch-misses,cache-misses -- \
./bench_random_mixed_hakmem 20000000 400 1
HAKMEM_FRONT_FASTLANE=1 perf stat -e cycles,instructions,branches,branch-misses,cache-misses -- \
./bench_random_mixed_hakmem 20000000 400 1
```
### 4.4 GO/NO-GO 閾値(運用)
repo の運用指針に合わせ、まずは以下を推奨しますPhase5の方針と整合
* **GO**: Mixed 10-run mean **+1.0% 以上**
* **NEUTRAL**: **±1.0%** → freezeresearch箱として保持
* **NO-GO**: mean **-1.0% 以下** → rollbackして freeze
> 分岐形だけの調整で -1.71% を踏んだ例があるので、「branch-miss率が下がった」だけでは GO にしないbranch数/コードサイズ増の方が効く)。
---
## 5. リスクと対策(戻せる手段込み)
### リスク1FastLaneが “二重分岐” を生み、コードが太って逆効果
* **症状**branch-miss率は微改善でも、branch数増・I-cache圧でスループットが落ちる既に同型の罠が観測されている
* **対策**
* FastLane 入口は **「1回だけ if」**。以降は **直線 + switch/jumptable** に寄せる。
* fallback は `__attribute__((cold))`または別TUに追い出し、hot 側に条件分岐を増やさない。
* “snapshot enabled/disabled” みたいな二系統を FastLane 内で抱えないL0で決め打ち
### リスク2別バイナリ比較に引きずられて判断を誤るdiet最適化の罠
* **症状**:箱を削ったら速くなるはずが遅い/速い、が **リンク配置差**で反転。
* **対策**
* “削除”ではなく **同一バイナリ内での無効化**ENV=0を常態化。
* `scripts/run_mixed_10_cleanenv.sh` を基準にし、export環境汚染を排除。
### リスク3Fail-fast 条件が緩く、silent corruption に寄る
* **対策Q3の要求に対応**
* **fast path に入れる条件は最小**
* alloc`size <= snapshot->max_fast_size` かつ `class_mask` に含まれる
* free`ptr` が “自分の管理領域” と O(1) で断定できるときだけ
* **fallback 条件は広く**
* “確信が持てないものは全部” `hak_cold_free_fallback()`
* **不変条件(最小)**
* debugビルドのみ `assert(class_idx == page_meta->class_idx)`
* releaseは “ワンショットログ + disable gate”既にmadvise guard等の思想があるなら同型で
### リスク4FastLaneだけで目標mimalloc 50%)に届かない
* **現実**Aは「全呼び出しの固定費」を下げるが、mimalloc差の大きな部分が “ptr→meta” なら A単独では頭打ち。
* **対策(ロードマップ)**
* Phase ML2Aで 0.5台に入らない場合、次の章は **Bptr→meta O(1) を mid/pool に波及)** を本線にする。
* Aで FastLane を作っておくと、B/Cの導入点入口が固定され、以後の実験がやりやすい境界の一本化勝ち筋
---
作成日: 2025-12-14
記録者: Task agent