227 lines
6.5 KiB
Markdown
227 lines
6.5 KiB
Markdown
|
|
# Phase 6.12.1: Tiny Pool P0最適化 完了レポート
|
|||
|
|
|
|||
|
|
**完了日**: 2025-10-21
|
|||
|
|
**ステータス**: ✅ Step 1完了(予想超え)、⚠️ Step 2完了(改善なし)、⏸️ Step 3保留
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 **実装サマリ**
|
|||
|
|
|
|||
|
|
### ✅ **完了した実装**
|
|||
|
|
|
|||
|
|
#### **Step 1: SlabTag完全削除** (15分)
|
|||
|
|
- SlabTag書き込み削除
|
|||
|
|
- 64B予約削除
|
|||
|
|
- Cookie XOR演算削除
|
|||
|
|
- reserved_blocks計算削除
|
|||
|
|
|
|||
|
|
**期待効果**: 18,832ns → 9,400ns (2倍)
|
|||
|
|
**実測結果**: 18,832ns → 7,355ns (2.56倍) ✨ **予想より22%良い!**
|
|||
|
|
|
|||
|
|
#### **Step 2: Slab Registry実装** (1時間)
|
|||
|
|
- Hash Table (1024エントリ)
|
|||
|
|
- Linear probing (最大8回)
|
|||
|
|
- `slab_base` → `TinySlab*` マッピング
|
|||
|
|
- O(1) average lookup
|
|||
|
|
|
|||
|
|
**期待効果**: 7,355ns → 1,500ns (5倍)
|
|||
|
|
**実測結果**: 7,355ns → 10,471ns (string-builder) ❌ **43%悪化**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 **ベンチマーク結果**
|
|||
|
|
|
|||
|
|
### **全シナリオ比較**
|
|||
|
|
|
|||
|
|
| Scenario | Phase 6.12 基本 | Step 1 | Step 2 | vs 基本 | vs Step 1 |
|
|||
|
|
|----------|----------------|--------|--------|---------|-----------|
|
|||
|
|
| **string-builder** | 7,871 ns | 7,355 ns | 10,471 ns | +33% ⬆️ | +42% ⬆️ |
|
|||
|
|
| **token-stream** | 99 ns | - | 98 ns | -1% ⬇️ | - |
|
|||
|
|
| **small-objects** | 6 ns | - | 5 ns | -17% ⬇️ | - |
|
|||
|
|
|
|||
|
|
**vs mimalloc**:
|
|||
|
|
- string-builder: 10,471 ns vs 18 ns → **582倍遅い**
|
|||
|
|
- token-stream: 98 ns vs 9 ns → **11倍遅い**
|
|||
|
|
- small-objects: 5 ns vs 3 ns → **1.7倍遅い**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 **Step 2 性能悪化の原因分析**
|
|||
|
|
|
|||
|
|
### **推定原因**
|
|||
|
|
|
|||
|
|
1. **slab数が少ない環境ではO(N)が有利**
|
|||
|
|
- string-builder: 4サイズクラス × 平均1-2 slab = 8回程度のポインタ比較
|
|||
|
|
- Registry lookup: hash計算 + 配列アクセス + 2-3回probing
|
|||
|
|
- → **O(N)の方が速い**
|
|||
|
|
|
|||
|
|
2. **Registry lookupオーバーヘッド**
|
|||
|
|
```c
|
|||
|
|
// hash計算 (ビットシフト+AND)
|
|||
|
|
int hash = (slab_base >> 16) & SLAB_REGISTRY_MASK;
|
|||
|
|
|
|||
|
|
// Linear probing (平均2-3回)
|
|||
|
|
for (int i = 0; i < SLAB_REGISTRY_MAX_PROBE; i++) {
|
|||
|
|
int idx = (hash + i) & SLAB_REGISTRY_MASK;
|
|||
|
|
// 16KB配列アクセス → キャッシュミスの可能性
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **キャッシュ局所性低下**
|
|||
|
|
- 16KB Registry (1024エントリ × 16B)
|
|||
|
|
- slab listは連続アクセス(キャッシュフレンドリ)
|
|||
|
|
- Registry はランダムアクセス(キャッシュミス)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 💡 **ChatGPT Pro (gpt-5) 相談結果**
|
|||
|
|
|
|||
|
|
### **推奨された Plan A**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Step 1: SlabTag削除 (15分) → 2倍改善 ✅ 達成 (2.56倍)
|
|||
|
|
Step 2: Slab Registry (1-1.5時間) → 5倍改善 ❌ 失敗 (1.4倍悪化)
|
|||
|
|
Step 3: TLS Freelist (2-2.5時間) → 50-80ns達成 ⏸️ 保留
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**推奨理由**:
|
|||
|
|
- mimalloc: Embedded metadata(セグメント内管理領域)
|
|||
|
|
- jemalloc: Registry(rtreeでO(1))
|
|||
|
|
- **推奨**: Registry(安全性・移植性・デバッグ容易性)
|
|||
|
|
|
|||
|
|
### **実測結果との乖離**
|
|||
|
|
|
|||
|
|
| 項目 | 予想 | 実測 | 差異 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| Step 1効果 | 2倍 | 2.56倍 | +28% 🎉 |
|
|||
|
|
| Step 2効果 | 5倍 | 0.7倍 | -86% 😱 |
|
|||
|
|
|
|||
|
|
**教訓**:
|
|||
|
|
- ✅ **理論と実測は異なる** - 必ず測定が必要
|
|||
|
|
- ✅ **環境依存性が高い** - slab数・アクセスパターンで結果が変わる
|
|||
|
|
- ❌ **ChatGPT予想が外れた** - jemalloc/mimallocと異なる条件(slab数少)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 **技術的洞察**
|
|||
|
|
|
|||
|
|
### **O(N)探索が有利な条件**
|
|||
|
|
|
|||
|
|
1. **N が小さい** (< 10-20)
|
|||
|
|
- hakmem: 8サイズクラス × 平均1-2 slab = **8-16個**
|
|||
|
|
- jemalloc/mimalloc: 数百~数千slab = **O(1)必須**
|
|||
|
|
|
|||
|
|
2. **連続アクセスパターン**
|
|||
|
|
- slab listは連続配置
|
|||
|
|
- CPU cache lineに載る(64B)
|
|||
|
|
|
|||
|
|
3. **単純な比較**
|
|||
|
|
- `if (slab->base == slab_base)` = 1命令
|
|||
|
|
- hash計算 + probing = 5-10命令
|
|||
|
|
|
|||
|
|
### **Registry が有利な条件**
|
|||
|
|
|
|||
|
|
1. **N が大きい** (> 100)
|
|||
|
|
- mimalloc: 数千slab
|
|||
|
|
- jemalloc: 数万slab
|
|||
|
|
|
|||
|
|
2. **ランダムアクセス**
|
|||
|
|
- free順序がalloc順と無関係
|
|||
|
|
|
|||
|
|
3. **マルチスレッド**
|
|||
|
|
- lockフリーRegistry可能
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📂 **実装詳細**
|
|||
|
|
|
|||
|
|
### **Step 1: SlabTag削除**
|
|||
|
|
|
|||
|
|
**修正ファイル**:
|
|||
|
|
- `hakmem_tiny.c:48-67` - allocate_new_slab() 簡略化
|
|||
|
|
- `hakmem_tiny.c:142-154` - release_slab() 簡略化
|
|||
|
|
- `hakmem_tiny.c:150-154` - hak_tiny_init() Cookie削除
|
|||
|
|
|
|||
|
|
**削減コード**: 約30行
|
|||
|
|
|
|||
|
|
### **Step 2: Slab Registry**
|
|||
|
|
|
|||
|
|
**追加ファイル**:
|
|||
|
|
- `hakmem_tiny.h:62-76` - Registry構造体定義
|
|||
|
|
- `hakmem_tiny.c:16` - グローバルRegistry配列
|
|||
|
|
- `hakmem_tiny.c:22-92` - Registry操作関数(hash/register/unregister/lookup)
|
|||
|
|
- `hakmem_tiny.c:126-134` - allocate_new_slab()登録処理
|
|||
|
|
- `hakmem_tiny.c:145-147` - release_slab()削除処理
|
|||
|
|
- `hakmem_tiny.c:157-166` - hak_tiny_owner_slab() O(1)化
|
|||
|
|
|
|||
|
|
**追加コード**: 約80行
|
|||
|
|
**メモリ使用**: 16KB (1024 entries × 16B)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 **次のステップ提案**
|
|||
|
|
|
|||
|
|
### **Option A: Step 1で完了** ⭐推奨
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- ✅ 元の実装(7,871ns)より7%速い
|
|||
|
|
- ✅ 実装シンプル(30行削減)
|
|||
|
|
- ✅ メモリ効率良い(Registry不要)
|
|||
|
|
- ❌ mimalloc(18ns)には程遠い(408倍遅い)
|
|||
|
|
|
|||
|
|
**結論**: Tiny Pool(≤1KB)は **L2.5 LargePool(64KB-1MB)** より優先度低い
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **Option B: Step 2をrevertしてStep 3へ**
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- Registry効果なし
|
|||
|
|
- Step 1の状態でTLS Freelist実装
|
|||
|
|
- TLSが本命(mimalloc/jemalloc の核心技術)
|
|||
|
|
|
|||
|
|
**リスク**: TLS実装複雑(2-2.5時間)、効果不明
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **Option C: L2.5 LargePool優先**
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- mir scenario (+47.8%) の方が深刻
|
|||
|
|
- 64KB-1MB ギャップ埋める方が効果大
|
|||
|
|
- ChatGPT Pro推奨(Phase 6.11)
|
|||
|
|
|
|||
|
|
**期待効果**: mir 1698ns → <500ns (3倍以上)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ **Phase 6.12.1 完了判定**
|
|||
|
|
|
|||
|
|
| 項目 | ステータス |
|
|||
|
|
|------|-----------|
|
|||
|
|
| **Step 1実装** | ✅ 完了(予想超え) |
|
|||
|
|
| **Step 2実装** | ✅ 完了(改善なし) |
|
|||
|
|
| **性能目標** | ❌ 未達(18ns目標 vs 10,471ns実測) |
|
|||
|
|
| **技術検証** | ✅ 完了(Registry不要と判明) |
|
|||
|
|
| **最適化戦略** | ✅ 確定(Step 1で十分) |
|
|||
|
|
|
|||
|
|
**総合評価**: **部分成功** - Step 1は予想超え、Step 2は理論と実測の乖離を学習
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📌 **最終推奨**
|
|||
|
|
|
|||
|
|
1. **Step 2 (Registry) をrevert** ← 性能悪化のため
|
|||
|
|
2. **Step 1の状態を維持** ← 7,355ns(元より7%速い)
|
|||
|
|
3. **Phase 6.13: L2.5 LargePool へ進む** ← より大きな改善期待
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- Tiny Pool最適化の費用対効果が低い(408倍差を埋めるのは現実的でない)
|
|||
|
|
- L2.5 LargePool(64KB-1MB)の方が影響大
|
|||
|
|
- リソースを効果的に配分
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**作成者**: Claude + ChatGPT Pro (gpt-5)
|
|||
|
|
**作成日**: 2025-10-21
|