468 lines
12 KiB
Markdown
468 lines
12 KiB
Markdown
|
|
# hakmem 実装ロードマップ(ハイブリッド案)(2025-11-01)
|
|||
|
|
|
|||
|
|
**戦略**: ハイブリッドアプローチ
|
|||
|
|
- **≤1KB (Tiny)**: 静的最適化(P0完了、学習不要)
|
|||
|
|
- **8-32KB (Mid)**: mimalloc風 per-thread segment(MT性能最優先)
|
|||
|
|
- **≥64KB (Large)**: 学習ベース(ELO戦略が活きる)
|
|||
|
|
|
|||
|
|
**基準ドキュメント**:
|
|||
|
|
- `NEXT_STEP_ANALYSIS.md` - ハイブリッド案の詳細分析
|
|||
|
|
- `P0_SUCCESS_REPORT.md` - P0実装成功レポート
|
|||
|
|
- `docs/analysis/CHATGPT_PRO_ULTRATHINK_RESPONSE.md` - ChatGPT Pro 推奨
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 現在の性能状況(P0実装後)
|
|||
|
|
|
|||
|
|
| ベンチマーク | hakmem (hakx) | mimalloc | 差分 | 状況 |
|
|||
|
|
|------------|---------------|----------|------|------|
|
|||
|
|
| **Tiny Hot 32B** | 215 M ops/s | 182 M ops/s | **+18%** ✅ | 勝利(P0で改善)|
|
|||
|
|
| **Random Mixed** | 22.5 M ops/s | 25.1 M ops/s | **-10%** ⚠️ | 負け |
|
|||
|
|
| **mid_large_mt** | 46-47 M ops/s | 122 M ops/s | **-62%** ❌❌ | 惨敗(最大の課題)|
|
|||
|
|
|
|||
|
|
**P0成果**: Tiny Pool リフィルバッチ化で +5.16%
|
|||
|
|
- IPC: 4.71 → 5.35 (+13.6%)
|
|||
|
|
- L1キャッシュミス: -80%
|
|||
|
|
- 命令数/op: 100.1 → 101.8 (+1.7%だが実行効率向上)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ Phase 0: Tiny Pool 最適化(完了)
|
|||
|
|
|
|||
|
|
### 実装内容
|
|||
|
|
- ✅ **P0: 完全バッチ化**(ChatGPT Pro 推奨)
|
|||
|
|
- `core/hakmem_tiny_refill_p0.inc.h` 新規作成
|
|||
|
|
- `sll_refill_batch_from_ss()` 実装
|
|||
|
|
- `ss_active_inc × 64 → ss_active_add × 1`
|
|||
|
|
|
|||
|
|
### 成果
|
|||
|
|
- ✅ Tiny Hot: 202.55M → 213.00M (+5.16%)
|
|||
|
|
- ✅ IPC向上: 4.71 → 5.35 (+13.6%)
|
|||
|
|
- ✅ L1キャッシュミス削減: -80%
|
|||
|
|
|
|||
|
|
### 教訓
|
|||
|
|
- ❌ 3層アーキテクチャ(失敗): ホットパス変更で -63%
|
|||
|
|
- ✅ P0(成功): リフィルのみ最適化、ホットパス不変で +5.16%
|
|||
|
|
- 💡 **ホットパスは触らない、スローパスだけ最適化**
|
|||
|
|
|
|||
|
|
詳細: `P0_SUCCESS_REPORT.md`, `3LAYER_FAILURE_ANALYSIS.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 Phase 1: Mid Range MT最適化(最優先、1週間)
|
|||
|
|
|
|||
|
|
### 目標
|
|||
|
|
- **mid_large_mt**: 46M → **100-120M** (+120-160%)
|
|||
|
|
- mimalloc 並みのMT性能達成
|
|||
|
|
- 学習層への影響: **なし**(64KB以上は無変更)
|
|||
|
|
|
|||
|
|
### 問題分析
|
|||
|
|
|
|||
|
|
**現状の処理フロー**:
|
|||
|
|
```
|
|||
|
|
8-32KB → L2 Pool (hakmem_pool.c)
|
|||
|
|
↓
|
|||
|
|
ELO戦略選択(オーバーヘッド)
|
|||
|
|
↓
|
|||
|
|
Global Pool(ロック競合)
|
|||
|
|
↓
|
|||
|
|
MT性能: 46M ops/s(mimalloc の 38%)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**mimalloc の処理フロー**:
|
|||
|
|
```
|
|||
|
|
8-32KB → per-thread segment
|
|||
|
|
↓
|
|||
|
|
TLSから直接取得(ロックフリー)
|
|||
|
|
↓
|
|||
|
|
MT性能: 122M ops/s
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**根本原因**: ロック競合 + 戦略選択オーバーヘッド
|
|||
|
|
|
|||
|
|
### 実装計画
|
|||
|
|
|
|||
|
|
#### 1.1 新規ファイル作成
|
|||
|
|
|
|||
|
|
**`core/hakmem_mid_mt.h`** - per-thread segment 定義
|
|||
|
|
```c
|
|||
|
|
#ifndef HAKMEM_MID_MT_H
|
|||
|
|
#define HAKMEM_MID_MT_H
|
|||
|
|
|
|||
|
|
// Mid Range size classes (8KB, 16KB, 32KB)
|
|||
|
|
#define MID_NUM_CLASSES 3
|
|||
|
|
#define MID_CLASS_8KB 0
|
|||
|
|
#define MID_CLASS_16KB 1
|
|||
|
|
#define MID_CLASS_32KB 2
|
|||
|
|
|
|||
|
|
// per-thread segment (mimalloc風)
|
|||
|
|
typedef struct MidThreadSegment {
|
|||
|
|
void* free_list; // Free list head
|
|||
|
|
void* current; // Current allocation pointer
|
|||
|
|
void* end; // Segment end
|
|||
|
|
size_t size; // Segment size (64KB chunk)
|
|||
|
|
uint32_t used_count; // Used blocks in segment
|
|||
|
|
uint32_t capacity; // Total capacity
|
|||
|
|
} MidThreadSegment;
|
|||
|
|
|
|||
|
|
// TLS segments (one per size class)
|
|||
|
|
extern __thread MidThreadSegment g_mid_segments[MID_NUM_CLASSES];
|
|||
|
|
|
|||
|
|
// API
|
|||
|
|
void* mid_mt_alloc(size_t size);
|
|||
|
|
void mid_mt_free(void* ptr, size_t size);
|
|||
|
|
|
|||
|
|
#endif
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`core/hakmem_mid_mt.c`** - 実装
|
|||
|
|
```c
|
|||
|
|
#include "hakmem_mid_mt.h"
|
|||
|
|
#include <sys/mman.h>
|
|||
|
|
|
|||
|
|
__thread MidThreadSegment g_mid_segments[MID_NUM_CLASSES] = {0};
|
|||
|
|
|
|||
|
|
// Segment size: 64KB chunk per class
|
|||
|
|
#define SEGMENT_SIZE (64 * 1024)
|
|||
|
|
|
|||
|
|
static int size_to_mid_class(size_t size) {
|
|||
|
|
if (size <= 8192) return MID_CLASS_8KB;
|
|||
|
|
if (size <= 16384) return MID_CLASS_16KB;
|
|||
|
|
if (size <= 32768) return MID_CLASS_32KB;
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void* segment_alloc_new(MidThreadSegment* seg, size_t block_size) {
|
|||
|
|
// Allocate new 64KB segment
|
|||
|
|
void* mem = mmap(NULL, SEGMENT_SIZE,
|
|||
|
|
PROT_READ | PROT_WRITE,
|
|||
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|||
|
|
if (mem == MAP_FAILED) return NULL;
|
|||
|
|
|
|||
|
|
seg->current = (char*)mem + block_size;
|
|||
|
|
seg->end = (char*)mem + SEGMENT_SIZE;
|
|||
|
|
seg->size = SEGMENT_SIZE;
|
|||
|
|
seg->capacity = SEGMENT_SIZE / block_size;
|
|||
|
|
seg->used_count = 1;
|
|||
|
|
|
|||
|
|
return mem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void* mid_mt_alloc(size_t size) {
|
|||
|
|
int class_idx = size_to_mid_class(size);
|
|||
|
|
if (class_idx < 0) return NULL;
|
|||
|
|
|
|||
|
|
MidThreadSegment* seg = &g_mid_segments[class_idx];
|
|||
|
|
size_t block_size = (class_idx == 0) ? 8192 :
|
|||
|
|
(class_idx == 1) ? 16384 : 32768;
|
|||
|
|
|
|||
|
|
// Fast path: pop from free list
|
|||
|
|
if (seg->free_list) {
|
|||
|
|
void* p = seg->free_list;
|
|||
|
|
seg->free_list = *(void**)p;
|
|||
|
|
return p;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Bump allocation from current segment
|
|||
|
|
void* current = seg->current;
|
|||
|
|
if (current && (char*)current + block_size <= (char*)seg->end) {
|
|||
|
|
seg->current = (char*)current + block_size;
|
|||
|
|
seg->used_count++;
|
|||
|
|
return current;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Allocate new segment
|
|||
|
|
return segment_alloc_new(seg, block_size);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void mid_mt_free(void* ptr, size_t size) {
|
|||
|
|
if (!ptr) return;
|
|||
|
|
|
|||
|
|
int class_idx = size_to_mid_class(size);
|
|||
|
|
if (class_idx < 0) return;
|
|||
|
|
|
|||
|
|
MidThreadSegment* seg = &g_mid_segments[class_idx];
|
|||
|
|
|
|||
|
|
// Push to free list
|
|||
|
|
*(void**)ptr = seg->free_list;
|
|||
|
|
seg->free_list = ptr;
|
|||
|
|
seg->used_count--;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 1.2 メインルーティングの変更
|
|||
|
|
|
|||
|
|
**`core/hakmem.c`** - malloc/free にルーティング追加
|
|||
|
|
```c
|
|||
|
|
#include "hakmem_mid_mt.h"
|
|||
|
|
|
|||
|
|
void* malloc(size_t size) {
|
|||
|
|
// ... recursion guard etc ...
|
|||
|
|
|
|||
|
|
// Size-based routing
|
|||
|
|
if (size <= TINY_MAX_SIZE) { // ≤1KB
|
|||
|
|
return hak_tiny_alloc(size);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (size <= 32768) { // 8-32KB: Mid Range MT
|
|||
|
|
return mid_mt_alloc(size);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ≥64KB: Existing L2.5/Whale (学習ベース)
|
|||
|
|
return hak_alloc_at(size, HAK_CALLSITE());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void free(void* ptr) {
|
|||
|
|
if (!ptr) return;
|
|||
|
|
|
|||
|
|
// ... recursion guard etc ...
|
|||
|
|
|
|||
|
|
// Determine pool by size lookup
|
|||
|
|
size_t size = hak_usable_size(ptr); // Need to implement
|
|||
|
|
|
|||
|
|
if (size <= TINY_MAX_SIZE) {
|
|||
|
|
hak_tiny_free(ptr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (size <= 32768) {
|
|||
|
|
mid_mt_free(ptr, size);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ≥64KB: Existing free path
|
|||
|
|
hak_free_at(ptr, 0, HAK_CALLSITE());
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 1.3 サイズ検索の実装
|
|||
|
|
|
|||
|
|
**`core/hakmem_mid_mt.c`** - segment registry
|
|||
|
|
```c
|
|||
|
|
// Simple segment registry (for size lookup in free)
|
|||
|
|
typedef struct {
|
|||
|
|
void* segment_base;
|
|||
|
|
size_t block_size;
|
|||
|
|
} SegmentInfo;
|
|||
|
|
|
|||
|
|
#define MAX_SEGMENTS 1024
|
|||
|
|
static SegmentInfo g_segment_registry[MAX_SEGMENTS];
|
|||
|
|
static int g_segment_count = 0;
|
|||
|
|
|
|||
|
|
static void register_segment(void* base, size_t block_size) {
|
|||
|
|
if (g_segment_count < MAX_SEGMENTS) {
|
|||
|
|
g_segment_registry[g_segment_count].segment_base = base;
|
|||
|
|
g_segment_registry[g_segment_count].block_size = block_size;
|
|||
|
|
g_segment_count++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static size_t lookup_segment_size(void* ptr) {
|
|||
|
|
for (int i = 0; i < g_segment_count; i++) {
|
|||
|
|
void* base = g_segment_registry[i].segment_base;
|
|||
|
|
if (ptr >= base && ptr < (char*)base + SEGMENT_SIZE) {
|
|||
|
|
return g_segment_registry[i].block_size;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return 0; // Not found
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 作業工数
|
|||
|
|
- Day 1-2: ファイル作成、基本実装
|
|||
|
|
- Day 3-4: ルーティング統合、テスト
|
|||
|
|
- Day 5: ベンチマーク、チューニング
|
|||
|
|
- Day 6-7: バグ修正、最適化
|
|||
|
|
|
|||
|
|
### 成功基準
|
|||
|
|
- ✅ mid_large_mt: 100+ M ops/s(mimalloc の 82%以上)
|
|||
|
|
- ✅ 他のベンチマークへの影響なし
|
|||
|
|
- ✅ 学習層(64KB以上)は無変更
|
|||
|
|
|
|||
|
|
### リスク管理
|
|||
|
|
- サイズ検索のオーバーヘッド → segment registry で解決
|
|||
|
|
- メモリオーバーヘッド → 64KB chunk(mimalloc並み)
|
|||
|
|
- スレッド数が多い場合 → 各スレッド独立、問題なし
|
|||
|
|
|
|||
|
|
詳細設計: `docs/design/MID_RANGE_MT_DESIGN.md`(次に作成)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 Phase 2: ChatGPT Pro P1-P2(中優先、3-5日)
|
|||
|
|
|
|||
|
|
### 目標
|
|||
|
|
- Random Mixed: 22.5M → 24M (+7%)
|
|||
|
|
- Tiny Hot: 215M → 220M (+2%)
|
|||
|
|
|
|||
|
|
### 実装項目
|
|||
|
|
|
|||
|
|
#### 2.1 P1: Quick補充の粒度可変化
|
|||
|
|
|
|||
|
|
**現状**: `quick_refill_from_sll` は最大2個
|
|||
|
|
```c
|
|||
|
|
if (room > 2) room = 2; // 固定
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**改善**: `g_frontend_fill_target` による動的調整
|
|||
|
|
```c
|
|||
|
|
int target = g_frontend_fill_target[class_idx];
|
|||
|
|
if (room > target) room = target;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: +1-2%
|
|||
|
|
|
|||
|
|
#### 2.2 P2: Remote Freeしきい値最適化
|
|||
|
|
|
|||
|
|
**現状**: 全クラス共通の `g_remote_drain_thresh`
|
|||
|
|
|
|||
|
|
**改善**: クラス別しきい値テーブル
|
|||
|
|
```c
|
|||
|
|
// Hot classes (0-2): 高しきい値(バースト吸収)
|
|||
|
|
static const int g_remote_thresh[TINY_NUM_CLASSES] = {
|
|||
|
|
64, // class 0: 8B
|
|||
|
|
64, // class 1: 16B
|
|||
|
|
64, // class 2: 32B
|
|||
|
|
32, // class 3: 64B
|
|||
|
|
16, // class 4+: 即時性優先
|
|||
|
|
// ...
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: MT性能 +2-3%
|
|||
|
|
|
|||
|
|
### 作業工数
|
|||
|
|
- Day 1-2: P1実装、テスト
|
|||
|
|
- Day 3: P2実装、テスト
|
|||
|
|
- Day 4-5: ベンチマーク、チューニング
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📈 Phase 3: Long-term Improvements(長期、1-2ヶ月)
|
|||
|
|
|
|||
|
|
### ChatGPT Pro P3: Bundle ノード
|
|||
|
|
|
|||
|
|
**対象**: 64KB以上の Large Pool
|
|||
|
|
|
|||
|
|
**実装**: Transfer Cache方式(tcmalloc風)
|
|||
|
|
```c
|
|||
|
|
// Bundle node: 32/64個を1ノードに
|
|||
|
|
typedef struct BundleNode {
|
|||
|
|
void* items[64];
|
|||
|
|
int count;
|
|||
|
|
struct BundleNode* next;
|
|||
|
|
} BundleNode;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: MT性能 +5-10%(CAS回数削減)
|
|||
|
|
|
|||
|
|
### ChatGPT Pro P5: UCB1自動調整
|
|||
|
|
|
|||
|
|
**対象**: パラメータ自動チューニング
|
|||
|
|
|
|||
|
|
**実装**: 既存 `hakmem_ucb1.c` を活用
|
|||
|
|
- Frontend fill target
|
|||
|
|
- Quick rush size
|
|||
|
|
- Magazine capacity
|
|||
|
|
|
|||
|
|
**期待効果**: +3-5%(長期的にワークロード適応)
|
|||
|
|
|
|||
|
|
### ChatGPT Pro P6: NUMA/CPUシャーディング
|
|||
|
|
|
|||
|
|
**対象**: Large Pool(64KB以上)
|
|||
|
|
|
|||
|
|
**実装**: NUMA node単位で Pool 分割
|
|||
|
|
```c
|
|||
|
|
// NUMA-aware pool
|
|||
|
|
int node = numa_node_of_cpu(cpu);
|
|||
|
|
LargePool* pool = &g_large_pools[node];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待効果**: MT性能 +10-20%(ロック競合削減)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 最終目標(Phase 1-3完了後)
|
|||
|
|
|
|||
|
|
| ベンチマーク | 現状 | Phase 1後 | Phase 2後 | Phase 3後 |
|
|||
|
|
|------------|------|-----------|-----------|-----------|
|
|||
|
|
| **Tiny Hot** | 215 M | 215 M | 220 M | 225 M |
|
|||
|
|
| **Random Mixed** | 22.5 M | 23 M | 24 M | 25 M |
|
|||
|
|
| **mid_large_mt** | 46 M | **110 M** | 115 M | 130 M |
|
|||
|
|
|
|||
|
|
**総合評価**: mimalloc と同等~上回る性能を達成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 実装優先度まとめ
|
|||
|
|
|
|||
|
|
### 今週(最優先)
|
|||
|
|
1. ✅ ドキュメント更新(完了)
|
|||
|
|
2. 🔥 **Phase 1: Mid Range MT最適化**(始める)
|
|||
|
|
- Day 1-2: 設計ドキュメント + 基本実装
|
|||
|
|
- Day 3-4: 統合 + テスト
|
|||
|
|
- Day 5-7: ベンチマーク + 最適化
|
|||
|
|
|
|||
|
|
### 来週
|
|||
|
|
3. Phase 2: ChatGPT Pro P1-P2(3-5日)
|
|||
|
|
|
|||
|
|
### 長期(1-2ヶ月)
|
|||
|
|
4. Phase 3: P3, P5, P6
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🤔 設計原則(ハイブリッド案)
|
|||
|
|
|
|||
|
|
### 1. 領域別の最適化戦略
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
≤1KB (Tiny) → 静的最適化(学習不要)
|
|||
|
|
P0完了、これ以上の改善は限定的
|
|||
|
|
|
|||
|
|
8-32KB (Mid) → MT性能最優先(学習不要)
|
|||
|
|
mimalloc風 per-thread segment
|
|||
|
|
|
|||
|
|
≥64KB (Large) → 学習ベース(ELO戦略)
|
|||
|
|
ワークロード適応が効果的
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 学習層の役割
|
|||
|
|
|
|||
|
|
- **Tiny**: 学習しない(P0で最適化完了)
|
|||
|
|
- **Mid**: 学習しない(mimalloc風に移行)
|
|||
|
|
- **Large**: 学習が主役(ELO戦略選択)
|
|||
|
|
|
|||
|
|
→ 学習層のオーバーヘッドを最小化、効果的な領域に集中
|
|||
|
|
|
|||
|
|
### 3. トレードオフ
|
|||
|
|
|
|||
|
|
**mimalloc 真似(全面)**:
|
|||
|
|
- ✅ MT性能最高
|
|||
|
|
- ❌ 学習層が死ぬ
|
|||
|
|
- ❌ hakmem の差別化ポイント喪失
|
|||
|
|
|
|||
|
|
**ChatGPT Pro(全面)**:
|
|||
|
|
- ✅ 学習層が活きる
|
|||
|
|
- ❌ MT性能が届かない
|
|||
|
|
|
|||
|
|
**ハイブリッド(採用)**:
|
|||
|
|
- ✅ MT性能最高(8-32KB)
|
|||
|
|
- ✅ 学習層保持(≥64KB)
|
|||
|
|
- ✅ 段階的実装
|
|||
|
|
- ✅ **両者の良いとこ取り**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📚 参考資料
|
|||
|
|
|
|||
|
|
- `NEXT_STEP_ANALYSIS.md` - ハイブリッド案の詳細分析
|
|||
|
|
- `P0_SUCCESS_REPORT.md` - P0実装成功レポート
|
|||
|
|
- `3LAYER_FAILURE_ANALYSIS.md` - 3層アーキテクチャ失敗分析
|
|||
|
|
- `docs/analysis/CHATGPT_PRO_ULTRATHINK_RESPONSE.md` - ChatGPT Pro 推奨
|
|||
|
|
- `docs/design/MID_RANGE_MT_DESIGN.md` - Mid Range MT設計(次に作成)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**最終更新**: 2025-11-01
|
|||
|
|
**ステータス**: Phase 0完了(P0)、Phase 1準備中(Mid Range MT)
|
|||
|
|
**次のアクション**: Mid Range MT 設計ドキュメント作成 → 実装開始
|