# HAKMEM アロケータ パフォーマンス分析レポート ## 1. 実行環境 - ベンチマーク: bench_random_mixed (1,000,000 ops, working set=256) - プラットフォーム: Linux x86_64 - perf_event_paranoid: 1 ## 2. パフォーマンス統計比較 ### HAKMEM アロケータ ``` Throughput: 55,705,335 ops/s Time: 0.018s Cycles: 78,648,007 Instructions: 167,028,675 IPC: 2.12 Cache References: 1,861,523 Cache Misses: 172,740 (9.28%) Branches: 35,993,722 Branch Misses: 921,505 (2.56%) ``` ### System malloc (glibc) ``` Throughput: 86,683,664 ops/s (+55.6% faster) Time: 0.012s Cycles: 44,872,364 (-43.0% fewer cycles) Instructions: 93,643,012 (-43.9% fewer instructions) IPC: 2.09 (similar) Cache References: 339,504 (-81.8% fewer) Cache Misses: 45,009 (-73.9% fewer) Branches: 16,572,153 (-53.9% fewer) Branch Misses: 561,229 (-39.1% fewer) ``` ## 3. ホットスポット分析 ### CPU時間消費 (Top Functions) 1. **malloc**: 26.10% (self) / 39.22% (children) 2. **free**: 19.47% (self) / 40.23% (children) 3. **shared_pool_acquire_slab**: 23.83% (children only) 4. **Page fault handling**: 25.55% (kernel time) ### 主要な発見 - **Page faults が顕著**: 25.55% が asm_exc_page_fault 経由 - `shared_pool_acquire_slab` → `__memset_avx2_unaligned_erms` → page fault - `clear_page_erms` が 4.46% を消費 - **memset overhead**: `__memset_avx2_unaligned_erms` が 6.41% - **メモリ管理のオーバーヘッド**: kernel の folio/page 管理が目立つ ## 4. ボトルネック特定 ### 1. shared_pool_acquire_slab() の初期化コスト - **問題**: memset → page fault → kernel page allocation - **影響**: 23.83% の CPU 時間 - **原因**: SuperSlab 獲得時の large memory clear (1MB/2MB) ### 2. 過剰なキャッシュ参照 - **HAKMEM**: 1,861,523 cache refs (system の 5.5倍) - **Cache miss率**: 9.28% (system は 13.26% だがアクセス量が少ない) - **分析**: データ構造のメモリフットプリントが大きい ### 3. 分岐数の多さ - **HAKMEM**: 35,993,722 branches (system の 2.2倍) - **Branch miss率**: 2.56% (system は 3.39%) - **分析**: 複雑な分岐ロジック (Front Gate, domain routing, etc.) ### 4. 命令数の多さ - **HAKMEM**: 167M instructions (system の 1.8倍) - **分析**: 多層的なアロケーション戦略 (Tiny/Mid/ACE/BigCache) ## 5. 最適化提案(優先度順) ### 優先度1: SuperSlab 初期化の遅延化・削減 **問題**: `shared_pool_acquire_slab()` で 23.83% の CPU 時間を消費 - memset による 1MB-2MB のゼロクリア - Page fault による kernel page allocation (clear_page_erms: 4.46%) **提案**: 1. **Lazy Initialization**: メタデータのゼロクリアを遅延化 - mmap(MAP_ANONYMOUS) は既にゼロページを返すため、明示的な memset は不要 - 4つの memset() 呼び出し(lines 912-915)を削除可能 - 推定効果: **10-15% throughput 向上** 2. **On-Demand Page Faulting**: - MADV_DONTNEED または MADV_FREE を活用 - 実際に使用される slab だけ page fault を起こす - 推定効果: **5-10% throughput 向上** 3. **SuperSlab Size 調整**: - 現状: 1MB (lg=20) or 2MB (lg=21) - 提案: 512KB (lg=19) or 256KB (lg=18) をデフォルトに - 推定効果: **初期化コスト 50-75% 削減** **実装箇所**: `/mnt/workdisk/public_share/hakmem/core/hakmem_tiny_superslab.c:912-915` --- ### 優先度2: Front Gate 分岐最適化 **問題**: 35,993,722 branches (system の 2.2倍) - Branch miss率は良好 (2.56%) だが絶対数が多い - malloc/free の多層ルーティング (Tiny/Mid/ACE/BigCache) **提案**: 1. **Fast Path 統合**: - 現状: smallmid → tiny → mid → ACE の順でチェック - 提案: サイズレンジを統合して判定を1回に削減 ```c // Before: 4 separate checks if (smallmid_is_in_range(size)) { ... } if (size <= tiny_get_max_size()) { ... } if (mid_is_in_range(size)) { ... } if (size < threshold) { ... } // After: Single dispatch table void* (*allocator)(size_t) = size_dispatch_table[size >> 8]; return allocator(size); ``` - 推定効果: **5-8% throughput 向上** 2. **Likely/Unlikely Hints 追加**: - `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:43-78` - 使用頻度が高い Tiny path に `__builtin_expect()` - 推定効果: **2-3% throughput 向上** --- ### 優先度3: キャッシュライン最適化 **問題**: 1,861,523 cache refs (system の 5.5倍) - Cache miss率は 9.28% と許容範囲だが、アクセス回数が多すぎる **提案**: 1. **SuperSlab メタデータ構造の再配置**: - Hot fields(freelist, used, capacity)を先頭 64 bytes に集約 - Cold fields(LRU, statistics)を末尾に移動 - `__attribute__((aligned(64)))` でキャッシュライン境界に整列 - 推定効果: **3-5% cache miss 削減** 2. **TLS Hot Slot の積極活用**: - 現状: Stage 0 (L0 reuse) は既に実装済み (lines 802-832) - 提案: L0 hit rate をモニタリングし、閾値調整 - ENV: `HAKMEM_SS_L0_CAPACITY` でキャッシュサイズ拡大 - 推定効果: **Stage 1-3 の呼び出し 20-30% 削減** --- ### 優先度4: インライン化の最適化 **問題**: 167M instructions (system の 1.8倍) - 多層の関数呼び出しによる overhead **提案**: 1. **Critical Path のインライン化**: - `fg_classify_domain()` - 既に static inline? - `hak_tiny_free_fast_v2()` - 既に always_inline 化されている - `smallmid_is_in_range()` / `mid_is_in_range()` を強制インライン - 推定効果: **2-4% call overhead 削減** 2. **LTO (Link Time Optimization) の有効化**: - `-flto -fwhole-program` でコンパイル - クロスモジュールのインライン化が可能に - 推定効果: **5-8% code size 削減、2-3% throughput 向上** --- ### 優先度5: mincore() 呼び出しの削減 **問題**: free() 内の mincore() によるシステムコール overhead - `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h:224-272` - TLS page cache で緩和されているが、まだ overhead がある **提案**: 1. **Registry First Policy**: - mincore() の前に必ず SuperSlab registry を先にチェック - Registry hit ならヘッダー読み取り不要 - 推定効果: **free() の 5-10% を高速化** 2. **Compile-Time Option**: - `HAKMEM_DISABLE_MINCORE_CHECK=1` を production default に - Invalid pointer は極稀なので、クラッシュリスクは許容範囲 - 推定効果: **free() の 10-15% を高速化** --- ## 6. 実測効果の予測 ### 楽観的シナリオ(全提案を実装) | 最適化項目 | 予測効果 | |-----------|---------| | SuperSlab lazy init | +15% | | Front Gate 統合 | +8% | | Cache line 最適化 | +5% | | Inline + LTO | +5% | | mincore 削減 | +8% | | **合計** | **+41%** (複合効果を考慮) | **目標スループット**: 55M → **77M ops/s** (system 86M の 89%) ### 保守的シナリオ(優先度1-2のみ実装) | 最適化項目 | 予測効果 | |-----------|---------| | SuperSlab lazy init | +12% | | Front Gate 統合 | +5% | | **合計** | **+17%** | **目標スループット**: 55M → **65M ops/s** (system 86M の 75%) --- ## 7. 追加分析が必要な項目 ### 7.1 メモリフットプリント - **課題**: Cache refs が 5.5倍 → データ構造サイズが大きい可能性 - **調査**: `sizeof(SuperSlab)`, `sizeof(TinySlabMeta)` の確認 - **ツール**: Valgrind massif, heaptrack ### 7.2 マルチスレッド性能 - **課題**: 現在のベンチマークはシングルスレッド - **調査**: pthread 環境での lock contention - **ツール**: `perf record -e lock:contention_begin` ### 7.3 Workload 別の最適戦略 - **課題**: random_mixed 以外のパターン(sequential, burst, etc.) - **調査**: ELO strategy の adaptive 効果測定 - **ベンチマーク**: bench_comprehensive の全パターン実行 --- ## 8. 次のステップ ### Phase 1: Quick Wins (1-2日) 1. SuperSlab memset 削除 (lines 912-915) 2. HAKMEM_DISABLE_MINCORE_CHECK=1 でビルド・測定 3. Front Gate に `__builtin_expect()` 追加 ### Phase 2: 構造的改善 (1週間) 1. Front Gate dispatch table 実装 2. SuperSlab size を 512KB に変更 3. LTO 有効化 ### Phase 3: 詳細分析 (2週間) 1. Valgrind/heaptrack でメモリプロファイリング 2. マルチスレッドベンチマーク追加 3. Workload 別の最適化 --- ## 9. 参考データ ### ファイルパス - perf データ: `/mnt/workdisk/public_share/hakmem/perf.data` - ホットスポットレポート: `/mnt/workdisk/public_share/hakmem/perf_hakmem_hotspots.txt` - 統計データ: `/mnt/workdisk/public_share/hakmem/perf_hakmem_stats.txt` - コールグラフ: `/mnt/workdisk/public_share/hakmem/perf_hakmem_callgraph.txt` ### 重要なソースファイル - Alloc API: `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h` - Free API: `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h` - SuperSlab: `/mnt/workdisk/public_share/hakmem/core/hakmem_tiny_superslab.c` - Shared Pool: `/mnt/workdisk/public_share/hakmem/core/hakmem_shared_pool.c` --- **レポート生成日**: 2025-11-28 **分析対象**: HAKMEM allocator (commit 0ce20bb83) **ベンチマーク**: bench_random_mixed_hakmem 1000000 256 42