# PHASE ML2: 外部LLM回答(Front FastLane / Layer Collapse) ## 0. 位置づけ - 本ドキュメントは、`PHASE_ML2_CHATGPT_QUESTIONNAIRE_FASTLANE.md` への外部レビュー回答を記録する。 - 次フェーズの設計/実装は、本回答を踏まえつつ **hakmem 側の既存 Box/ENV/命名**に合わせて落とし込む。 ## 1. 外部回答の要点(抜粋) ### Q1: 優先順位 1. **A) Front FastLane(front層の 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 の 50–65%**が現実的。 - **70%+**を狙うなら、Front の collapse(A)に加えて、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 FastLane(front層の 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/配置差に負ける)。 * **Q5(mimallocに追いつく現実ライン)** * wrapper→gate→policy→route→handler を “階層のまま”維持すると、上限は概ね **mimallocの50–65%** が現実的(あなたの現状 0.4台→0.5台を狙うのは十分射程)。 * **70%+** を狙うには、少なくとも 1. front層の collapse(A)に加えて、 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 1(allocのみ fastlane、対象クラス限定)** * `hak_fastlane_try_alloc()` を実装(size→class→route の collapse)。 * まずは **“Tiny内で完結するクラスだけ”** に限定(class_maskで制御)。 * fail は必ず `hak_cold_alloc_fallback()` に落とす(境界1箇所)。 **Phase 2(freeも fastlane、ただし Fail-fast 強め)** * `hak_fastlane_try_free()` 実装。 * “判定が曖昧”なものは全部 fallback(性能より安全優先で開始)。 ### 4.3 A/B コマンド(Mixed 10-run) repo に **cleanenv 10-run** スクリプトがあるので、それを基準にします。 **A: FastLane OFF(baseline)** ```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%** → freeze(research箱として保持) * **NO-GO**: mean **-1.0% 以下** → rollbackして freeze > 分岐形だけの調整で -1.71% を踏んだ例があるので、「branch-miss率が下がった」だけでは GO にしない(branch数/コードサイズ増の方が効く)。 --- ## 5. リスクと対策(戻せる手段込み) ### リスク1:FastLaneが “二重分岐” を生み、コードが太って逆効果 * **症状**: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環境汚染を排除。 ### リスク3:Fail-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等の思想があるなら同型で) ### リスク4:FastLaneだけで目標(mimalloc 50%)に届かない * **現実**:Aは「全呼び出しの固定費」を下げるが、mimalloc差の大きな部分が “ptr→meta” なら A単独では頭打ち。 * **対策(ロードマップ)**: * Phase ML2(A)で 0.5台に入らない場合、次の章は **B(ptr→meta O(1) を mid/pool に波及)** を本線にする。 * Aで FastLane を作っておくと、B/Cの導入点(入口)が固定され、以後の実験がやりやすい(境界の一本化=勝ち筋)。 --- 作成日: 2025-12-14 記録者: Task agent