From 580e8f57f7707bbccf25eed95d306b420aa688e6 Mon Sep 17 00:00:00 2001 From: "Moe Charm (CI)" Date: Fri, 12 Dec 2025 04:36:37 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20V7=20Architecture=20Decision=20Matrix?= =?UTF-8?q?=20(mimalloc=20=E7=AB=B6=E4=BA=89=E5=8A=9B=E8=A9=95=E4=BE=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mimalloc vs HAKMEM v7 feature-by-feature 比較表 - v7-5a vs v7-5b 決定基準フレームワーク - Intrusive LIFO 採用検討 - TLS cache hit rate 目標 - Overhead 内訳の実測計画 結論: v7-5a (C6 極限最適化) を先に実施 目標: Intrusive LIFO + Headerless で mimalloc 同等性能 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../V7_ARCHITECTURE_DECISION_MATRIX.md | 414 ++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 docs/analysis/V7_ARCHITECTURE_DECISION_MATRIX.md diff --git a/docs/analysis/V7_ARCHITECTURE_DECISION_MATRIX.md b/docs/analysis/V7_ARCHITECTURE_DECISION_MATRIX.md new file mode 100644 index 00000000..9c8df60b --- /dev/null +++ b/docs/analysis/V7_ARCHITECTURE_DECISION_MATRIX.md @@ -0,0 +1,414 @@ +# V7 Architecture Decision Matrix + +**Date**: 2025-12-12 +**Purpose**: mimalloc 競争力評価 + v7-5 方向性の決定基準を明確化 + +--- + +## 1. mimalloc vs HAKMEM v7 比較表 + +### 1-1. アーキテクチャ比較 + +| 要素 | mimalloc | HAKMEM v7 (C6-only) | Gap | 対策 | +|------|----------|---------------------|-----|------| +| **Free List 構造** | Intrusive LIFO (ブロック内 next ptr) | Page metadata explicit freelist | **-2~3%** | Intrusive LIFO 採用検討 | +| **Size Class 数** | 128 (fine-grained) | 8 (C0-C7) | **-1~2%** | 現状維持 (overhead 分摊で対応) | +| **Page Size** | 8KB (L1 cache fit) | 64KB (ULTRA 互換) | **±0%** | tradeoff 異なる (検証必要) | +| **Segment Size** | 4MB on-demand | 2MB fixed | **±0%** | 同等 | +| **Lookup Cost** | Direct array O(1) | RegionIdBox binary search O(log N) | **-1~2%** | TLS fast path で緩和済み | +| **Header** | なし (headerless) | 薄く残す (1 byte) | **-0.5%** | v6 headerless パターン適用検討 | +| **TLS Access** | 1 read + array index | TLS bounds check + page_meta | **-1%** | TLS hint 最適化済み | +| **Remote Free** | Lock-free MPSC | Lock-free MPSC (同等) | **±0%** | 同等 | +| **Stats Overhead** | Batched/deferred | Atomic increment on hot path | **-0.5~1%** | Stats を cold path へ移動 | + +### 1-2. Hot Path 比較 (14 ns vs 現状) + +**mimalloc hot path** (14 ns): +```c +mi_heap_t* heap = mi_get_default_heap(); // 2 ns: TLS read +int cls = mi_size_to_class(size); // 3 ns: LUT + BSR +mi_page_t* page = heap->pages[cls]; // 1 ns: array index +void* p = page->free; // 3 ns: load free head +page->free = *(void**)p; // 3 ns: update free +return p; // 2 ns +``` + +**HAKMEM v7 hot path** (推定 18-22 ns): +```c +SmallHeapCtx_v7* ctx = small_heap_ctx_v7(); // 2 ns: TLS read +SmallClassHeap_v7* h = &ctx->cls[class_idx]; // 1 ns: array index +SmallPageMeta_v7* p = h->current; // 2 ns: load current +void* base = p->free_list; // 3 ns: load free head +p->free_list = *(void**)base; // 3 ns: update free +p->used++; // 1 ns: counter +((uint8_t*)base)[0] = HEADER_MAGIC | class; // 2 ns: header write +small_v7_stat_alloc(); // 2 ns: atomic stats +return (uint8_t*)base + 1; // 2 ns: USER ptr +``` + +**Gap 内訳**: +| Step | mimalloc | v7 | Diff | 削減可能? | +|------|----------|-----|------|----------| +| TLS access | 2 ns | 2 ns | 0 | - | +| Class lookup | 3 ns | 1 ns | -2 ns | ✅ v7 の方が速い | +| Page lookup | 1 ns | 2 ns | +1 ns | 改善可能 | +| Free list op | 6 ns | 6 ns | 0 | - | +| Counter update | 0 ns | 1 ns | +1 ns | cold path へ移動 | +| Header write | 0 ns | 2 ns | +2 ns | headerless 化 | +| Stats | 0 ns | 2 ns | +2 ns | cold path へ移動 | +| Return | 2 ns | 2 ns | 0 | - | +| **Total** | **14 ns** | **18 ns** | **+4 ns** | **-3~4 ns 可能** | + +### 1-3. 競争力評価 + +**現状 v7 の立ち位置**: +- Legacy baseline: 58.6M ops/s +- v7 Phase v7-3: 56.3M ops/s (-4.3%) +- mimalloc 推定: 71M ops/s (+21% vs legacy) + +**v7 が mimalloc に追いつくには**: +1. Header write 削除: +2 ns 改善 +2. Stats を cold path へ: +2 ns 改善 +3. Counter を cold path へ: +1 ns 改善 +4. **合計**: 18 ns → 13-14 ns (mimalloc と同等) + +**結論**: 設計上 mimalloc と **同等まで到達可能**。ただし intrusive LIFO 採用が鍵。 + +--- + +## 2. v7-5 方向性の決定基準 + +### 2-1. v7-5a vs v7-5b 比較表 + +| 項目 | v7-5a (C6 極限最適化) | v7-5b (Multi-class 拡張) | +|------|----------------------|-------------------------| +| **目標** | C6-only で -4.3% → ±0% | C5+C6 で overhead 分摊 | +| **作業量** | 小 (hotbox 微調整) | 中 (Segment 複数化, TLS hint 拡張) | +| **リスク** | 効果薄い可能性 (diminishing returns) | 複雑度増加 | +| **成功時の効果** | C6 で mimalloc 同等 | C5+C6 で -2% (予測) | +| **失敗時の影響** | 時間の無駄 (1-2日) | 設計変更のコスト (数日) | +| **検証方法** | A/B bench (C6-heavy) | Mixed bench + per-class stats | + +### 2-2. 決定フレームワーク + +**v7-5a を選ぶ条件**: +1. C6 の hot path に明確なボトルネックがある +2. Header write / Stats を cold path へ移動する具体策がある +3. 1-2 日で A/B 検証可能 + +**v7-5b を選ぶ条件**: +1. C6-only では overhead 削減に限界がある (既に TLS 最適化済み) +2. C5/C4 の allocation が実 workload で significant +3. overhead 分摊の理論値 (-4.3% → -2%) が魅力的 + +### 2-3. 推奨: **v7-5a を先に試す** + +**理由**: +1. **低コスト**: 1-2 日で結果が出る +2. **具体的改善点が明確**: Header write + Stats 移動 +3. **失敗しても学び**: 限界が分かれば v7-5b へ移行 +4. **成功すれば**: C6 で mimalloc 同等 → 強力な武器 + +**v7-5a タスク**: +``` +1. Header write を条件付きにする (ENV: HAKMEM_V7_HEADERLESS=1) +2. small_v7_stat_alloc() を #ifdef HAKMEM_V7_STATS で囲む +3. p->used++ を ColdIface retire 時に計算 +4. A/B bench: C6-heavy (400-510B) で v7 ON/OFF +``` + +**成功基準**: +- C6-heavy: v7 ON が legacy ±2% 以内 +- Mixed: v7 ON が legacy と同等以上 + +--- + +## 3. Intrusive LIFO 採用検討 + +### 3-1. 現状 (Explicit Freelist) + +```c +// SmallPageMeta_v7 +void* free_list; // page metadata に freelist head + +// Alloc +void* base = p->free_list; +p->free_list = *(void**)base; + +// Free +*(void**)base = p->free_list; +p->free_list = base; +``` + +**問題**: free_list が page_meta 内にあり、間接参照が必要。 + +### 3-2. Intrusive LIFO (mimalloc 方式) + +```c +// Block 内に next pointer を埋め込む +// Free block: +// +0: next_ptr (8 bytes) - 次の free block へのポインタ +// +8: (unused) + +// Alloc +void* p = page->free; // free head (block 先頭) +page->free = *(void**)p; // block 内の next を読む + +// Free +*(void**)p = page->free; // block 内に next を書く +page->free = p; +``` + +**利点**: +- **Zero metadata per block**: free 時に block 自身に next を書く +- **Cache locality**: 直前に free した block は L1 cache にある +- **Minimal indirection**: page→free だけで完結 + +### 3-3. v7 への適用可能性 + +**現状 v7 の構造**: +``` +SmallPageMeta_v7 +├── free_list (void*) ← page_meta 内 +├── used (uint32_t) +├── capacity (uint32_t) +└── ... + +Block (512B for C6) +├── [0]: header (1 byte) ← USER ptr = base + 1 +└── [1-511]: user data +``` + +**Intrusive 化案**: +``` +SmallPageMeta_v7 +├── free (void*) ← 直接 block を指す (base ptr) +├── used (uint32_t) +└── ... + +Free Block (512B) +├── [0-7]: next_ptr ← intrusive next pointer +└── [8-511]: (unused when free) + +Allocated Block (512B) +├── [0]: header (optional) +└── [1-511]: user data +``` + +**変更点**: +1. `free_list` を `free` にリネーム (semantic 変更) +2. free 時: `*(void**)base = page->free; page->free = base;` +3. alloc 時: `void* p = page->free; page->free = *(void**)p;` +4. Header は USER ptr 計算時のみ使用 (hot path から削除可能) + +### 3-4. 採用判断 + +**採用する場合のメリット**: +- +2 ns 改善 (page_meta 間接参照削減) +- mimalloc と同じデータ構造 → 同等性能の可能性 + +**採用しない場合の理由**: +- 既存 v7 コードの変更が必要 +- Header との互換性を慎重に検討必要 +- v6 headerless との設計統合を先に検討すべき + +**結論**: **v7-5a の後で検討**。まず Header/Stats 削除で効果を測る。 + +--- + +## 4. TLS Cache Hit Rate 目標 + +### 4-1. 現状の TLS Fast Path + +```c +// Phase v7-3 で追加 +if (addr >= ctx->tls_seg_base && addr < ctx->tls_seg_end) { + // TLS hit: RegionIdBox skip + size_t page_idx = (addr - ctx->tls_seg_base) >> SMALL_PAGE_V7_SHIFT; + SmallPageMeta_v7* page = &seg->page_meta[page_idx]; + // ... free logic +} else { + // TLS miss: RegionIdBox fallback + RegionLookupV6 lk = region_id_lookup_v6(ptr); + // ... +} +``` + +### 4-2. Hit Rate 目標 + +| Workload | TLS Hit Rate 目標 | 現状推定 | 根拠 | +|----------|------------------|----------|------| +| C6-heavy | 99%+ | 95-98% | ほぼ同一 segment | +| Mixed | 90%+ | 80-90% | 複数 class で分散 | +| Multi-thread | 85%+ | 75-85% | Remote free 混在 | + +### 4-3. Hit Rate 測定方法 + +```c +// ENV: HAKMEM_V7_TLS_STATS=1 +static uint64_t g_v7_tls_hit = 0; +static uint64_t g_v7_tls_miss = 0; + +// In free path +if (addr >= ctx->tls_seg_base && addr < ctx->tls_seg_end) { + __sync_fetch_and_add(&g_v7_tls_hit, 1); + // ... +} else { + __sync_fetch_and_add(&g_v7_tls_miss, 1); + // ... +} + +// At exit +fprintf(stderr, "[V7_TLS] hit=%lu miss=%lu rate=%.2f%%\n", + g_v7_tls_hit, g_v7_tls_miss, + 100.0 * g_v7_tls_hit / (g_v7_tls_hit + g_v7_tls_miss)); +``` + +### 4-4. 改善策 (Hit Rate < 目標の場合) + +1. **Multi-segment TLS hint** (v7-5b で必要): + ```c + struct { + uintptr_t seg_base; + uintptr_t seg_end; + SmallSegment_v7* seg; + } tls_seg[5]; // C3-C7 用 + ``` + +2. **Last-page cache** (既に設計あり): + ```c + uintptr_t last_page_base; + uintptr_t last_page_end; + SmallPageMeta_v7* last_page_meta; + ``` + +3. **Segment 再利用**: 同一 class の allocation が同一 segment に集中するよう誘導 + +--- + +## 5. Overhead 内訳の実測計画 + +### 5-1. 現状の仮説 (-4.3% 内訳) + +| 要因 | 推定 | 対策 | +|------|------|------| +| Page metadata 間接参照 | ~2% | Intrusive LIFO | +| Extra validation | ~1% | Branch 最適化 | +| RegionIdBox fallback | ~1% | TLS cache 強化 | +| Header write | ~0.3% | Headerless 化 | +| **合計** | **~4.3%** | | + +### 5-2. 実測方法 + +**Step 1: Header write 削除** +```bash +# ENV で headerless 有効化 +HAKMEM_V7_HEADERLESS=1 ./bench_random_mixed_hakmem +# 効果測定: -0.3% 改善なら仮説検証 +``` + +**Step 2: Stats 削除** +```bash +# Stats を compile-time で無効化 +make clean && make CFLAGS="-DHAKMEM_V7_NO_STATS" +# 効果測定: -0.5% 改善なら仮説検証 +``` + +**Step 3: TLS hit rate 測定** +```bash +HAKMEM_V7_TLS_STATS=1 ./bench_random_mixed_hakmem +# Hit rate < 90% なら TLS 改善が必要 +``` + +**Step 4: Page metadata 間接参照** +```bash +# Intrusive LIFO 試験実装 +# 効果測定: -2% 改善なら大きな勝利 +``` + +### 5-3. 検証完了基準 + +| 仮説 | 実測結果 | 判定 | +|------|----------|------| +| Header write ~0.3% | 実測値 | ±0.2% なら OK | +| Stats ~0.5% | 実測値 | ±0.3% なら OK | +| TLS fallback ~1% | Hit rate × miss cost | 計算で検証 | +| Page metadata ~2% | Intrusive 後の差分 | ±0.5% なら OK | + +--- + +## 6. 次のアクション + +### 6-1. 即時 (v7-5a: 1-2 日) + +1. **Header write 条件化**: + - `smallobject_hotbox_v7_box.h` に `#ifdef HAKMEM_V7_HEADERLESS` 追加 + - Free path で header validation をスキップ + +2. **Stats を cold path へ**: + - `small_v7_stat_alloc()` を `#ifdef HAKMEM_V7_STATS` で囲む + - Default OFF で bench + +3. **A/B bench**: + - C6-heavy: `HAKMEM_BENCH_MIN_SIZE=400 HAKMEM_BENCH_MAX_SIZE=510` + - v7 ON/OFF 比較 + +### 6-2. 短期 (v7-5a 評価後: 2-3 日) + +4. **TLS hit rate 測定**: + - Stats 追加して hit/miss ratio 確認 + - < 90% なら multi-segment hint 検討 + +5. **Intrusive LIFO 試験**: + - small_heap_alloc_fast_v7 を intrusive 版に書き換え + - A/B bench で効果測定 + +### 6-3. 中期 (v7-5b 検討: 1 週間) + +6. **Multi-class 拡張設計**: + - C5 対応の Segment 設計 + - TLS context 拡張 (tls_seg[5]) + +7. **v6 headerless 統合**: + - v6 と v7 の headerless パターン統合 + - RegionIdBox で class_idx 取得を共通化 + +--- + +## 7. 結論 + +### mimalloc に勝てるか? + +**Yes, 設計上は可能**。 + +条件: +1. Intrusive LIFO 採用 (+2 ns) +2. Header write 削除 (+2 ns) +3. Stats を cold path へ (+2 ns) +4. TLS hit rate 90%+ 維持 + +これで v7 は 13-14 ns (mimalloc 同等) に到達可能。 + +### v7-5 の推奨 + +**v7-5a (C6 極限最適化) を先に実施**。 + +理由: +- 低コスト (1-2 日) +- 具体的改善点が明確 +- 成功すれば v7-5b は不要かもしれない +- 失敗しても学びがある + +### 最終目標 + +| Phase | 目標 | 達成基準 | +|-------|------|----------| +| v7-5a | C6 で legacy ±2% | C6-heavy bench | +| v7-5b | C5+C6 で legacy ±0% | Mixed bench | +| v7-6 | mimalloc 同等 | Intrusive LIFO + Headerless | + +--- + +**Document Status**: COMPLETE +**Next Action**: v7-5a 実装開始 +**Decision Owner**: User