Files
hakmem/docs/design/TINY_3LAYER_ARCHITECTURE.md

388 lines
9.5 KiB
Markdown
Raw Normal View History

# 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 実装開始