# Phase 6.11.4 Plan: hak_alloc Optimization - mimalloc 完全打倒作戦 **Date**: 2025-10-22 **Goal**: 🎯 **全ての条件で mimalloc を倒す!** **Strategy**: ultrathink (ChatGPT o1) + Gemini 協調分析 --- ## 🎯 **Mission: mimalloc 完全打倒** ### 現状 vs 目標 | Scenario | hakmem (現在) | **目標 (P0-2後)** | mimalloc | **判定** | |----------|---------------|------------------|----------|---------| | **json** (64KB) | 217 ns | **155 ns** | 220 ns | **30% faster** 🔥 | | **mir** (256KB) | 874 ns | **620 ns** | 1,072 ns | **42% faster** 🔥🔥 | | **vm** (2MB) | 13,933 ns | **11,000 ns** | 13,812 ns | **20% faster** 🔥 | **宣言**: ✅ **全シナリオで mimalloc を超える!** --- ## 📊 **問題分析 (Phase 6.11.3 Profiling 結果)** ### ボトルネック発見 ``` HAKMEM Debug Timing Statistics ======================================== syscall_munmap: 131,666 cycles (41.3%) ← #1 既知(Whale で最適化済み) hak_alloc: 126,479 cycles (39.6%) ← #2 新発見! 🔥 **ターゲット** hak_free: 48,206 cycles (15.1%) ======================================== ``` ### hak_alloc 内訳(推定) **ultrathink 分析**: 126,479 cycles の内訳 ``` Atomic 操作: 55-100 cycles (43-79%) ← 最大のボトルネック - atomic_fetch_add: 30-50 cycles - hak_evo_tick (1/1024): 5-10 cycles - hak_elo_select (1/100): 5-10 cycles - 条件分岐・剰余: 5-15 cycles Hash lookup: 15-20 cycles (12-16%) - Site Rules lookup: 10-15 cycles - BigCache lookup: 5-10 cycles その他ロジック: 10-20 cycles (8-16%) - Threshold 判定: 3-5 cycles - Feature flag check: 3-5 cycles - ポインタ計算: 4-10 cycles ``` --- ## 🚀 **Implementation Plan** ### **Phase 6.11.4 (P0-1): Atomic 操作削除** ⭐ **最優先!** #### Goal `HAKMEM_FEATURE_EVOLUTION` 無効時のアトミック操作を**コンパイル時削除** #### Implementation ```c // Before (現在) void* hak_alloc_at(size_t size, hak_callsite_t site) { if (HAK_ENABLED_LEARNING(HAKMEM_FEATURE_EVOLUTION)) { static _Atomic uint64_t tick_counter = 0; if ((atomic_fetch_add(&tick_counter, 1) & 0x3FF) == 0) { hak_evo_tick(now_ns); } } // ... rest ... } // After (改善後) void* hak_alloc_at(size_t size, hak_callsite_t site) { #if HAKMEM_FEATURE_EVOLUTION static _Atomic uint64_t tick_counter = 0; if ((atomic_fetch_add(&tick_counter, 1) & 0x3FF) == 0) { hak_evo_tick(now_ns); } #endif // ... rest ... } ``` #### Expected Results ``` Before: 126,479 cycles After: 96,000 cycles (-30,479 cycles, -24%) vm scenario: 13,933 ns → ~12,500 ns ``` #### Risk Assessment - **Risk**: ✅ **ZERO** (コンパイル時 guard、実行時変化なし) - **Complexity**: ✅ **Very Low** (単純な #if 追加) - **Time**: ✅ **30 minutes** --- ### **Phase 6.11.4 (P0-2): Cached Strategy** ⭐ **高優先!** #### Goal LEARN モードを FROZEN と同じ速度に(アトミックキャッシュ戦略) #### Problem ```c // 現在 (LEARN モード): 100回ごとに重い計算 g_elo_call_count++; if (g_elo_call_count % 100 == 0 || g_cached_strategy_id == -1) { strategy_id = hak_elo_select_strategy(); // 重い (5-10 cycles 平均) g_cached_strategy_id = strategy_id; hak_elo_record_alloc(strategy_id, size, 0); // 重い } else { strategy_id = g_cached_strategy_id; // 99回はキャッシュ読み取り } ``` **オーバーヘッド**: - 剰余計算 (`% 100`): 10-20 cycles - 条件分岐: 5-10 cycles - カウンタインクリメント: 3-5 cycles - **合計**: 18-35 cycles (99回) + 重い計算 (1回) #### Solution: Always Use Cached Strategy ```c // Global cached strategy (atomic) static _Atomic int g_cached_strategy_id = 0; void* hak_alloc_at(size_t size, hak_callsite_t site) { HKM_TIME_START(t0); #if HAKMEM_FEATURE_EVOLUTION // Evolution tick (1/1024) - 変更なし static _Atomic uint64_t tick_counter = 0; if ((atomic_fetch_add(&tick_counter, 1) & 0x3FF) == 0) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); uint64_t now_ns = now.tv_sec * 1000000000ULL + now.tv_nsec; hak_evo_tick(now_ns); // ここで g_cached_strategy_id を更新 } #endif // Strategy selection: すべてのモードで同じ速度! int strategy_id = atomic_load(&g_cached_strategy_id); // 10 cycles のみ size_t threshold = hak_elo_get_threshold(strategy_id); // ... rest of allocation logic ... } // Cold-path: hak_evo_tick で更新 void hak_evo_tick(uint64_t now_ns) { // ... 既存の P2推定、分布更新、状態遷移 ... // NEW: キャッシュされた戦略を更新 int new_strategy = hak_elo_select_strategy(); atomic_store(&g_cached_strategy_id, new_strategy); // 学習データ記録(非同期、ホットパス外) // Note: サイズ情報は hak_evo_record_size で既に記録されている } ``` #### Benefits 1. **LEARN モード**: 剰余・分岐・カウンタ削除 → **-18-35 cycles** 2. **FROZEN/CANARY**: 変化なし(既に最適) 3. **学習精度**: 1-2% 低下(無視できる) #### Expected Results ``` Before (P0-1): 96,000 cycles After (P0-2): 70,000 cycles (-26,000 cycles, -27% additional) vm scenario: ~12,500 ns → ~11,000 ns ``` #### Risk Assessment - **Risk**: ✅ **LOW** (1-2%精度低下、無視できる) - **Complexity**: ✅ **Low** (アトミック変数追加のみ) - **Time**: ✅ **1-2 hours** --- ### **❌ Phase 6.11.5 (P1): Learning Thread - SKIP!** #### Why Skip? **ultrathink 分析**: ロックフリーキューのコストが現在のアトミック操作より高い! ``` 現在のアトミック操作: 30-50 cycles/alloc ロックフリーキュー: 60-110 cycles/alloc ← 2倍遅い! ``` **Gemini の提案は誤り**: - 高頻度アロケーション(10,000+/秒)では、イベントキューのオーバーヘッドが大きい - P0-2 (Cached Strategy) が同等の性能で実装が簡単 **結論**: ✅ **P0-2 で十分、P1 は不要** --- ### **Phase 6.11.6 (P2): Hash Table Optimization** (Optional) #### Goal Site Rules / BigCache の hash lookup 最適化 #### Strategies 1. **Perfect Hashing**: サイズクラス数が既知(L2.5: 5クラス、Tiny: 8クラス) 2. **Cache-line Alignment**: Hash table をキャッシュライン(64B)に整列 3. **Hash Function**: FNV-1a → xxHash or murmur3 #### Expected Results ``` Before (P0-2): 70,000 cycles After (P2): 60,000 cycles (-10,000 cycles, -14% additional) vm scenario: ~11,000 ns → ~10,000 ns ``` #### When to Implement - **Condition**: P0-2 実装後、hak_alloc が依然として >75,000 cycles の場合 - **Priority**: P2(P0-2 が期待通りなら不要) --- ## 📈 **Expected Final Results** ### Phase 6.11.4 (P0-1 + P0-2) 実装後 #### Profiling Results (予測) ``` HAKMEM Debug Timing Statistics ======================================== syscall_munmap: 131,666 cycles (50.2%) ← #1 (比率上昇) hak_alloc: 70,000 cycles (26.7%) ← #2 (-45% 🔥) hak_free: 48,206 cycles (18.4%) whale_get: 3,113 cycles ( 1.2%) whale_put: 3,064 cycles ( 1.2%) ======================================== Total cycles: 262,542 (-18%) ======================================== ``` #### Benchmark Results (予測) | Scenario | hakmem (現在) | **hakmem (P0-2後)** | mimalloc | **勝利!** | |----------|---------------|---------------------|----------|-----------| | **json** (64KB) | 217 ns | **155 ns** | 220 ns | **✅ 30% faster** | | **mir** (256KB) | 874 ns | **620 ns** | 1,072 ns | **✅ 42% faster** | | **vm** (2MB) | 13,933 ns | **11,000 ns** | 13,812 ns | **✅ 20% faster** | **🎉 Mission Accomplished: 全シナリオで mimalloc 打倒!** --- ## 🎯 **Implementation Checklist** ### Phase 6.11.4 (P0-1): Atomic 操作削除 (30分) **ファイル**: `hakmem.c` - [ ] Line 362-368: `if (HAK_ENABLED_LEARNING(...))` → `#if HAKMEM_FEATURE_EVOLUTION` - [ ] 同様の変更を他の `HAK_ENABLED_LEARNING` 箇所にも適用 - [ ] ビルド & テスト - [ ] Profiling 測定(期待: hak_alloc ~96,000 cycles) ### Phase 6.11.4 (P0-2): Cached Strategy (1-2時間) **ファイル**: `hakmem.c`, `hakmem_elo.c`, `hakmem_evo.c` **Step 1: Global cached strategy 追加** - [ ] `static _Atomic int g_cached_strategy_id = 0;` を hakmem.c に追加 - [ ] 初期化: `hak_init()` で `atomic_store(&g_cached_strategy_id, 0);` **Step 2: hak_alloc_at 簡略化** - [ ] Line 375-405 の ELO 選択ロジックを削除 - [ ] 代わりに `int strategy_id = atomic_load(&g_cached_strategy_id);` のみ - [ ] `g_elo_call_count` 関連の削除 **Step 3: hak_evo_tick で更新** - [ ] `hak_evo_tick()` の最後に追加: ```c int new_strategy = hak_elo_select_strategy(); atomic_store(&g_cached_strategy_id, new_strategy); ``` **Step 4: テスト** - [ ] ビルド & テスト - [ ] Profiling 測定(期待: hak_alloc ~70,000 cycles) - [ ] 全シナリオベンチマーク(json/mir/vm) --- ## 📊 **Validation Plan** ### 1. Profiling Validation ```bash HAKMEM_MODE=minimal HAKMEM_TIMING=1 \ ./bench_allocators_hakmem --allocator hakmem-baseline --scenario vm --iterations 10 ``` **Expected**: ``` hak_alloc: ~70,000 cycles (26.7%) ← -45% from 126,479 ``` ### 2. Benchmark Validation (All Scenarios) ```bash # json scenario ./bench_allocators --allocator hakmem-baseline --scenario json --iterations 100 # mir scenario ./bench_allocators --allocator hakmem-baseline --scenario mir --iterations 100 # vm scenario ./bench_allocators --allocator hakmem-baseline --scenario vm --iterations 100 ``` **Expected**: - json: ~155 ns (vs mimalloc 220 ns) ✅ - mir: ~620 ns (vs mimalloc 1,072 ns) ✅ - vm: ~11,000 ns (vs mimalloc 13,812 ns) ✅ ### 3. Regression Test - [ ] すべての既存テストが PASS - [ ] ELO 学習が依然として機能(1-2%精度低下は許容) - [ ] Whale cache hit rate が変化なし --- ## 🎓 **Lessons Learned** ### 1. **Profiling First, Optimize Later** - Phase 6.11.3 で Profiling Infrastructure を作ったからこそ、hak_alloc のボトルネックを発見 - Pre-Warm Pages 失敗を未然に防げた ### 2. **Quantitative Analysis > Intuition** - Gemini の提案(学習スレッド)は直感的には正しそう - でも **ultrathink の定量分析** で、ロックフリーキューが遅いことを発見 - **数値で検証することの重要性** 🔬 ### 3. **Simple Solutions Win** - P0-2 (Cached Strategy) は P1 (Learning Thread) より: - **速い**(60-110 cycles vs 30-50 cycles) - **簡単**(アトミック変数 vs スレッド管理) - **安全**(race condition なし) ### 4. **User の直感は貴重** - "オーバーヘッドどこか見つける仕組み先につくらない?" ← **完全に正しかった** - エンジニアは素直にユーザーの指摘を受け入れるべき --- ## 🚀 **Next Steps** ### Immediate (P0): Implement Phase 6.11.4 (2-3 hours) 1. P0-1: Atomic 操作削除(30分) 2. P0-2: Cached Strategy(1-2時間) 3. Benchmark 全シナリオ 4. **mimalloc 打倒を確認** ✅ ### Short-term (P1): L2.5 Pool Optimization (Phase 6.13) - mir scenario の更なる高速化(620 ns → <500 ns?) - Site Rules の L2.5 routing 強化 ### Medium-term (P2): Hash Table Optimization (Phase 6.11.6) - **Condition**: hak_alloc が >75,000 cycles の場合のみ - Perfect hashing + cache-line alignment --- ## 📚 **References** ### Analysis Documents - **ultrathink**: PHASE_6.11.4_THREADING_COST_ANALYSIS.md (Task Agent 作成) - **Gemini**: 学習スレッド提案(誤り、定量分析で否定) - **Phase 6.11.3**: PHASE_6.11.3_COMPLETION_REPORT.md (Profiling Infrastructure) ### Technical Background - **Atomic Operations**: LOCK CMPXCHG on x86 = 30-50 cycles - **Lock-free Queue**: MPSC queue = 60-110 cycles/op (alloc + atomic) - **mimalloc/jemalloc**: Cached strategy approach を採用 --- **Mission**: 🎯 **全ての条件で mimalloc を倒す!** **Strategy**: P0-1 (Atomic 削除) + P0-2 (Cached Strategy) **Time**: 2-3 hours **Expected**: json -30%, mir -42%, vm -20% **vs mimalloc** 🔥🔥🔥