12 KiB
PHASE ML2: 外部LLM回答(Front FastLane / Layer Collapse)
0. 位置づけ
- 本ドキュメントは、
PHASE_ML2_CHATGPT_QUESTIONNAIRE_FASTLANE.mdへの外部レビュー回答を記録する。 - 次フェーズの設計/実装は、本回答を踏まえつつ hakmem 側の既存 Box/ENV/命名に合わせて落とし込む。
1. 外部回答の要点(抜粋)
Q1: 優先順位
- A) Front FastLane(front層の Layer Collapse)
- B) ptr→meta O(1) を mid/pool に波及(segment/mask)
- 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%+ を狙うには、少なくとも
- front層の collapse(A)に加えて、
- 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。
// 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箱)。
// 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へ落ちる “唯一の穴”。
// 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)
HAKMEM_FRONT_FASTLANE=0 scripts/run_mixed_10_cleanenv.sh
B: FastLane ON
HAKMEM_FRONT_FASTLANE=1 scripts/run_mixed_10_cleanenv.sh
任意(perf stat:差分が出たら原因を見る)
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) で断定できるときだけ
- alloc:
- fallback 条件は広く:
- “確信が持てないものは全部”
hak_cold_free_fallback()
- “確信が持てないものは全部”
- 不変条件(最小):
- debugビルドのみ
assert(class_idx == page_meta->class_idx)等 - releaseは “ワンショットログ + disable gate”(既にmadvise guard等の思想があるなら同型で)
- debugビルドのみ
- fast path に入れる条件は最小:
リスク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