# Tiny Pool 3-Layer Architecture Design **日付**: 2025-11-01 **目的**: 6-7層 → 3層への大胆なシンプル化 **根拠**: ChatGPT Pro UltraThink Response + 性能計測 --- ## 📊 現状の問題 ### 計測結果 (Baseline) | Metric | Tiny Hot | Random Mixed | |--------|----------|--------------| | Throughput | 179 M ops/s | 21.6 M ops/s | | Instructions/op | **100** | **412** | | 目標 instructions/op | 20-30 | 100-150 | | 削減率 | **70-80%** | **60-75%** | **問題**: mimalloc (推定 10-20 insns/op) の **5-10倍** のオーバーヘッド --- ## 🏗️ 現在のアーキテクチャ (6-7層) ```c void* hak_tiny_alloc(size_t size) { class_idx = hak_tiny_size_to_class(size); // Layer 1: HAKMEM_TINY_BENCH_FASTPATH (ベンチ専用) #ifdef HAKMEM_TINY_BENCH_FASTPATH if (g_tls_sll_head[class_idx]) return pop_sll(); if (g_tls_mags[class_idx].top > 0) return pop_mag(); #endif // Layer 2: TinyHotMag (class ≤ 2) if (g_hotmag_enable && class_idx <= 2) { if (hotmag_pop()) return p; } // Layer 3: g_hot_alloc_fn (専用関数) if (g_hot_alloc_fn[class_idx]) { switch (class_idx) { case 0: return tiny_hot_pop_class0(); ... } } // Layer 4: tiny_fast_pop (Fast Head SLL) if (tiny_fast_pop()) return p; // Layer 5-7: Slow path (Magazine, Slab, Bitmap, etc.) return hak_tiny_alloc_slow(); } ``` **問題**: 1. ✗ 重複する層 (Layer 1-4 はすべて TLS キャッシュ) 2. ✗ 条件分岐が多すぎる 3. ✗ 関数呼び出しオーバーヘッド 4. ✗ 複数のデータ構造 (sll, hotmag, fast_pop, magazine) --- ## 🎯 新アーキテクチャ (3層) ### Layer 1: TLS Bump Allocator (8B/16B/32B専用) **目的**: 超高速パス、2-3 instructions/op **データ構造**: ```c // Per-class bump allocator (hot classes only: 8B, 16B, 32B) typedef struct { void* bcur; // Current bump pointer void* bend; // Bump end } TinyBump; static __thread TinyBump g_tiny_bump[3]; // class 0, 1, 2 ``` **アロケーション**: ```c static inline void* tiny_bump_alloc_8B(void) { void* old = g_tiny_bump[0].bcur; void* new_cur = (char*)old + 8; if (likely(new_cur <= g_tiny_bump[0].bend)) { g_tiny_bump[0].bcur = new_cur; return old; } return NULL; // fallback to Layer 2 } // 16B, 32B も同様 ``` **期待命令数**: 2-3 instructions - load bcur - add 8/16/32 - compare bcur <= bend - store bcur (条件付き) - return **リフィル** (Layer 3 から): ```c void tiny_bump_refill(int class_idx, void* base, size_t size) { g_tiny_bump[class_idx].bcur = base; g_tiny_bump[class_idx].bend = (char*)base + size; } ``` --- ### Layer 2: TLS Small Magazine (全クラス) **目的**: 中速パス、5-10 instructions/op **データ構造**: ```c typedef struct { void* items[128]; // 固定サイズ 128 int top; // スタックポインタ } TinySmallMag; static __thread TinySmallMag g_tiny_small_mag[TINY_NUM_CLASSES]; ``` **アロケーション**: ```c static inline void* small_mag_pop(int class_idx) { TinySmallMag* mag = &g_tiny_small_mag[class_idx]; int t = mag->top; if (likely(t > 0)) { mag->top = t - 1; return mag->items[t - 1]; } return NULL; // fallback to Layer 3 } ``` **期待命令数**: 5-10 instructions - load mag->top - compare top > 0 - decrement top - load mag->items[top - 1] - store mag->top - return **フリー**: ```c static inline bool small_mag_push(int class_idx, void* ptr) { TinySmallMag* mag = &g_tiny_small_mag[class_idx]; int t = mag->top; if (likely(t < 128)) { mag->items[t] = ptr; mag->top = t + 1; return true; } return false; // overflow, drain to Layer 3 } ``` **サイズ計算** (L1 cache): - 8B class: 128 * 8B = 1KB - 16B class: 128 * 8B (pointer) = 1KB - 32B class: 128 * 8B = 1KB - Total per thread: ~8KB (全クラス分) → L1 32KB の 25% → OK ✅ --- ### Layer 3: Slow Path (Slab管理) **目的**: 低頻度パス、リフィル・Slab割り当て **処理**: 1. **Magazine リフィル**: Layer 2 の Small Magazine を補充 2. **Bump リフィル**: Layer 1 の Bump を補充 (class 0-2) 3. **Slab 割り当て**: 新しい Slab を割り当て 4. **Global pool からの取得** **関数**: ```c void* tiny_alloc_slow(int class_idx) { // Step 1: Try refill Small Magazine from large magazine if (large_mag_refill_to_small(class_idx, 64)) { return small_mag_pop(class_idx); } // Step 2: Try refill from Slab if (slab_refill_to_small(class_idx, 64)) { return small_mag_pop(class_idx); } // Step 3: Allocate new Slab TinySlab* slab = allocate_new_slab(class_idx); if (slab) { // Refill both bump (class 0-2) and magazine if (class_idx <= 2) { tiny_bump_refill(class_idx, slab->base, slab->total_count * g_tiny_class_sizes[class_idx]); return tiny_bump_alloc(class_idx); } else { slab_refill_to_small(class_idx, 64); return small_mag_pop(class_idx); } } return NULL; // OOM } ``` --- ## 🔄 メインアロケーション関数 ```c void* hak_tiny_alloc(size_t size) { // Size to class int class_idx = hak_tiny_size_to_class(size); if (class_idx < 0) return NULL; // > 1KB // === Layer 1: TLS Bump (hot classes 0-2: 8B/16B/32B) === if (class_idx <= 2) { void* p; switch (class_idx) { case 0: p = tiny_bump_alloc_8B(); break; case 1: p = tiny_bump_alloc_16B(); break; case 2: p = tiny_bump_alloc_32B(); break; } if (likely(p)) return p; } // === Layer 2: TLS Small Magazine (all classes) === void* p = small_mag_pop(class_idx); if (likely(p)) return p; // === Layer 3: Slow path === return tiny_alloc_slow(class_idx); } ``` **期待命令数**: - **Hot path (Layer 1 hit)**: 5-8 instructions (switch + bump + return) - **Medium path (Layer 2 hit)**: 15-20 instructions (switch + mag_pop + return) - **Cold path (Layer 3)**: 50-100+ instructions **平均命令数** (Tiny Hot, 推定): - Layer 1 hit rate: 95% → 95% * 8 = 7.6 insns - Layer 2 hit rate: 4% → 4% * 20 = 0.8 insns - Layer 3 hit rate: 1% → 1% * 100 = 1.0 insns - **Total: ~9.4 insns/op** (現在の 100 から **90% 削減**!) --- ## 🗑️ 削除する機能 ### 完全削除 1. ✂️ `HAKMEM_TINY_BENCH_FASTPATH` - ベンチ専用、本番不要 2. ✂️ `TinyHotMag` (`g_tls_hot_mag`) - Layer 1 Bump で代替 3. ✂️ `g_hot_alloc_fn` - Layer 1 Bump で代替 4. ✂️ `tiny_fast_pop` (`g_fast_head`) - Layer 2 Small Magazine で代替 5. ✂️ 大きい Magazine (2048 items) - Layer 2 (128 items) に統一 ### 保持 (Layer 3 で使用) 1. ✅ Slab 管理 (bitmap, mini-mag) 2. ✅ Registry (O(1) lookup) 3. ✅ Remote free queue 4. ✅ Background spill/drain --- ## 📈 期待効果 ### Tiny Hot (64B, class 2) | Metric | 現在 | 目標 | 改善 | |--------|------|------|------| | Instructions/op | 100 | **10-15** | **85-90%削減** | | Throughput | 179 M/s | **240-250 M/s** | **+35-40%** | | Layer 1 hit rate | - | **95%+** | - | ### Random Mixed (8-128B) | Metric | 現在 | 目標 | 改善 | |--------|------|------|------| | Instructions/op | 412 | **100-150** | **60-75%削減** | | Throughput | 21.6 M/s | **23-24 M/s** | **+10%** | | Layer 1+2 hit rate | - | **98%+** | - | --- ## 🛠️ 実装ステップ ### Phase 1: 新 Layer 実装 1. **TLS Bump** (`core/hakmem_tiny_bump.inc.h`) - データ構造定義 - `tiny_bump_alloc_8B/16B/32B()` - `tiny_bump_refill()` - 所要時間: 1-2時間 2. **Small Magazine** (`core/hakmem_tiny_smallmag.inc.h`) - データ構造定義 - `small_mag_pop/push()` - 所要時間: 1-2時間 3. **新メイン関数** (`core/hakmem_tiny_alloc.inc` 書き換え) - シンプルな 3-layer 構造 - 所要時間: 1時間 ### Phase 2: 古い Layer 削除 4. **コンパイル確認** - 削除する機能を `#if 0` で無効化 - ビルド成功確認 - 所要時間: 30分 5. **ベンチマーク実行** - Tiny Hot, Random Mixed 実行 - perf stat 計測 - 所要時間: 30分 ### Phase 3: 評価・調整 6. **結果評価** - 目標達成? - パフォーマンス低下? - 所要時間: 30分 7. **調整 or ロールバック** - 成功 → 古いコード完全削除、コミット - 失敗 → ロールバック、原因分析 - 所要時間: 1-2時間 **総所要時間**: 6-8時間 (1日作業) --- ## ⚠️ リスクと対策 ### リスク 1: パフォーマンス低下 **対策**: - ✅ ベースライン計測済み - ✅ 各ステップで perf stat 実行 - ✅ 低下時は即ロールバック ### リスク 2: 機能の欠落 **対策**: - ✅ Remote free は保持 (Layer 3) - ✅ Background drain は保持 - ✅ テスト実行で確認 ### リスク 3: L1 cache 圧迫 **対策**: - ✅ Small Magazine は合計 8KB (L1 32KB の 25%) - ✅ Bump は 24B (3 classes * 8B) のみ - ✅ 計測で確認 --- ## 📋 チェックリスト ### 実装前 - [x] ベースライン計測完了 - [x] 設計ドキュメント作成 - [ ] Git ブランチ作成 ### 実装中 - [ ] TLS Bump 実装 - [ ] Small Magazine 実装 - [ ] 新メイン関数実装 - [ ] 古いコード無効化 - [ ] ビルド成功 ### 実装後 - [ ] ベンチマーク実行 - [ ] perf stat 計測 - [ ] 目標達成確認 - [ ] コミット or ロールバック --- **次のアクション**: Git ブランチ作成 → TLS Bump 実装開始