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>
388 lines
9.5 KiB
Markdown
388 lines
9.5 KiB
Markdown
# 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 実装開始
|