Files
hakmem/docs/status/PHASE_6.22_RESULTS_2025_10_24.md

439 lines
13 KiB
Markdown
Raw Normal View History

# Phase 6.22: SuperSlab 実装(基盤構築フェーズ)
**日付**: 2025-10-24
**ステータス**: ✅ **Phase 6.22-A/B 完了** (基盤準備済み、未稼働)
**目標**: mimalloc-inspired SuperSlab architecture 実装
**期待効果**: +10-15% (Tiny 1T/4T) ※Phase 6.23 で稼働時
---
## 📋 Overview
Phase 6.22 では、mimalloc の Segment-Aligned Allocation 手法を参考に、hakmem Tiny Pool 用の **SuperSlab** アーキテクチャを実装しました。これは 2MB aligned memory 上に 32 個の 64KB slab を配置し、pointer → slab の高速変換1 AND 演算)を実現します。
### Phase 6.22 分割実装
| Sub-Phase | 内容 | ステータス |
|-----------|------|-----------|
| **6.22-A** | SuperSlab 構造体定義 + 2MB allocator | ✅ 完了 |
| **6.22-B** | Free path への SuperSlab 統合 | ✅ 完了(未稼働) |
| **6.23** | Allocation path 統合 + Per-thread queues | 🔜 次回 |
---
## 🏗️ Phase 6.22-A: SuperSlab 基盤実装
### 実装内容
#### 1. SuperSlab 構造体定義 (`hakmem_tiny_superslab.h`)
```c
#define SUPERSLAB_SIZE (2 * 1024 * 1024) // 2MB (mimalloc-style)
#define SUPERSLAB_MASK (SUPERSLAB_SIZE - 1)
#define SLAB_SIZE (64 * 1024) // 64KB per slab
#define SLABS_PER_SUPERSLAB 32 // 2MB / 64KB = 32
typedef struct TinySlabMeta {
void* freelist; // Freelist head (8B)
uint16_t used; // Blocks currently used (2B)
uint16_t capacity; // Total blocks in slab (2B)
uint32_t owner_tid; // Owner thread ID (4B)
} TinySlabMeta; // Total: 16B per slab
typedef struct SuperSlab {
// Header (64B)
uint64_t magic; // 0x48414B4D454D5353 ("HAKMEMSS")
uint8_t size_class; // 0-7 (8-64B)
uint8_t active_slabs; // Number of active slabs (0-32)
uint32_t slab_bitmap; // 32-bit bitmap (1=active, 0=free)
// Per-slab metadata (32 x 16B = 512B)
TinySlabMeta slabs[32];
} __attribute__((aligned(64))) SuperSlab;
```
#### 2. Fast Inline Functions (mimalloc-style)
```c
// Get SuperSlab from pointer (1 AND operation)
static inline SuperSlab* ptr_to_superslab(void* p) {
return (SuperSlab*)((uintptr_t)p & ~(uintptr_t)SUPERSLAB_MASK);
}
// Get slab index within SuperSlab (1 shift operation)
static inline int ptr_to_slab_index(void* p) {
uintptr_t offset = (uintptr_t)p & SUPERSLAB_MASK;
return (int)(offset >> 16); // Divide by 64KB (2^16)
}
// Get slab metadata from pointer (2 operations)
static inline TinySlabMeta* ptr_to_slab_meta(void* p) {
SuperSlab* ss = ptr_to_superslab(p);
int idx = ptr_to_slab_index(p);
return &ss->slabs[idx];
}
```
#### 3. 2MB Aligned Allocator (`hakmem_tiny_superslab.c`)
```c
SuperSlab* superslab_allocate(uint8_t size_class) {
// 1. Try MAP_ALIGNED_SUPER (if available)
#ifdef MAP_ALIGNED_SUPER
ptr = mmap(NULL, SUPERSLAB_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0);
#endif
// 2. Fallback: Manual alignment
size_t alloc_size = SUPERSLAB_SIZE * 2; // 4MB
void* raw = mmap(NULL, alloc_size, ...);
// Align to 2MB boundary
uintptr_t aligned_addr = (raw_addr + SUPERSLAB_MASK) & ~SUPERSLAB_MASK;
// Unmap unused regions (prefix/suffix)
munmap(prefix_region, prefix_size);
munmap(suffix_region, suffix_size);
// Initialize SuperSlab header
ss->magic = SUPERSLAB_MAGIC;
ss->size_class = size_class;
ss->active_slabs = 0;
ss->slab_bitmap = 0;
return ss;
}
```
### Makefile 統合
```makefile
# Line 14
OBJS = ... hakmem_tiny_superslab.o ...
# Line 18
SHARED_OBJS = ... hakmem_tiny_superslab_shared.o ...
# Line 23
BENCH_HAKMEM_OBJS = ... hakmem_tiny_superslab.o ...
```
### ビルド結果
```
$ make clean && make bench
...
========================================
Build successful!
========================================
```
### Benchmark (Phase 6.21 比較)
| Benchmark | Phase 6.21 | Phase 6.22-A | 変化 | 備考 |
|-----------|------------|--------------|------|------|
| Tiny 1T | 20.1 M/s | 20.0 M/s | -0.5% | コード追加によるわずかな劣化 |
| Tiny 4T | 53.6 M/s | **57.9 M/s** | **+8.0%** | 🎉 **予期しない改善!** |
**驚きの発見**: SuperSlab コードを追加しただけまだ使用していないで、Tiny 4T が +8% 向上!
**推測**: コードサイズ変化によるキャッシュライン配置の偶然の最適化。
---
## 🔧 Phase 6.22-B: SuperSlab Free Path 統合
### 実装内容
#### 1. SuperSlab Fast Free Path (`hakmem_tiny.c:863-875`)
```c
// Phase 6.22-B: SuperSlab fast free path
static inline void hak_tiny_free_superslab(void* ptr, SuperSlab* ss) {
int slab_idx = ptr_to_slab_index(ptr);
TinySlabMeta* meta = &ss->slabs[slab_idx];
// Simple freelist push (no same-thread check for now)
*(void**)ptr = meta->freelist;
meta->freelist = ptr;
meta->used--;
}
```
#### 2. Free Function 統合 (`hakmem_tiny.c:877-893`)
```c
void hak_tiny_free(void* ptr) {
if (!ptr || !g_tiny_initialized) return;
// Phase 6.22-B: Try SuperSlab fast path first
SuperSlab* ss = ptr_to_superslab(ptr);
if (ss && ss->magic == SUPERSLAB_MAGIC) {
hak_tiny_free_superslab(ptr, ss);
return; // Fast path exit
}
// Fallback to Registry lookup (existing path)
TinySlab* slab = hak_tiny_owner_slab(ptr);
if (!slab) return;
hak_tiny_free_with_slab(ptr, slab);
}
```
### 現在の動作
- ✅ SuperSlab free path のコードは実装済み
- ❌ SuperSlab allocation がまだ未実装のため、**実際には実行されない**
- ✅ Registry ベースの allocation/free が継続動作中
- ✅ Backward compatibility 維持
### Benchmark (Phase 6.22-A 比較)
| Benchmark | Phase 6.22-A | Phase 6.22-B | 変化 | 備考 |
|-----------|--------------|--------------|------|------|
| Tiny 1T | 20.0 M/s | 20.0 M/s | 0% | 変化なし(期待通り) |
| Tiny 4T | 57.9 M/s | 57.3 M/s | -1% | わずかな劣化(期待通り) |
**結果**: SuperSlab free path は未実行のため、性能は横ばい(期待通り)。
---
## 📊 Performance Comparison
### Phase 6.20 → 6.21 → 6.22 推移
| Benchmark | 6.20 | 6.21 | 6.22-A | 6.22-B | 変化 (6.20→6.22) |
|-----------|------|------|--------|--------|------------------|
| Tiny 1T | 20.1 | 20.1 | 20.0 | 20.0 | -0.5% |
| Tiny 4T | 53.6 | 53.6 | 57.9 | 57.3 | **+6.9%** 🎉 |
| Mid 1T | 3.86 | 3.86 | 3.87 | - | +0.3% |
| Mid 4T | 8.36 | 8.37 | 8.33 | - | -0.4% |
| Large 1T | 0.54 | 0.54 | 0.54 | - | 0% |
| Large 4T | 1.27 | 1.27 | 1.27 | - | 0% |
### vs mimalloc (Phase 6.22-B)
| Benchmark | hakmem | mimalloc | 達成率 |
|-----------|--------|----------|--------|
| Tiny 1T | 20.0 M/s | 33.8 M/s | **59%** |
| Tiny 4T | 57.3 M/s | 76.5 M/s | **75%** |
**Phase 6.23 目標**: Tiny 1T/4T で +10-15% → 達成率 65-70% / 82-86%
---
## 🎯 Technical Achievements
### ✅ 完了した項目
1. **SuperSlab 構造体設計**
- 2MB aligned memory layout
- 32 x 64KB slab structure
- Per-slab metadata (16B each)
- Magic number validation
2. **2MB Aligned Allocator**
- MAP_ALIGNED_SUPER サポート
- Manual alignment fallback (4MB allocation)
- Unused region unmapping
- Global statistics tracking
3. **Fast Pointer Arithmetic**
- `ptr_to_superslab()`: 1 AND operation
- `ptr_to_slab_index()`: 1 shift operation
- `ptr_to_slab_meta()`: 2 operations total
4. **Free Path Integration**
- SuperSlab magic check
- Fast freelist push
- Registry fallback 維持
5. **Makefile Integration**
- Static/shared library builds
- Benchmark integration
- Dependency tracking
### ⏳ 未実装項目 (Phase 6.23 へ)
1. **SuperSlab Allocation Path**
- `refill_from_superslab()` 実装
- TLS active slab 統合
- Initial slab initialization
2. **Same-Thread Fast Path**
- Owner TID check
- Lock-free allocation/free
3. **Remote Free Handling**
- Per-thread remote queues
- Cross-thread freelist
4. **Registry Migration**
- SuperSlab への完全移行
- または Hybrid 運用
---
## 🚀 Next Steps: Phase 6.23
### 実装計画
#### Step 1: SuperSlab Allocation Path (1-2時間)
```c
void* hak_tiny_alloc(size_t size) {
int class_idx = SIZE_TO_CLASS[size >> 3];
TinyTLS* tls = get_tls();
// 1. Try TLS active slab
TinySlab* active = tls->active_slab[class_idx];
if (!active || !active->freelist) {
// 2. Refill from SuperSlab
active = refill_from_superslab(class_idx);
if (!active) return NULL;
tls->active_slab[class_idx] = active;
}
// 3. Pop from freelist
void* block = active->freelist;
active->freelist = *(void**)block;
active->used++;
return block;
}
TinySlab* refill_from_superslab(int class_idx) {
// 1. Allocate new SuperSlab
SuperSlab* ss = superslab_allocate(class_idx);
if (!ss) return NULL;
// 2. Initialize first slab
uint32_t my_tid = (uint32_t)(uintptr_t)pthread_self();
superslab_init_slab(ss, 0, g_class_sizes[class_idx], my_tid);
// 3. Return slab metadata
return convert_to_tinyslab(&ss->slabs[0]);
}
```
#### Step 2: Same-Thread Fast Path
```c
void hak_tiny_free_superslab(void* ptr, SuperSlab* ss) {
int slab_idx = ptr_to_slab_index(ptr);
TinySlabMeta* meta = &ss->slabs[slab_idx];
// Same-thread check
uint64_t my_tid = (uint64_t)(uintptr_t)pthread_self();
if (meta->owner_tid == (uint32_t)my_tid) {
// Fast path: Direct freelist push
*(void**)ptr = meta->freelist;
meta->freelist = ptr;
meta->used--;
} else {
// Slow path: Remote free queue
remote_free_superslab(ss, slab_idx, ptr);
}
}
```
#### Step 3: Per-Thread Remote Queues
```c
typedef struct RemoteFreeQueue {
void* head;
void* tail;
uint32_t count;
} RemoteFreeQueue;
typedef struct TinyTLS {
TinySlab* active_slab[8];
RemoteFreeQueue remote_queue[8]; // Per size class
} TinyTLS;
```
### 期待される性能向上
| Benchmark | Phase 6.22-B | Phase 6.23 目標 | 改善幅 |
|-----------|--------------|-----------------|--------|
| Tiny 1T | 20.0 M/s | **22-23 M/s** | +10-15% |
| Tiny 4T | 57.3 M/s | **63-67 M/s** | +10-17% |
### vs mimalloc 予測
| Benchmark | Phase 6.23 目標 | mimalloc | 達成率 |
|-----------|-----------------|----------|--------|
| Tiny 1T | 22-23 M/s | 33.8 M/s | **65-68%** |
| Tiny 4T | 63-67 M/s | 76.5 M/s | **82-88%** |
---
## 📝 Lessons Learned
### 1. Code Size が性能に影響
Phase 6.22-A でコードを追加しただけで Tiny 4T が +8% 向上した事例から、コードサイズ変化がキャッシュライン配置に影響を与えることを確認。
**教訓**: 性能測定は常にフルビルドで行うべき。Incremental build では予期しない性能変化が起こりうる。
### 2. Hybrid Approach の有効性
SuperSlab と Registry を並行運用することで、段階的な移行が可能。Backward compatibility を維持しながら新機能を実装できる。
**教訓**: Big Bang リライトではなく、Incremental migration が安全。
### 3. mimalloc の設計思想
Segment-Aligned Allocation は単なる最適化ではなく、アーキテクチャ全体の設計思想。Fast pointer arithmetic により、メタデータアクセスのコストを最小化。
**教訓**: "Fast path を極限まで速く" という mimalloc の哲学を学ぶ。
---
## 📂 File Changes Summary
### 新規ファイル
| ファイル | 行数 | 内容 |
|---------|------|------|
| `hakmem_tiny_superslab.h` | 117 | SuperSlab 構造体定義 + inline 関数 |
| `hakmem_tiny_superslab.c` | 231 | 2MB allocator 実装 |
| `docs/status/PHASE_6.22_PLAN_2025_10_24.md` | 467 | Phase 6.22 実装計画 |
| `docs/status/PHASE_6.22B_PLAN_2025_10_24.md` | 278 | Phase 6.22-B 実装計画 |
### 変更ファイル
| ファイル | 変更内容 |
|---------|----------|
| `Makefile` | hakmem_tiny_superslab.o 追加 |
| `hakmem_tiny.c` | SuperSlab free path 統合 (lines 863-893) |
### 合計
- **新規**: 4 ファイル, 1093 行
- **変更**: 2 ファイル, ~20 行
- **Total**: 約 1100 行の追加
---
## 🎉 Conclusion
Phase 6.22 では、mimalloc の Segment-Aligned Allocation 手法を参考に、SuperSlab アーキテクチャの**基盤構築**を完了しました。
### 主な成果
1. ✅ 2MB aligned SuperSlab allocator 実装
2. ✅ Fast pointer arithmetic (1-2 操作)
3. ✅ Free path への SuperSlab 統合
4. ✅ Backward compatibility 維持
5. ✅ Tiny 4T で +7% 改善(副次効果)
### 次のステップ
Phase 6.23 で SuperSlab allocation path を実装し、**+10-15%** の性能向上を目指します。
---
**作成日**: 2025-10-24 12:05 JST
**次のフェーズ**: Phase 6.23 (SuperSlab Allocation + Per-thread Queues)
**目標**: Tiny 1T/4T で mimalloc の 65-88% 達成