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>
9.5 KiB
9.5 KiB
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層)
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();
}
問題:
- ✗ 重複する層 (Layer 1-4 はすべて TLS キャッシュ)
- ✗ 条件分岐が多すぎる
- ✗ 関数呼び出しオーバーヘッド
- ✗ 複数のデータ構造 (sll, hotmag, fast_pop, magazine)
🎯 新アーキテクチャ (3層)
Layer 1: TLS Bump Allocator (8B/16B/32B専用)
目的: 超高速パス、2-3 instructions/op
データ構造:
// 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
アロケーション:
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 から):
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
データ構造:
typedef struct {
void* items[128]; // 固定サイズ 128
int top; // スタックポインタ
} TinySmallMag;
static __thread TinySmallMag g_tiny_small_mag[TINY_NUM_CLASSES];
アロケーション:
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
フリー:
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割り当て
処理:
- Magazine リフィル: Layer 2 の Small Magazine を補充
- Bump リフィル: Layer 1 の Bump を補充 (class 0-2)
- Slab 割り当て: 新しい Slab を割り当て
- Global pool からの取得
関数:
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
}
🔄 メインアロケーション関数
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% 削減!)
🗑️ 削除する機能
完全削除
- ✂️
HAKMEM_TINY_BENCH_FASTPATH- ベンチ専用、本番不要 - ✂️
TinyHotMag(g_tls_hot_mag) - Layer 1 Bump で代替 - ✂️
g_hot_alloc_fn- Layer 1 Bump で代替 - ✂️
tiny_fast_pop(g_fast_head) - Layer 2 Small Magazine で代替 - ✂️ 大きい Magazine (2048 items) - Layer 2 (128 items) に統一
保持 (Layer 3 で使用)
- ✅ Slab 管理 (bitmap, mini-mag)
- ✅ Registry (O(1) lookup)
- ✅ Remote free queue
- ✅ 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 実装
-
TLS Bump (
core/hakmem_tiny_bump.inc.h)- データ構造定義
tiny_bump_alloc_8B/16B/32B()tiny_bump_refill()- 所要時間: 1-2時間
-
Small Magazine (
core/hakmem_tiny_smallmag.inc.h)- データ構造定義
small_mag_pop/push()- 所要時間: 1-2時間
-
新メイン関数 (
core/hakmem_tiny_alloc.inc書き換え)- シンプルな 3-layer 構造
- 所要時間: 1時間
Phase 2: 古い Layer 削除
-
コンパイル確認
- 削除する機能を
#if 0で無効化 - ビルド成功確認
- 所要時間: 30分
- 削除する機能を
-
ベンチマーク実行
- Tiny Hot, Random Mixed 実行
- perf stat 計測
- 所要時間: 30分
Phase 3: 評価・調整
-
結果評価
- 目標達成?
- パフォーマンス低下?
- 所要時間: 30分
-
調整 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) のみ
- ✅ 計測で確認
📋 チェックリスト
実装前
- ベースライン計測完了
- 設計ドキュメント作成
- Git ブランチ作成
実装中
- TLS Bump 実装
- Small Magazine 実装
- 新メイン関数実装
- 古いコード無効化
- ビルド成功
実装後
- ベンチマーク実行
- perf stat 計測
- 目標達成確認
- コミット or ロールバック
次のアクション: Git ブランチ作成 → TLS Bump 実装開始