diff --git a/docs/analysis/PERF_ULTRA_REFILL_OPT_1_PLAN.md b/docs/analysis/PERF_ULTRA_REFILL_OPT_1_PLAN.md new file mode 100644 index 00000000..deeed7c5 --- /dev/null +++ b/docs/analysis/PERF_ULTRA_REFILL_OPT_1_PLAN.md @@ -0,0 +1,206 @@ +# Phase PERF-ULTRA-REFILL-OPT-1 計画:C7 ULTRA refill パス最適化 + +## 背景 + +### 現状分析 (PERF-ULTRA-REBASE-4) + +Mixed 16-1024B ワークロード(iters=10M, ws=8192)のホットパス分析結果: + +| 関数 | self% | 最適化状況 | +|------|-------|--------| +| free (dispatcher) | 25.48% | ✅ snapshot 済み(ENV/route 初期化時のみ) | +| malloc (dispatcher) | 21.13% | ✅ LUT 化済み(size_to_class/route 両方 0 calls) | +| tiny_c7_ultra_alloc | 7.66% | ⚠️ 既に最適化済み(直線化限界)| +| tiny_c7_ultra_free | 3.50% | ✅ TLS push + segment learning | +| so_free | 2.47% | ❌ v3 backend(最適化機会未調査) | +| so_alloc_fast | 2.39% | ❌ v3 backend(最適化機会未調査) | +| **tiny_c7_ultra_page_of** | **1.78%** | **🎯 refill path(最適化ターゲット)** | +| so_alloc | 1.21% | - | +| classify_ptr | 1.15% | - | + +### 重要な発見 + +1. **Dispatcher/Gate レベルの最適化は既に完了** + - free dispatcher (25%) = malloc/free の C API コール + routing overhead + - malloc dispatcher (21%) = 内部的には LUT/ULTRA で最適化済み + - これ以上削減するには architecture レベルの再設計が必要 + +2. **次のボトルネックは C7 ULTRA 内部** + - alloc (7.66%) + free (3.50%) + refill (1.78%) = **12.94%** + - このうち refill (1.78%) が新規ボトルネック + +3. **Refill パスが visible に** + - C7 ULTRA は page を「必要に応じて allocate」 + - refill 呼び出しが所々で発生し、tiny_c7_ultra_page_of が呼ばれている + +--- + +## 目的 + +**C7 ULTRA refill パスを最適化し、tiny_c7_ultra_page_of の 1.78% を削減** + +期待効果: +- refill path 削減で 0.5-1% の削減 +- 全体スループット +0.5-2M ops/s(30M → 30.5-32M ops/s) + +--- + +## 現状の C7 ULTRA refill 構造 + +### TLS キャッシュ管理 + +C7 ULTRA は以下の構造を持つ: +```c +typedef struct TinyC7UltraBox { + // TLS freelist(alloc pop 用) + void* freelist[128]; + uint16_t count; + + // Segment 情報(free で学習) + uintptr_t seg_base, seg_end; + tiny_c7_ultra_segment_t* cached_segment; + +} TinyC7UltraBox; +``` + +### Refill のトリガー + +1. **Alloc 側**: + - TLS freelist が empty → refill_cold パスへ + - segment から新しいページを割り当て + - 128 個のブロックを freelist に詰める + +2. **Retire 側**: + - freelist が full → retire_cold へ + - ページを segment に返す + +### tiny_c7_ultra_page_of の役割 + +refill/retire 時に「ページを特定するため」に呼ばれる: +```c +tiny_c7_ultra_page_meta_t* tiny_c7_ultra_page_of(void* p, + tiny_c7_ultra_segment_t** out_seg, + uint32_t* out_page_idx) { + tiny_c7_ultra_segment_t* seg = tiny_c7_ultra_segment_from_ptr(p); + if (!seg) return NULL; + + // Offset 計算と page index 取得 + uintptr_t offset = (uintptr_t)p - (uintptr_t)seg->base; + uint32_t idx = (uint32_t)(offset / seg->page_size); + + // Bounds check + if (idx >= seg->num_pages) return NULL; + + return &seg->pages[idx]; +} +``` + +**cost breakdown**: +- tiny_c7_ultra_segment_from_ptr(): O(1) ptr lookup +- offset 計算: 固定コスト(1-2 cycles) +- page_size division: 可変(seg->page_size がキャッシュマイス可能) +- bounds check: 1-2 cycles + +--- + +## 最適化候補 + +### Option 1: Page size を固定に(最大効果) + +**現状**: +```c +size_t page_size; // seg ごとに異なる可能性 +uint32_t idx = (uint32_t)(offset / seg->page_size); // division +``` + +**問題**: `seg->page_size` が毎回参照 → cache line miss 可能性 + +**最適化案**: +- TINY_C7_ULTRA_PAGE_SIZE を macro 定義(64KiB 固定と仮定) +- division → right shift に最適化(`offset >> PAGE_SHIFT`) + +**期待**: division 命令削減で 0.1-0.2% 削減 + +**条件**: C7 ULTRA segment の page_size が常に一定であることを確認 + +--- + +### Option 2: Segment learning を alloc 側に移動(中程度効果) + +**現状**: +- free 時に segment を学習(initial miss) +- その後 free はキャッシュされた seg_base/seg_end でチェック + +**提案**: +- alloc refill 時に segment を学習/cache +- refill が segment を既に知っている → segment_from_ptr が不要に + +**期待**: refill パスで segment_from_ptr call 削減 → 0.2-0.3% + +--- + +### Option 3: Page lookup の TLS cache(小程度効果) + +**提案**: +- 直前に lookup した page を TLS に cache +- 同じページに対する refill 呼び출しなら cache hit + +**期待**: 0.1% 程度(alloc batch が小さいため) + +--- + +## 実装計画(推奨順) + +### Phase REFILL-OPT-1a: Page Size Macro 化 + +1. **確認**: + - C7 ULTRA segment の page_size 値を記録 + - 常に 64KiB(または固定値)か確認 + +2. **実装**: + - TINY_C7_ULTRA_PAGE_SIZE macro を定義 + - tiny_c7_ultra_page_of で `offset >> TINY_C7_ULTRA_PAGE_SHIFT` に変更 + - tiny_c7_ultra_segment_t から page_size を削除(optional) + +3. **テスト**: + - Mixed bench: 29.5-32M ops/s 範囲で確認 + - SEGV/assert なし + +4. **計測**: + - perf で tiny_c7_ultra_page_of self% が 1.78% → 1.5% 以下か確認 + +### Phase REFILL-OPT-1b: Segment Learning in Alloc + +1. **実装**: + - tiny_c7_ultra_alloc_refill で segment を学習して cache + - tiny_c7_ultra_segment_from_ptr 呼び出し削減 + +2. **テスト同様** + +--- + +## リスク評価 + +| リスク | 確率 | 対策 | +|--------|------|------| +| page_size が可変 | 低 | 確認 phase で判定、fallback 用 code keep | +| segment cache miss | 低 | TLS cache 容量確保 | +| allocation pattern 変化 | 低 | multi-thread test で確認 | + +--- + +## 成功条件 + +- ✅ Build 成功、warning なし +- ✅ Mixed bench で SEGV/assert なし +- ✅ Throughput 回帰なし(≥ −2%) +- ✅ tiny_c7_ultra_page_of self% が 1.5% 以下 + +--- + +## 参考資料 + +- `PERF_ULTRA_REBASE_4.md`: 詳細計測結果 +- `TINY_C7_ULTRA_DESIGN.md`: C7 ULTRA 設計概要 +- `docs/analysis/ALLOC_GATE_ANALYSIS.md`: Gate 分析 +