Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
12 KiB
12 KiB
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
// 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
// 現在 (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
// 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
- LEARN モード: 剰余・分岐・カウンタ削除 → -18-35 cycles
- FROZEN/CANARY: 変化なし(既に最適)
- 学習精度: 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
- Perfect Hashing: サイズクラス数が既知(L2.5: 5クラス、Tiny: 8クラス)
- Cache-line Alignment: Hash table をキャッシュライン(64B)に整列
- 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()の最後に追加: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
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)
# 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)
- P0-1: Atomic 操作削除(30分)
- P0-2: Cached Strategy(1-2時間)
- Benchmark 全シナリオ
- 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 🔥🔥🔥