Files
hakmem/CURRENT_TASK.md
Moe Charm (CI) 5b36c1c908 Phase 26: Front Gate Unification - Tiny allocator fast path (+12.9%)
Implementation:
- New single-layer malloc/free path for Tiny (≤1024B) allocations
- Bypasses 3-layer overhead: malloc → hak_alloc_at (236 lines) → wrapper → tiny_alloc_fast
- Leverages Phase 23 Unified Cache (tcache-style, 2-3 cache misses)
- Safe fallback to normal path on Unified Cache miss

Performance (Random Mixed 256B, 100K iterations):
- Baseline (Phase 26 OFF): 11.33M ops/s
- Phase 26 ON: 12.79M ops/s (+12.9%)
- Prediction (ChatGPT): +10-15% → Actual: +12.9% (perfect match!)

Bug fixes:
- Initialization bug: Added hak_init() call before fast path
- Page boundary SEGV: Added guard for offset_in_page == 0

Also includes Phase 23 debug log fixes:
- Guard C2_CARVE logs with #if !HAKMEM_BUILD_RELEASE
- Guard prewarm logs with #if !HAKMEM_BUILD_RELEASE
- Set Hot_2048 as default capacity (C2/C3=2048, others=64)

Files:
- core/front/malloc_tiny_fast.h: Phase 26 implementation (145 lines)
- core/box/hak_wrappers.inc.h: Fast path integration (+28 lines)
- core/front/tiny_unified_cache.h: Hot_2048 default
- core/tiny_refill_opt.h: C2_CARVE log guard
- core/box/ss_hot_prewarm_box.c: Prewarm log guard
- CURRENT_TASK.md: Phase 26 completion documentation

ENV variables:
- HAKMEM_FRONT_GATE_UNIFIED=1 (enable Phase 26, default: OFF)
- HAKMEM_TINY_UNIFIED_CACHE=1 (Phase 23, required)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 05:29:08 +09:00

1359 lines
54 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CURRENT TASK (Phase 1426 Snapshot) Tiny / Mid / ExternalGuard / Unified Cache / Front Gate
**Last Updated**: 2025-11-17
**Owner**: ChatGPT → Phase 23/25/26 実装完了: Claude Code
**Size**: 約 350 行Claude 用コンテキスト簡略版)
---
## 🎉 **Phase 26: Front Gate Unification - 完了** (2025-11-17)
**成果**: Random Mixed 256B ベンチマーク **+12.9%** 改善 (11.33M → 12.79M ops/s)
### Phase 26: Front Gate Unification (ChatGPT先生提案)
- **設計**: malloc → hak_alloc_at (236行) → wrapper → tiny_alloc_fast の **3層オーバーヘッド削減**
- **実装**: `core/front/malloc_tiny_fast.h` + `core/box/hak_wrappers.inc.h` 統合
- **戦略**: Tiny範囲≤1024B専用の単層直行経路、Phase 23 Unified Cache 活用
- **ENV**: `HAKMEM_FRONT_GATE_UNIFIED=1` でデフォルトOFF → **本番投入推奨**
### Phase 26 実装詳細
**malloc_tiny_fast()** (alloc fast path):
```c
1. size class_idx (inline table lookup, 1-2 instructions)
2. unified_cache_pop_or_refill(class_idx) (Phase 23 tcache, 2-3 cache misses)
3. Write header + return USER pointer (2-3 instructions)
Total: 8-10 instructions (vs 3-layer cascade: 236 lines routing + diagnostics)
```
**free_tiny_fast()** (free fast path):
```c
1. Page boundary guard (offset_in_page == 0 return 0)
2. Read header + validate Tiny magic (0xa0-0xa7)
3. unified_cache_push(class_idx, base) (Phase 23 tcache, 2-3 cache misses)
Total: 6-8 instructions (vs classify_ptr + hak_free_at routing)
```
### Phase 26 修正したバグ
1. **初期化バグ**: Phase 26 fast path が hak_init() をバイパス → `if (!g_initialized) hak_init()` 追加
2. **ページ境界SEGV**: free_tiny_fast() がページ先頭 (offset==0) で前ページ読み → ガード追加
```c
uintptr_t off = (uintptr_t)ptr & 0xFFFu;
if (off == 0) return 0; // Page-aligned → 通常 free 経路へ
```
### A/B ベンチマーク結果 (Random Mixed 256B, 100K iterations)
| Configuration | Run 1 | Run 2 | Run 3 | **Average** | vs Baseline |
|---------------|-------|-------|-------|-------------|-------------|
| **Phase 26 OFF** | 11.21M | 11.02M | 11.76M | **11.33M ops/s** | Baseline |
| **Phase 26 ON** | 13.21M | 12.55M | 12.62M | **12.79M ops/s** | **+12.9%** 🎯 |
**ChatGPT先生の予測**: +10-15% (3層オーバーヘッド削減による改善)
**実測結果**: **+12.9%** ← **予測ど真ん中!** 🎯
### 本番推奨設定 (Phase 23 + Phase 26 組み合わせ)
```bash
export HAKMEM_TINY_UNIFIED_CACHE=1 # Phase 23: Hot_2048がデフォルト
export HAKMEM_FRONT_GATE_UNIFIED=1 # Phase 26: Front Gate Unification
./out/release/bench_random_mixed_hakmem
# Expected: 12.79M ops/s (+27.8% vs Phase 23前のbaseline 10.0M ops/s)
```
**主要ファイル**:
- `core/front/malloc_tiny_fast.h` - Phase 26 single-layer malloc/free implementation
- `core/box/hak_wrappers.inc.h:128-143` - Phase 26 fast path integration (malloc)
- `core/box/hak_wrappers.inc.h:179-190` - Phase 26 fast path integration (free)
---
## 🎉 **Phase 23/25: Unified Frontend Cache - 完了** (2025-11-17)
**成果**: Random Mixed 256B ベンチマーク **+7.3%** 改善 (10.58M → 11.35M ops/s)
### Phase 23: Unified Cache Implementation
- **設計**: tcache-style single-layer frontend (Ring → FastCache → SFC → SLL の 4 層を 1 層に統合)
- **実装**: `core/front/tiny_unified_cache.{h,c}` - Array-based ring buffer (2-3 cache misses)
- **統合**: Alloc path (`tiny_alloc_fast.inc.h:621-633`) + Free path (`hak_free_api.inc.h`)
- **ENV**: `HAKMEM_TINY_UNIFIED_CACHE=1` でデフォルトOFF → **Hot_2048設定で本番投入**
### Phase 23 Capacity Optimization (Hot_2048)
- **Task Agent**: 10 configurations × 3 runs = 35 benchmarks
- **最適設定**: C2/C3 (128B/256B) = 2048 slots, 他 = 64 slots
- **根拠**: Hot-class優先戦略が+6.2%の追加改善vs All_128
- **メモリ**: ~1.1MB cache overhead (C2/C3 に集中配置)
### Phase 25-A: Header Read Optimization (+2.2%)
- **削減**: FG_DOMAIN_TINY の重複 header read を除去
- **L1 hit**: 2回目の header read は L1 cache hit (~1 cycle) → 効果限定的
### Phase 25-B-1: Promote-on-Full (REVERTED, -4.0%)
- **失敗**: Smart promotion logic が overhead > benefit
- **教訓**: Clever ≠ Fast、incremental最適化は限界に達した
### Debug Log修正 (性能改善)
- **修正箇所**: `core/tiny_refill_opt.h:316-326`, `core/box/ss_hot_prewarm_box.c:143-146`
- **問題**: `[C2_CARVE]` / `[BOX_SS_HOT_PREWARM]` が Release build で常時出力
- **解決**: `#if !HAKMEM_BUILD_RELEASE` で囲み、stderr負荷を除去
### 本番推奨設定
```bash
export HAKMEM_TINY_UNIFIED_CACHE=1 # Hot_2048がデフォルトC2/C3=2048, 他=64
./out/release/bench_random_mixed_hakmem
```
**次の戦略**: Phase 23でfrontend最適化は限界、Phase 12 Shared SuperSlab Pool (backend根本解決) へ進む
---
## 1. 全体の現在地(どこまで終わっているか)
- Tiny (01023B)
- NEW 3-layer frontbump / small_mag / slow安定。
- TinyHeapV2: 「alloc フロント+統計」は実装済みだが、実運用は **C2/C3 を UltraHot に委譲**。
- TinyUltraHotPhase 14:
- C2/C316B/32B専用 L0 ultra-fast pathStealing モデル)。
- 固定サイズベンチで +16〜36% 改善、hit 率 ≈ 100%。
- Box 分離Phase 15:
- free ラッパが外部ポインタまで `hak_free_at` に投げていた問題を修正。
- BenchMetaslots など)→ 直接 `__libc_free`、CoreAllocTiny/Mid→ `hak_free_at` の二段構えに整理。
- Mid / PoolTLS1KB32KB
- PoolTLS Phase 完了Mid-Large MT ベンチ)
- ~10.6M ops/ssystem malloc より速い構成あり)。
- lock contentionfutex 68%)を lock-free MPSC + bind box で大幅削減。
- GAP 修正Tiny 1023B / Mid 1KB〜:
- `TINY_MAX_SIZE=1023` / `MID_MIN_SIZE=1024` で 1KB8KB の「誰も扱わない帯」は解消済み。
- Shared SuperSlab PoolPhase 12 SP-SLOT Box
- 1 SuperSlab : 多 class 共有 + SLOT_UNUSED/ACTIVE/EMPTY 追跡。
- SuperSlab 数: 877 → 72-92%、mmap/munmap: -48%、Throughput: +131%。
- Lock contention P0-5 まで実装済みStage 2 lock-free claiming
- ExternalGuardPhase 15
- UNKNOWN ポインタTiny/Pool/Mid/L25/registry どこでも捕まらないもの)を最後の箱で扱う。
- 挙動:
- `hak_super_lookup` など全て miss → mincore でページ確認 → 原則「解放せず leak 扱い(安全優先)」。
- Phase 15 修正で:
- BenchMeta のポインタを CoreAlloc に渡さなくなり、UNKNOWN 呼び出し回数が激減。
- `mincore` の CPU 負荷もベンチではほぼ無視できるレベルまで縮小。
---
## 2. Tiny 性能の現状Phase 1415 時点)
### 2.1 Fixed-size Tiny ベンチHAKMEM vs System
**Phase 21-1: Ring Cache Implementation (C2/C3/C5) (2025-11-16)** 🎯
- **Goal**: Eliminate pointer chasing in TLS SLL by using array-based ring buffer cache
- **Strategy**: 3-layer hierarchy (Ring L0 → SLL L1 → SuperSlab L2)
- **Implementation**:
- Added `TinyRingCache` struct with power-of-2 ring buffer (128 slots default)
- Implemented `ring_cache_pop/push` for ultra-fast alloc/free (1-2 instructions)
- Extended to C2 (32B), C3 (64B), C5 (256B) size classes
- ENV variables: `HAKMEM_TINY_HOT_RING_ENABLE=1`, `HAKMEM_TINY_HOT_RING_C2/C3/C5=128`
- **Results** (`bench_random_mixed_hakmem 500K, 256B workload`):
- **Baseline** (Ring OFF): 20.18M ops/s
- **C2/C3 Ring**: 21.15M ops/s (**+4.8%** improvement) ✅
- **C2/C3/C5 Ring**: 21.18M ops/s (**+5.0%** total improvement) ✅
- **Analysis**:
- C2/C3 provide most of the gain (small sizes are hottest)
- C5 addition provides marginal benefit (+0.03M ops/s)
- Implementation complete and stable
- **Files Modified**:
- `core/front/tiny_ring_cache.h/c` - Ring buffer implementation
- `core/tiny_alloc_fast.inc.h` - Alloc path integration
- `core/tiny_free_fast_v2.inc.h` - Free path integration (line 154-160)
---
**Phase 21-1-D: Ring Cache Default ON (2025-11-16)** 🚀
- **Goal**: Enable Ring Cache by default for production use (remove ENV gating)
- **Implementation**: 1-line change in `core/front/tiny_ring_cache.h:72`
- Changed logic: `g_enable = (e && *e == '0') ? 0 : 1; // DEFAULT: ON`
- ENV=0 disables, ENV unset or ENV=1 enables
- **Results** (`bench_random_mixed_hakmem 500K, 256B workload, 3-run average`):
- **Ring ON** (default): **20.31M ops/s** (baseline)
- **Ring OFF** (ENV=0): 19.30M ops/s
- **Improvement**: **+5.2%** (+1.01M ops/s) ✅
- **Impact**: Ring Cache now active in all builds without manual ENV configuration
---
**Performance Bottleneck Analysis (Task-sensei Report, 2025-11-16)** 🔍
**Root Cause: Cache Misses (6.6x worse than System malloc)**
- **L1 D-cache miss rate**: HAKMEM 5.15% vs System 0.78% → **6.6x higher**
- **IPC (instructions/cycle)**: HAKMEM 0.52 vs System 1.43 → **2.75x worse**
- **Branch miss rate**: HAKMEM 11.86% vs System 4.77% → **2.5x higher**
- **Per-operation cost**: HAKMEM **8-10 cache misses** vs System **2-3 cache misses**
**Problem: 4-5 Layer Frontend Cascade**
```
Random Mixed allocation flow:
Ring (L0) miss → FastCache (L1) miss → SFC (L2) miss → TLS SLL (L3) miss → SuperSlab refill (L4)
= 8-10 cache misses per allocation (each layer = 2 misses: head + next pointer)
```
**System malloc tcache: 2-3 cache misses (single-layer array-based bins)**
**Improvement Roadmap** (Target: 48-77M ops/s, System比 53-86%):
1. **P1 (Done)**: Ring Cache default ON → **+5.2%** (20.3M ops/s) ✅
2. **P2 (Next)**: Unified Frontend Cache (flatten 4-5 layers → 1 layer) → **+50-100%** (30-40M expected)
3. **P3**: Adaptive refill optimization → **+20-30%**
4. **P4**: Branchless dispatch table → **+10-15%**
5. **P5**: Metadata locality optimization → **+15-20%**
**Conservative Target**: 48M ops/s (+136% vs current, 53% of System)
**Optimistic Target**: 77M ops/s (+279% vs current, 86% of System)
---
**Phase 22: Lazy Per-Class Initialization (2025-11-16)** 🚀
- **Goal**: Cold-start page faultを削減 (ChatGPT分析: `hak_tiny_init()` → 94.94% of page faults)
- **Strategy**: Eager init (全8クラス初期化) → Lazy init (使用クラスのみ初期化)
- **Results** (`bench_random_mixed_hakmem 500K, 256B workload`):
- **Cold-start**: 18.1M ops/s (Phase 21-1: 16.2M) → **+12% improvement** ✅
- **Steady-state**: 25.5M ops/s (Phase 21-1: 26.1M) → -2.3% (誤差範囲)
- **Key Achievement**: `hak_tiny_init.part.0` 完全削除、未使用クラスのpage touchを回避
- **Remaining Bottleneck**: SuperSlab allocation時の`memset` page fault (42.40%)
---
**📊 PERFORMANCE MAP (2025-11-16) - 全体性能俯瞰** 🗺️
ベンチマーク自動化スクリプト: `scripts/bench_performance_map.sh`
最新結果: `bench_results/performance_map/20251116_095827/`
### 🎯 固定サイズ (16-1024B) - Tiny層の現実
| Size | System | HAKMEM | Ratio | Status |
|------|--------|--------|-------|--------|
| 16B | 118.6M | 50.0M | 42.2% | ❌ Slow |
| 32B | 103.3M | 49.3M | 47.7% | ❌ Slow |
| 64B | 104.3M | 49.2M | 47.1% | ❌ Slow |
| **128B** | **74.0M** | **51.8M** | **70.0%** | **⚠️ Gap** ✨ |
| 256B | 115.7M | 36.2M | 31.3% | ❌ Slow |
| 512B | 103.5M | 41.5M | 40.1% | ❌ Slow |
| 1024B| 96.0M | 47.8M | 49.8% | ❌ Slow |
**発見**:
- **128Bのみ 70%** (唯一Gap範囲) - 他は全て50%未満
- **256Bが最悪 31.3%** - Phase 22で18.1M → 36.2Mに改善したが、systemの1/3に留まる
- **小サイズ (16-64B) 42-47%** - UltraHot経由でも system の半分
### 🌀 Random Mixed (128B-1KB)
| Allocator | ops/s | vs System |
|-----------|--------|-----------|
| System | 90.2M | 100% (baseline) |
| **Mimalloc** | **117.5M** | **130%** 🏆 (systemより速い) |
| **HAKMEM** | **21.1M** | **23.4%** ❌ (mimallocの1/5.5) |
**衝撃的発見**:
- Mimallocは system より 30%速い
- HAKMEMは mimalloc の **1/5.5** - 巨大なギャップ
### 💥 CRITICAL ISSUES - Mid-Large / MT層が完全破壊
**Mid-Large MT (8-32KB)**: ❌ **CRASHED** (コアダンプ)
- **原因**: `hkm_ace_alloc` が 33KB allocation で NULL返却
- **結果**: `free(): invalid pointer` → クラッシュ
- **Mimalloc**: 40.2M ops/s (system の 449%)
- **HAKMEM**: 0 ops/s (動作不能)
**VM Mixed**: ❌ **CRASHED** (コアダンプ)
- System: 957K ops/s
- HAKMEM: 0 ops/s
**Larson (MT churn)**: ❌ **SEGV**
- System: 3.4M ops/s
- Mimalloc: 3.4M ops/s
- HAKMEM: 0 ops/s
---
**🔧 Mid-Large Crash FIX (2025-11-16)** ✅
**Root Cause (ChatGPT分析)**:
- `classify_ptr()` が AllocHeader (Mid/Large mmap allocations) をチェックしていない
- Free wrapper が `PTR_KIND_MID_LARGE` ケースを処理していない
- 結果: Mid-Large ポインタが `PTR_KIND_UNKNOWN` → `__libc_free()` → `free(): invalid pointer`
**修正内容**:
1. **`classify_ptr()` に AllocHeader チェック追加** (`core/box/front_gate_classifier.c:256-271`)
- `hak_header_from_user()` + `hak_header_validate()` で HAKMEM_MAGIC 確認
- `ALLOC_METHOD_MMAP/POOL/L25_POOL` → `PTR_KIND_MID_LARGE` 返却
2. **Free wrapper に `PTR_KIND_MID_LARGE` ケース追加** (`core/box/hak_wrappers.inc.h:181`)
- `is_hakmem_owned = 1` で HAKMEM 管轄として処理
**修正結果**:
- **Mid-Large MT (8-32KB)**: 0 → **10.5M ops/s** (System 8.7M = **120%**) 🏆
- **VM Mixed**: 0 → **285K ops/s** (System 939K = 30.4%)
- ✅ クラッシュ完全解消、Mid-Large で system malloc を **20% 上回る**
**残存課題**:
- ❌ **random_mixed**: SEGV (AllocHeader読み込みでページ境界越え)
- ❌ **Larson**: SEGV継続 (Tiny 8-128B 領域、別原因)
---
**🔧 random_mixed Crash FIX (2025-11-16)** ✅
**Root Cause**:
- Mid-Large fix で追加した `classify_ptr()` の AllocHeader check が unsafe
- AllocHeader = 40 bytes → `ptr - 40` がページ境界越えると SEGV
- 例: `ptr = 0x7ffff6a00000` (page-aligned) → header at `0x7ffff69fffd8` (別ページ、unmapped)
**修正内容** (`core/box/front_gate_classifier.c:263-266`):
```c
// Safety check: Need at least HEADER_SIZE (40 bytes) before ptr
uintptr_t offset_in_page_for_hdr = (uintptr_t)ptr & 0xFFF;
if (offset_in_page_for_hdr >= HEADER_SIZE) {
// Safe to read AllocHeader (won't cross page boundary)
AllocHeader* hdr = hak_header_from_user(ptr);
...
}
```
**修正結果**:
- **random_mixed**: SEGV → **1.92M ops/s** ✅
- ✅ Single-thread workloads 完全修復
---
**🔧 Larson MT Crash FIX (2025-11-16)** ✅
**2-Layer Problem Structure**:
**Layer 1: Cross-thread Free (TLS SLL Corruption)**
- **Root Cause**: Block allocated by Thread A, freed by Thread B → pushed to B's TLS SLL
- B allocates the block → metadata still points to A's SuperSlab → corruption
- Poison values (0xbada55bada55bada) in TLS SLL → SEGV in `tiny_alloc_fast()`
- **Fix** (`core/tiny_free_fast_v2.inc.h:176-205`):
- Made cross-thread check **ALWAYS ON** (removed ENV gating)
- Check `owner_tid_low` on every free, route cross-thread to remote queue via `tiny_free_remote_box()`
- **Status**: ✅ **FIXED** - TLS SLL corruption eliminated
**Layer 2: SP Metadata Capacity Limit**
- **Root Cause**: `[SP_META_CAPACITY_ERROR] Exceeded MAX_SS_METADATA_ENTRIES=2048`
- Larson rapid churn workload → 2048+ SuperSlabs → registry exhaustion → hang
- **Fix** (`core/hakmem_shared_pool.h:122-126`):
- Increased `MAX_SS_METADATA_ENTRIES` from 2048 → **8192** (4x capacity)
- **Status**: ✅ **FIXED** - Larson completes successfully
**Results** (10 seconds, 4 threads):
- **Before**: 4.2TB virtual memory, 65,531 mappings, indefinite hang (kill -9 required)
- **After**: 6.7GB virtual (-99.84%), 424MB RSS, completes in 10-18 seconds
- **Throughput**: 7,387-8,499 ops/s (0.014% of system malloc 60.6M)
**Layer 3: Performance Optimization (IN PROGRESS)**
- Cross-thread check adds SuperSlab lookup on every free (20-50 cycles overhead)
- **Drain Interval Tuning** (2025-11-16):
- Baseline (drain=2048): 7,663 ops/s
- Moderate (drain=1024): **8,514 ops/s** (+11.1%) ✅
- Aggressive (drain=512): Core dump ❌ (too aggressive, causes crash)
- **Recommendation**: `export HAKMEM_TINY_SLL_DRAIN_INTERVAL=1024` for stable +11% gain
- **Remaining Work**: LRU policy tuning (MAX_CACHED, MAX_MEMORY_MB, TTL_SEC)
- Goal: Improve from 0.014% → 80% of system malloc (currently 0.015% with drain=1024)
---
### 📈 Summary (Performance Map 2025-11-16 17:15)
**修正後の全体結果**:
- ✅ Competitive (≥80%): **0/10 benchmarks** (0%)
- ⚠️ Gap (50-80%): **1/10 benchmarks** (10%) ← 64B固定のみ 53.6%
- ❌ Slow (<50%): **9/10 benchmarks** (90%)
**主要ベンチマーク**:
1. **Fixed-size (16-1024B)**: 38.5-53.6% of system (64B が最良)
2. **Random Mixed (128-1KB)**: **19.4M ops/s** (24.0% of system)
3. **Mid-Large MT (8-32KB)**: **891K ops/s** (12.1% of system, crash 修正済み ✅)
4. **VM Mixed**: **275K ops/s** (30.7% of system, crash 修正済み ✅)
5. **Larson (MT churn)**: **7.4-8.5K ops/s** (0.014% of system, crash 修正済み ✅, 性能最適化は Layer 3 で対応予定)
**優先課題 (2025-11-16 更新)**:
1. ✅ **完了**: Mid-Large crash 修復 (classify_ptr + AllocHeader check)
2. ✅ **完了**: VM Mixed crash 修復 (Mid-Large fix で解消)
3. ✅ **完了**: random_mixed crash 修復 (page boundary check)
4. 🔴 **P0**: Larson SP metadata limit 拡大 (2048 → 4096-8192)
5. 🟡 **P1**: Fixed-size 性能改善 (38-53% → 目標 80%+)
6. 🟡 **P1**: Random Mixed 性能改善 (24% → 目標 80%+)
7. 🟡 **P1**: Mid-Large MT 性能改善 (12% → 目標 80%+, mimalloc 449%が参考値)
`bench_fixed_size_hakmem` / `bench_fixed_size_system`workset=128, 500K iterations 相当)
| Size | HAKMEM (Phase 15) | System malloc | 比率 |
|--------|-------------------|---------------|----------|
| 128B | ~16.6M ops/s | ~90M ops/s | ~18.5% |
| 256B | ~16.2M ops/s | ~89.6M ops/s | ~18.1% |
| 512B | ~15.0M ops/s | ~90M ops/s | ~16.6% |
| 1024B | ~15.1M ops/s | ~90M ops/s | ~16.8% |
状態:
- クラッシュは完全解消workset=64/128 で長尺 500K iter も安定)。
- Tiny UltraHot + 学習層 + ExternalGuard の組み合わせは「正しさ」は OK。
- 性能は system の ~1618% レベル(約 56× 遅い)→ まだ大きな伸びしろあり。
### 2.2 C2/C3 UltraHot 専用ベンチ
固定サイズ100K iterations, workset=128
| Size | Baseline (UltraHot OFF) | UltraHot ON | 改善率 | Hit Rate |
|------|-------------------------|-------------|-------------|---------|
| 16B | ~40.4M ops/s | ~55.0M | +36.2% 🚀 | ≈100% |
| 32B | ~43.5M ops/s | ~50.6M | +16.3% 🚀 | ≈100% |
Random Mixed 256B
- Baseline: ~8.96M ops/s
- UltraHot ON: ~8.81M ops/s-1.6%、誤差〜軽微退化)
- 理由: C2/C3 が全体の 12% のみ → UltraHot のメリットが平均に薄まる。
結論:
- C2/C3 UltraHot は **ターゲットクラスに対しては実用級の Box**。
- 他ワークロードでは「ほぼ影響なし(わずかな分岐オーバーヘッドのみ)」の範囲に収まっている。
---
## 3. Phase 15: ExternalGuard / Domain 分離の成果
### 3.1 以前の問題
- free ラッパ(`core/box/hak_wrappers.inc.h`)が:
- HAKMEM 所有かチェックせず、すべての `free(ptr)` を `hak_free_at(ptr, …)` に投げていた。
- その結果:
- ベンチ内部 `slots``calloc(256, sizeof(void*))` の 2KB など)も CoreAlloc に流入。
- `classify_ptr` → UNKNOWN → ExternalGuard → mincore → 「解放せず leak」と判定。
- ベンチ観測:
- 約 0.84% の leakBenchMeta がどんどん漏れる)。
- `mincore` が Tiny ベンチ CPU の ~13% を消費。
### 3.2 修正内容Phase 15
- free ラッパ側:
- 軽量なドメインチェックを追加:
- Tiny/Pool 用の header magic を安全に読んで、HAKMEM 所有の可能性があるものだけ `hak_free_at` へ。
- そうでないBenchMeta/外部)ポインタは `__libc_free` へ。
- ExternalGuard:
- UNKNOWN ポインタを「解放しないleak」方針に明示的変更。
- デバッグ時のみ `HAKMEM_EXTERNAL_GUARD_LOG=1` で原因特定用ログを出す。
### 3.3 結果
- Leak 率:
- 100K iter: 840 leaks → 0.84%
- 500K iter: ~4200 leaks → 0.84%
- ほぼ全部が BenchMeta / 外部ポインタであり、CoreAlloc 側の漏れではないと確認。
- 性能:
- 256B 固定:
- Before: 15.9M ops/s
- After: 16.2M ops/s+1.9%)→ domain check オーバーヘッドは軽微、むしろ微増。
- 安定性:
- 全サイズ128/256/512/1024Bで 500K iter 完走(クラッシュなし)。
- ExternalGuard 経由の「危ない free」は leak に封じ込められた。
**要点:**
Box 境界違反BenchMeta→CoreAlloc 流入)はほぼ完全に解消。
ベンチでの mincore / ExternalGuard コストも許容範囲になった。
---
## 4. Phase 16: Dynamic Tiny/Mid Boundary A/B Testing2025-11-16完了
### 4.1 実装内容
ENV変数でTiny/Mid境界を動的調整可能にする機能を追加
- `HAKMEM_TINY_MAX_CLASS=7` (デフォルト): Tiny が 0-1023B を担当
- `HAKMEM_TINY_MAX_CLASS=5` (実験用): Tiny が 0-255B のみ担当
実装ファイル:
- `hakmem_tiny.h/c`: `tiny_get_max_size()` - ENV読取とクラス→サイズマッピング
- `hakmem_mid_mt.h/c`: `mid_get_min_size()` - 動的境界調整(サイズギャップ防止)
- `hak_alloc_api.inc.h`: 静的TINY_MAX_SIZEを動的呼び出しに変更
### 4.2 A/B Benchmark Results
| Size | Config A (C0-C7) | Config B (C0-C5) | 変化率 |
|------|------------------|------------------|--------|
| 128B | 6.34M ops/s | 1.38M ops/s | **-78%** ❌ |
| 256B | 6.34M ops/s | 1.36M ops/s | **-79%** ❌ |
| 512B | 5.55M ops/s | 1.33M ops/s | **-76%** ❌ |
| 1024B | 5.91M ops/s | 1.37M ops/s | **-77%** ❌ |
### 4.3 発見と結論
✅ **成功**: サイズギャップ修正完了OOMクラッシュなし
❌ **失敗**: Tiny カバレッジ削減で大幅な性能劣化 (-76% ~ -79%)
⚠️ **根本原因**: Mid の粗いサイズクラス (8KB/16KB/32KB) が小サイズで非効率
- Mid は 8KB ページ単位の設計 → 256B-1KB を投げると 8KB ページをほぼ数ブロックのために確保
- ページ fault・TLB・メタデータコストが相対的に巨大
- Tiny は slab + freelist で高密度 → 同じサイズでも桁違いに効率的
**教訓ChatGPT先生分析**:
1. Mid 箱の前提が「8KB〜用」になっている
- 256B/512B/1024B では 8KB ページをほぼ1〜数個のブロックのために確保 → 非効率
2. パス長も Mid の方が長いPoolTLS / mid registry / page 管理)
3. 「Tiny を削って Mid に任せれば軽くなる」という仮説は、現行の "8KB〜前提の Mid 設計" では成り立たない
**推奨**: **デフォルト HAKMEM_TINY_MAX_CLASS=7 (C0-C7) を維持**
---
## 5. Phase 17: Small-Mid Allocator Box - 実験完了 ✅2025-11-16
### 5.1 目標と動機
**問題**: Tiny C5-C7 (256B/512B/1KB) が ~6M ops/s → system malloc の ~6.7% レベル
**仮説**: 専用層を作れば 2-4x 改善可能
**結果**: ❌ **仮説は誤り** - 性能改善なし±0-1%
### 5.2 Phase 17-1: TLS Frontend CacheTiny delegation
**実装**:
- TLS freelist256B/512B/1KB、容量32/24/16
- Backend: Tiny C5/C6/C7に委譲、Header変換0xa0 → 0xb0
- Auto-adjust: Small-Mid ON時にTinyをC0-C5に自動制限
**結果**:
| Size | OFF | ON | 変化率 |
|------|-----|-----|--------|
| 256B | 5.87M | 6.06M | **+3.3%** |
| 512B | 6.02M | 5.91M | **-1.9%** |
| 1024B | 5.58M | 5.54M | **-0.6%** |
| **平均** | 5.82M | 5.84M | **+0.3%** |
**教訓**: Delegation overhead = TLS savings → 正味利益ゼロ
### 5.3 Phase 17-2: Dedicated SuperSlab Backend
**実装**:
- Small-Mid専用SuperSlab pool1MB、16 slabs/SS
- Batch refill8-16 blocks/refill
- 直接0xb0 header書き込みTiny delegationなし
**結果**:
| Size | OFF | ON | 変化率 |
|------|-----|-----|--------|
| 256B | 6.08M | 5.84M | **-4.1%** ⚠️ |
| 512B | 5.79M | 5.86M | **+1.2%** |
| 1024B | 5.42M | 5.44M | **+0.4%** |
| **平均** | 5.76M | 5.71M | **-0.9%** |
**Phase 17-1比較**: Phase 17-2の方が悪化-3.6% on 256B
### 5.4 根本原因分析ChatGPT先生 + perf profiling
**発見**: **70% page fault** が支配的 🔥
**Perf分析**:
- `asm_exc_page_fault`: 70% CPU時間
- 実際のallocation logicTLS/refill: 30% のみ
- **結論**: Frontend実装は成功、Backendが重すぎる
**なぜpage faultが多いか**:
```
Small-Mid: alloc → TLS miss → refill → SuperSlab新規確保
→ mmap(1MB) → page fault 発生 → 70%のCPU消費
Tiny: alloc → TLS miss → refill → 既存warm SuperSlab使用
→ page faultなし → 高速
```
**Small-Mid問題**:
1. 新しいSuperSlabを頻繁に確保workloadが短いため
2. Warm SuperSlabの再利用なしusedカウンタ減らない
3. Batch refillのメリットよりmmap/page faultコストが大きい
### 5.5 Phase 17の結論と教訓
❌ **Small-Mid専用層戦略は失敗**:
- Phase 17-1Frontend only: +0.3%
- Phase 17-2Dedicated backend: -0.9%
- 目標2-4x改善: **未達成**-50-67%不足)
✅ **重要な発見**:
1. **FrontendTLS/batch refill設計はOK** - 30%のみの負荷
2. **70% page fault = SuperSlab層の問題**
3. **Tiny (6.08M) は既に十分速い** - これを超えるのは困難
4. **層の分離では性能は上がらない** - Backend最適化が必要
✅ **実装の価値**:
- ENV=0でゼロオーバーヘッドbranch predictor学習
- 実験記録として価値あり("なぜ専用層が効果なかったか"の証拠)
- Tiny最適化の邪魔にならない完全分離アーキテクチャ
### 5.6 次のステップ: SuperSlab ReusePhase 18候補
**ChatGPT提案**: Tiny SuperSlabの最適化Small-Mid専用層ではなく
**Box SS-ReuseSuperSlab slab再利用箱**:
- **目標**: 70% page fault → 5-10%に削減
- **戦略**:
1. meta->freelistを優先使用現在はbump onlyで再利用なし
2. slabがemptyになったらshared_poolに返却
3. 同じSuperSlab内で長く回す新規mmap削減
- **効果**: page fault大幅削減 → 2-4x改善期待
- **実装場所**: `core/hakmem_tiny_superslab.c`Tiny用、Small-Midではない
**Box SS-Prewarm事前温め箱**:
- クラスごとにSuperSlabを事前確保Phase 11実績: +6.4%
- page faultをbenchmark開始時に集中
- **課題**: benchmark専用、実運用では無駄
**推奨**: Box SS-Reuse優先実運用価値あり、根本解決
---
## 6. 未達成の目標・残課題(次フェーズ候補)
### 6.1 Tiny 性能ギャップSystem の ~18% 止まり)
現状:
- System malloc が ~90M ops/s レベルのところ、
- HAKMEM は 128〜1024B 固定で ~1516M ops/s約 18%)。
原因の切り分け(これまでの調査から):
- FrontUltraHot/TinyHeapV2/TLS SLLのパス長はかなり短縮済み。
- L1 dcache miss / instructions / branches は Phase 14 で大幅削減済みだが、
- まだ Tiny が 01023B を全部抱えており、
- 特に 512/1024B が Superslab/Pool 側のメタ負荷に効いている可能性。
候補:
- **Phase 17 で実装中!** Small-Mid Box256B〜4KB 専用箱を設計し、Tiny/Mid の間を分離する。
- 詳細は § 5. Phase 17 を参照
### 6.2 UltraHot/TinyHeapV2 の拡張 or 整理
- C2/C3 UltraHot は成功16/32B 用)。
- C4/C5 まで拡張した試みPhase 14-Bは:
- Fixed-size では改善あり。
- Random Mixed で shared_pool_acquire_slab() が 47.5% まで膨らみ、大退化。
- 原因: Superslab/TLS 在庫のバランスを壊す「窃取カスケード」。
方針:
- UltraHot は **C2/C3 専用 Box** に戻すC4/C5 は一旦対象外にする)。
- もし C4/C5 を最適化したいなら、SmallMid Box の中で別設計する。
### 6.3 ExternalGuard の統計と自動アラート
- 現在:
- `HAKMEM_EXTERNAL_GUARD_STATS=1` で統計を手動出力。
- 100+ 回呼ばれたら WARNING を出すのみ。
- 構想:
- 「ExternalGuard 呼び出しが一定閾値を超えたら、自動で簡易レポートを吐く」Box を追加。
- 例: Top N 呼び出し元アドレス、サイズ帯、mincore 結果 など。
---
## 7. Claude Code 君向け TODO
### 7.1 Phase 17: Small-Mid Allocator Box ✅ 完了2025-11-16
**Phase 17-1**: TLS Frontend Cache
- ✅ 実装完了TLS freelist + Tiny delegation
- ✅ A/B テスト: ±0.3%(性能改善なし)
- ✅ 教訓: Delegation overhead = TLS savings
**Phase 17-2**: Dedicated SuperSlab Backend
- ✅ 実装完了専用SuperSlab pool + batch refill
- ✅ A/B テスト: -0.9%Phase 17-1より悪化
- ✅ 根本原因: 70% page faultmmap/SuperSlab確保が重い
**結論**: Small-Mid専用層は性能改善なし±0-1%、Tiny最適化が必要
### 7.2 Phase 18 候補: SuperSlab ReuseTiny最適化
**Box SS-Reuse最優先**:
1. meta->freelist優先使用現状: bump only
2. slab empty検出→shared_pool返却
3. 同じSuperSlab内で長く回すpage fault削減
4. 目標: 70% page fault → 5-10%、性能 2-4x改善
**Box SS-Prewarm次優先**:
1. クラスごとSuperSlab事前確保
2. page faultをbenchmark開始時に集中
3. Phase 11実績: +6.4%(参考値)
**Box SS-HotHint長期**:
1. クラス別ホットSuperSlab管理
2. locality最適化cache効率
3. SS-Reuseとの統合
### 7.3 その他タスク
1. ✅ **Phase 16/17 結果分析** - CURRENT_TASK.md記録完了
2. **C2/C3 UltraHot コード掃除** - C4/C5関連を別Box化
3. **ExternalGuard 統計自動化** - 閾値超過時レポート
---
## 8. Phase 17 実装ログ(完了)
### 2025-11-16
- ✅ **Phase 17-1完了**: TLS Frontend + Tiny delegation
- 実装: `hakmem_smallmid.h/c`, auto-adjust, routing修正
- A/B結果: +0.3%(性能改善なし)
- 教訓: Delegation overhead = TLS savings
- ✅ **Phase 17-2完了**: Dedicated SuperSlab backend
- 実装: `hakmem_smallmid_superslab.h/c`, batch refill, 0xb0 header
- A/B結果: -0.9%Phase 17-1より悪化
- 根本原因: 70% page faultChatGPT + perf分析
- ✅ **重要な発見**:
- FrontendTLS/batch refill: OK30%のみ)
- BackendSuperSlab確保: ボトルネック70% page fault
- 専用層では性能上がらない → **Tiny SuperSlab最適化が必要**
- ✅ **CURRENT_TASK.md更新**: Phase 17結果 + Phase 18計画
- 🎯 **次**: Phase 18 Box SS-Reuse実装Tiny SuperSlab最適化
---
## 9. Phase 19 実装ログ(完了) 🎉
### 2025-11-16
- ✅ **Phase 19-1完了**: Box FrontMetrics観測
- 実装: `core/box/front_metrics_box.h/c`、全層にヒット率計測追加
- ENV: `HAKMEM_TINY_FRONT_METRICS=1`, `HAKMEM_TINY_FRONT_DUMP=1`
- 結果: CSV形式で per-class ヒット率レポート生成
- ✅ **Phase 19-2完了**: ベンチマークとヒット率分析
- ワークロード: Random Mixed 16-1040B、50万イテレーション
- **重要な発見**:
- **HeapV2**: 88-99% ヒット率(主力として機能)✅
- **UltraHot**: 0.2-11.7% ヒット率(ほぼ素通り)⚠️
- FC/SFC: 無効化済み0%
- TLS SLL: fallback として 0.7-2.7% のみ
- ✅ **Phase 19-3完了**: Box FrontPrune診断
- 実装: ENV切り替えで層を個別ON/OFF可能
- ENV: `HAKMEM_TINY_FRONT_ENABLE_ULTRAHOT=1`デフォルトOFF
- ENV: `HAKMEM_TINY_FRONT_DISABLE_HEAPV2=1`デフォルトON
- ✅ **Phase 19-4完了**: A/Bテストと最適化
- **テスト結果**:
| 設定 | 性能 | vs Baseline | C2/C3 ヒット率 |
|------|------|-------------|----------------|
| Baseline両方ON | 10.1M ops/s | - | UH=11.7%, HV2=88.3% |
| **HeapV2のみ** | **11.4M ops/s** | **+12.9%** ⭐ | HV2=99.3%, SLL=0.7% |
| UltraHotのみ | 6.6M ops/s | -34.4% ❌ | UH=96.4% (C2), SLL=94.2% (C3) |
- **決定的結論**:
- **UltraHot削除で性能向上** (+12.9%)
- 理由: 分岐予測ミスコスト > UltraHotヒット率向上効果
- UltraHotチェック: 88.3%のケースで無駄な分岐 → CPU分岐予測器を混乱
- HeapV2単独の方が予測可能性が高い → 性能向上
- ✅ **デフォルト設定変更**: UltraHot デフォルトOFF
- 本番推奨: UltraHot OFF最速設定
- 研究用: `HAKMEM_TINY_FRONT_ENABLE_ULTRAHOT=1` で有効化可能
- コードは削除せず ENV切り替えで残す研究・デバッグ用
- ✅ **Phase 19 成果**:
- ChatGPT先生の「観測→診断→治療」戦略が完璧に機能 🎓
- 直感に反する発見UltraHotが阻害要因をデータで証明
- A/Bテストでリスクなし確認してから最適化実施
- 詳細: `PHASE19_FRONTEND_METRICS_FINDINGS.md`, `PHASE19_AB_TEST_RESULTS.md`
---
## 10. Phase 20 計画: Tiny ホットパス一本化 + BenchFast モード 🎯
### 目標
- **性能目標**: 20-30M ops/ssystem malloc の 25-35%
- **設計目標**: 「箱を崩さず」に達成(研究価値を保つ)
### Phase 20-1: HeapV2 を唯一の Tiny Front に(本命ホットパス一本化)
**現状認識**:
- C2/C3: HeapV2 が 88-99% を処理(本命)
- UltraHot: 0.2-11.7% しか当たらず、分岐の邪魔(削ると +12.9%
- FC/SFC: 実質 OFF、TLS SLL は fallback のみ
**実装方針**:
1. **HeapV2 を「唯一の front」として扱う**:
- C2-C5: HeapV2 → fallback だけ TLS SLL
- 他層UltraHot, FC, SFCはホットパスから完全に外し、実験用に退避
2. **HeapV2 の中身を徹底的に薄くする**:
- size→class 再計算を全部やめて、「class_idx を渡すだけ」にする
- 分岐を「classごとの専用関数」かテーブルジャンプにして 1-2 本に減らす
- header 書き込み・TLS stack 操作・return までを「6-8 命令の直線」に近づける
3. **期待効果**:
- 現在 11M ops/s → 目標 15-20M ops/s (+35-80% 改善)
- 分岐削減 + 命令直線化 → CPU パイプライン効率向上
**ENV制御**:
```bash
# HeapV2専用モードPhase 20デフォルト
HAKMEM_TINY_FRONT_HEAPV2_ONLY=1 # UltraHot/FC/SFC完全バイパス
# 旧動作(研究用)
HAKMEM_TINY_FRONT_ENABLE_ULTRAHOT=1 # Phase 19設定
```
---
### Phase 20-2: BenchFast モードで安全コストを外す
**現状認識**:
- `hak_free_at` / `classify_ptr` / ExternalGuard / mincore など、
「LD_PRELOAD / 外部ライブラリから守る」層が、
ベンチでは「絶対に hakmem だけを使っている」前提の上に乗っている
**実装方針**:
1. **ベンチ用完全信頼モード**Box BenchFast:
- alloc/free ともに:
- header 1バイト で Tiny を即判定
- Pool/Mid/L25/ExternalGuard/registry を完全にバイパス
- 変なポインタが来たら壊れていい(ベンチ用なので)
2. **ENV制御**:
```bash
HAKMEM_BENCH_FAST_MODE=1 # 安全コスト全外し
```
3. **目的**:
- 「箱全部乗せ版」と「安全コスト全外し版」の差を測る
- 「設計そのものの限界」と「安全・汎用性のコスト」の内訳を見る
- mimalloc と同じくらい「危ないモード」で、どこまで近づけるかを研究
4. **期待効果**:
- HeapV2専用モード: 15-20M ops/s
- BenchFast追加: 25-30M ops/s (+65-100% vs 現状)
- system malloc (90M ops/s) の 28-33% に到達
---
### Phase 20-3: SuperSlab ホットセット チューニング
**現状認識**:
- SS-Reuse: 再利用率 98.8%、新規 mmap 1.2% → page fault は抑えられている
- とはいえ perf ではまだ `asm_exc_page_fault` がでかく見える場面もある
**実装方針**:
1. **Box SS-HotSet**(どのクラスが何枚をホットに持つか計測):
- クラスごとの「ホット SuperSlab 数」を 1-2 枚に抑えるように class_hints をチューニング
- precharge (`HAKMEM_TINY_SS_PRECHARGE_Cn`) を使って、「最初から 2 枚だけ温める」戦略を試す
2. **Box SS-Compact**(ホットセット圧縮):
- 同じ SuperSlab に複数のホットクラスを詰め込むPhase 12 の発展)
- 例: C2/C3 を同じ SuperSlab に配置 → キャッシュ効率向上
3. **期待効果**:
- page fault さらに削減 → +10-20% 性能向上
- 既存の SS-Reuse/Cache 設計を、「Tiny front が見ているサイズ帯に合わせて細かく調整」
---
### Phase 20 実装順序
1. **Phase 20-1**: HeapV2 専用モード実装(優先度: 高)
- 期待: +35-80% (11M → 15-20M ops/s)
- 工数: 中(既存 HeapV2 をスリム化)
2. **Phase 20-2**: BenchFast モード実装(優先度: 中)
- 期待: +65-100% (11M → 25-30M ops/s)
- 工数: 中(安全層バイパス)
3. **Phase 20-3**: SS-HotSet チューニング(優先度: 低)
- 期待: +10-20% 追加改善
- 工数: 小(パラメータ調整 + 計測箱追加)
---
### Phase 20 成功条件
- ✅ Tiny 固定サイズで 20-30M ops/s 達成system の 25-35%
- ✅ 「箱を崩さず」達成(研究箱としての価値を保つ)
- ✅ ENV切り替えで「安全モード」「ベンチモード」を選べる状態を維持
- ✅ 残りの差system との 2.5-3xは「kernel/page fault + mimalloc の極端な inlining」と言える根拠を固める
---
### Phase 20 後の展望
ここまで行けたら:
- 「残りの差は kernel/page fault + mimalloc の極端な inlining・OS依存の差」だと自信を持って言える
- hakmem の「研究箱」としての価値(構造をいじりやすい / 可視化しやすい)を保ったまま、
性能面でも「そこそこ実用に耐える」ラインに乗る
- 学術論文・技術ブログでの発表材料が揃う
---
## 11. Phase 20-1 実装ログ: Box SS-HotPrewarmTLS Cache 事前確保) ✅
### 2025-11-16
#### 実装内容
- ✅ **Box SS-HotPrewarm 作成**: ENV制御の per-class TLS cache prewarm
- 実装: `core/box/ss_hot_prewarm_box.h/c`
- デフォルト targets: C2/C3=128, C4/C5=64aggressive prewarm
- ENV制御: `HAKMEM_TINY_PREWARM_C2`, `_C3`, `_C4`, `_C5`, `_ALL`
- ✅ **初期化統合**: `hak_init_impl()` から自動呼び出し
- 384 ブロック事前確保C2=128, C3=128, C4=64, C5=64
- `box_prewarm_tls()` API 使用(安全な carve-push
#### ベンチマーク結果500K iterations, 256B random mixed
| 設定 | Page Faults | Throughput | vs Baseline |
|------|-------------|------------|-------------|
| **Baseline** (Prewarm OFF) | 10,399 | 15.7M ops/s | - |
| **Phase 20-1** (Prewarm ON) | 10,342 | 16.2M ops/s | **+3.3%** ⭐ |
- **Page fault 削減**: 0.55%(期待: 50-66% → 現実: ほぼなし)
- **性能向上**: +3.3%15.7M → 16.2M ops/s
#### 分析と結論
**❌ Page Fault 削減の失敗理由**:
1. **ユーザーページ由来が支配的**: ベンチマーク自体の初期化・データ構造確保による page fault が大半
2. **SuperSlab 事前確保の限界**: 384 ブロック程度の prewarm では、ベンチマーク全体の page fault (10K+) に対して微々たる影響しかない
3. **カーネル側のコスト**: `asm_exc_page_fault` はユーザー空間だけでは制御不可能
**✅ Cache Warming 効果**:
1. **TLS SLL 事前充填**: 初期の refill コスト削減
2. **CPU サイクル節約**: +3.3% の性能向上
3. **安定性向上**: 初期状態が warm → 最初のアロケーションから高速
#### 決定: 「軽い +3% 箱」として確定
- **prewarm は有効**: 384 ブロック確保C2/C3=128, C4/C5=64のまま残す
- **これ以上の aggressive 化は不要**: RSS 消費増 vs page fault 削減効果が見合わない
- **次フェーズへ**: BenchFast モードで「上限性能」を測定し、構造的限界を把握
#### 変更ファイル
- `core/box/ss_hot_prewarm_box.h` - NEW
- `core/box/ss_hot_prewarm_box.c` - NEW
- `core/box/hak_core_init.inc.h` - prewarm 呼び出し追加
- `Makefile` - `ss_hot_prewarm_box.o` 追加
---
**Status**: Phase 20-1 完了 ✅ → **Phase 20-2 準備中** 🎯
**Next**: BenchFast モード実装(安全コスト全外し → 構造的上限測定)
---
## Phase 20-2: BenchFast Mode Implementation (2025-11-16) ✅
**Status**: ✅ **COMPLETE** - Recursion fixed via prealloc pool + init guard
**Goal**: Measure HAKMEM's structural performance ceiling by removing ALL safety costs
**Implementation**: Complete (core/box/bench_fast_box.{h,c})
### Design Philosophy
BenchFast mode bypasses all safety mechanisms to measure the theoretical maximum throughput:
**Alloc path** (6-8 instructions):
- size → class_idx → TLS SLL pop → write header → return USER pointer
- Bypasses: classify_ptr, Pool/Mid routing, registry, refill logic
**Free path** (3-5 instructions):
- Read header → BASE pointer → TLS SLL push
- Bypasses: registry lookup, mincore, ExternalGuard, capacity checks
### Implementation Details
**Files Created**:
- `core/box/bench_fast_box.h` - ENV-gated API with recursion guard
- `core/box/bench_fast_box.c` - Ultra-minimal alloc/free + prealloc pool
**Integration**:
- `core/box/hak_wrappers.inc.h` - malloc()/free() wrappers with BenchFast bypass
- `bench_random_mixed.c` - bench_fast_init() call before benchmark loop
- `Makefile` - bench_fast_box.o added to all object lists
**Activation**:
```bash
export HAKMEM_BENCH_FAST_MODE=1
./bench_fixed_size_hakmem 500000 256 128
```
### Recursion Fix: Prealloc Pool Strategy
**Problem**: When TLS SLL is empty, bench_fast_alloc() → hak_alloc_at() → malloc() → infinite loop
**Solution** (User's "C案"):
1. **Prealloc pool**: bench_fast_init() pre-allocates 50K blocks per class using normal path
2. **Init guard**: `bench_fast_init_in_progress` flag prevents BenchFast during init
3. **Pop-only alloc**: bench_fast_alloc() only pops from pool, NO REFILL
**Key Fix** (User's contribution):
```c
// core/box/bench_fast_box.h
extern __thread int bench_fast_init_in_progress;
// core/box/hak_wrappers.inc.h (malloc wrapper)
if (__builtin_expect(!bench_fast_init_in_progress && bench_fast_enabled(), 0)) {
return bench_fast_alloc(size); // Only activate AFTER init complete
}
```
### Performance Results (500K iterations, 256B fixed-size)
| Mode | Throughput | vs Baseline | vs System |
|------|------------|-------------|-----------|
| **Baseline** (通常) | 54.4M ops/s | - | 53.3% |
| **BenchFast** (安全コスト除去) | 56.9M ops/s | **+4.5%** | 55.7% |
| **System malloc** | 102.1M ops/s | +87.6% | 100% |
### 🔍 Critical Discovery: Safety Costs Are NOT the Bottleneck
**BenchFast で安全コストをすべて除去しても、わずか +4.5% しか改善しない!**
**What this reveals**:
- classify_ptr、Pool/Mid routing、registry、mincore、ExternalGuard → これらは**ボトルネックではない**
- 本当のボトルネックは**構造的な部分**
- SuperSlab 設計1 SS = 1 class 固定)
- メタデータアクセスパターンcache miss 多発)
- TLS SLL 効率pointer chasing overhead
- 877 SuperSlab 生成による巨大なメタデータフットプリント
**System malloc との差**:
- Baseline: 47.7M ops/s 遅い(-46.7%
- BenchFast でも 45.2M ops/s 遅い(-44.3%
- → 安全コスト除去しても差は **たった 2.5M ops/s しか縮まらない**
### Implications for Future Work
**増分最適化の限界**:
- Phase 9-11 で学んだ教訓を確認:症状の緩和では埋まらない
- 安全コストは全体の 4.5% しか占めていない
- 残り 95.5% は**構造的なボトルネック**
**Phase 12 Shared SuperSlab Pool の重要性**:
- 877 SuperSlab → 100-200 に削減
- メタデータフットプリント削減 → cache miss 削減
- 動的 slab 共有 → 使用効率向上
- 期待性能: 70-90M ops/sSystem の 70-90%
### Bottleneck Breakdown (推定)
| コンポーネント | CPU 時間 | BenchFast で除去? |
|---------------|----------|------------------|
| SuperSlab metadata access | ~35% | ❌ 構造的 |
| TLS SLL pointer chasing | ~25% | ❌ 構造的 |
| Refill + carving | ~15% | ❌ 構造的 |
| classify_ptr + registry | ~10% | ✅ 除去済み |
| Pool/Mid routing | ~5% | ✅ 除去済み |
| mincore + guards | ~5% | ✅ 除去済み |
| その他 | ~5% | - |
**結論**: 構造的ボトルネック75%>> 安全コスト20%
**Next Steps**:
- Phase 12: Shared SuperSlab Pool本質的解決
- 877 SuperSlab → 100-200 に削減して cache miss を大幅削減
- 期待性能: 70-90M ops/sSystem の 70-90%
**Phase 20 完了**: BenchFast モードで「安全コストは 4.5%」と証明 ✅
---
## Phase 21: Hot Path Cache Optimization (HPCO) - 構造的ボトルネック攻略 🎯
**Status**: 🚧 **PLANNING** (ChatGPT先生のフィードバック反映済み)
**Goal**: アクセスパターン最適化で 60% CPUメタアクセス 35% + ポインタチェイス 25%)を直接攻撃
**Target**: 75-82M ops/sSystem malloc の 73-80%
### Phase 20-2 で判明した構造的ボトルネック
**BenchFast の結論**:
- 安全コストclassify_ptr/Pool routing/registry/mincore/guards= **4.5%** しかない
- 残り 45M ops/s の差 = **箱の積み方そのもの**
**支配的ボトルネック** (60% CPU):
```
メタアクセス: ~35% (SuperSlab/TinySlabMeta の複数フィールド読み書き)
ポインタチェイス: ~25% (TLS SLL の next ポインタたどり)
carve/refill: ~15% (batch carving + metadata updates)
```
**1 回の alloc/free で発生すること**:
- 何段も構造体を跨ぐTLS → SuperSlab → SlabMeta → freelist
- ポインタを何回もたどるSLL の next チェイン)
- メタデータを何フィールドも触るused/capacity/carved/freelist/...
### Phase 21 戦略ChatGPT先生フィードバック反映
#### Phase 21-1: Array-Based TLS Cache (C2/C3) 🔴 最優先
**狙い**: TLS SLL のポインタチェイス削減 → +15-20%
**現状の問題**:
```c
// TLS SLL (linked list) - 3 メモリアクセス、うち 1 回は cache miss
void* ptr = g_tls_sll_head[class_idx]; // 1. ヘッド読み込み
void* next = *(void**)ptr; // 2. next ポインタ読み込み (cache miss!)
g_tls_sll_head[class_idx] = next; // 3. ヘッド更新
```
**解決策: Ring Buffer**:
```c
// Box 21-1: Array-based hot cache (C2/C3 only)
typedef struct {
void* slots[128]; // 初期サイズ 128ENV で A/B: 64/128/256
uint16_t head; // pop index
uint16_t tail; // push index
} TlsRingCache;
static __thread TlsRingCache g_hot_cache_c2;
static __thread TlsRingCache g_hot_cache_c3;
// Ultra-fast alloc (1-2 命令)
void* ptr = g_hot_cache_c2.slots[g_hot_cache_c2.head++ & 0x7F]; // ring wrap
```
**階層化** (ChatGPT先生フィードバック):
```
Ring → SLL → SuperSlab
↑ ↑ ↑
L0 L1 L2
- alloc: Ring → 空なら SLL → 空なら SuperSlab
- free: Ring → 満杯なら SLL
- drain: SLL → Ring に昇格(一方向)
```
**効果**:
- ポインタチェイス: 1 回 → **0 回**
- メモリアクセス: 3 → **2 回**
- cache locality: 配列は連続メモリ
- **期待: +15-20%** (54.4M → 62-65M ops/s)
**ENV 変数**:
```bash
HAKMEM_TINY_HOT_RING_C2=128 # C2 Ring サイズ (default: 128)
HAKMEM_TINY_HOT_RING_C3=128 # C3 Ring サイズ (default: 128)
HAKMEM_TINY_HOT_RING_ENABLE=1 # Ring cache 有効化
```
**実装ポイント** (ChatGPT先生):
- Ring サイズは 64/128/256 で A/B テスト
- C0/C1/C4/C5/C6/C7 は SLL のまま(使用頻度低い)
- drain 時: SLL → Ring への昇格(一方向)
- Ring が空 → SLL fallback → SuperSlab refill
#### Phase 21-2: Hot Slab Direct Index 🟡 中優先度
**狙い**: SuperSlab → slab ループ削減 → +10-15%
**現状の問題**:
```c
// 毎回 32 slab をスキャン
SuperSlab* ss = g_tls_slabs[class_idx].ss;
for (int i = 0; i < 32; i++) { // ← ループ!
TinySlabMeta* meta = &ss->slabs[i];
if (meta->freelist != NULL) { ... }
}
```
**解決策: Hot Slab Cache**:
```c
// Box 21-2: Direct index to hot slab
static __thread TinySlabMeta* g_hot_slab[TINY_NUM_CLASSES];
void refill_from_hot_slab(int class_idx) {
TinySlabMeta* hot = g_hot_slab[class_idx];
// Hot slab が空なら更新
if (!hot || hot->freelist == NULL) {
hot = find_nonempty_slab(class_idx); // 1回だけ探索
g_hot_slab[class_idx] = hot; // cache!
}
pop_batch_from_freelist(hot, ...); // no loop!
}
```
**効果**:
- SuperSlab → slab ループ: 削除
- メタアクセス: 32 回 → **1 回**
- **期待: +10-15%** (62-65M → 70-75M ops/s)
**実装ポイント** (ChatGPT先生):
- Hot slab が EMPTY → find_nonempty_slab で差し替え
- free 時: hot slab に返す or freelist に戻す(ポリシー決める)
- shared_pool / SS-Reuse との整合性確保
#### Phase 21-3: Minimal Meta Access (C2/C3) 🟢 低優先度
**狙い**: 触るフィールド削減 → +5-10%
**現状の問題**:
```c
// 1 alloc/free で 4-5 フィールド触る
typedef struct {
uint16_t used; // ✅ 必須
uint16_t capacity; // ❌ compile-time 定数化できる
uint16_t carved; // ❌ C2/C3 では使わない
void* freelist; // ✅ 必須
} TinySlabMeta;
```
**解決策: アクセスパターン限定** (ChatGPT先生):
```c
// struct を分けなくてもOK型分岐を避ける
// C2/C3 コードパスで触るのを used/freelist だけに限定
#define C2_CAPACITY 64 // compile-time 定数
static inline int c2_can_alloc(TinySlabMeta* meta) {
return meta->used < C2_CAPACITY; // capacity フィールド不要!
}
```
**効果**:
- 触るフィールド: 4-5 → **2 個** (used/freelist のみ)
- cache line 消費: 削減
- **期待: +5-10%** (70-75M → 75-82M ops/s)
**実装ポイント** (ChatGPT先生):
- struct 分離は後回し(型分岐コスト vs 効果のトレードオフ)
- アクセスパターン限定だけでも cache 効果あり
- Phase 21-1/2 の結果を見てから判断
### Phase 21 実装順序
```
Phase 21-1 (Array-based TLS Cache C2/C3):
↓ +15-20% → 62-65M ops/s
Phase 21-2 (Hot Slab Direct Index):
↓ +10-15% → 70-75M ops/s
Phase 21-3 (Minimal Meta Access):
↓ +5-10% → 75-82M ops/s
🎯 Target: System malloc の 73-80%
```
**Phase 12 (SuperSlab 共有) は後回し**:
- Phase 21 で 80M ops/s 到達後、残り 20M ops/s を Phase 12 で詰める
### ChatGPT先生フィードバック重要
1. **Box 21-1 (Ring cache)**: ✅ perf 的にドンピシャ
- Ring → SLL → SuperSlab の階層を明確に
- Ring サイズは 128/64 から ENV で A/B
- drain 時: SLL → Ring への昇格(一方向)
2. **Box 21-2 (Hot slab)**: ✅ 有効だが扱いに注意
- hot slab が EMPTY 時の差し替えロジック
- shared_pool / SS-Reuse との整合性
3. **Box 21-3 (Minimal meta)**: ⚠️ 後回しでOK
- struct 分離は型分岐コスト増
- アクセスパターン限定だけで効果あり
- 21-1/2 の結果を見てから判断
4. **Phase 12 との順番**: ✅ 合理的
- アクセスパターン > SuperSlab 数
- Phase 21 → Phase 12 の順で問題なし
### 実装リスク
**低リスク**:
- C2/C3 のみ変更(他クラスは SLL のまま)
- 既存構造を大きく変えない
- ENV で A/B テスト可能
**注意点**:
- Ring と SLL の境界を明確に
- shared_pool / SS-Reuse との整合
- 型分岐が増えすぎないように
### 次のアクション
**Phase 21-1 実装開始**:
1. `core/box/hot_ring_cache_box.{h,c}` 作成
2. C2/C3 専用 TlsRingCache 実装
3. Ring → SLL → SuperSlab 階層化
4. ENV: `HAKMEM_TINY_HOT_RING_ENABLE=1`
5. ベンチマーク: 目標 62-65M ops/s (+15-20%)
---
---
## HAKMEM ハング問題調査 (2025-11-16)
### 症状
1. `bench_fixed_size_hakmem 1 16 128` → 5秒以上ハング
2. `bench_random_mixed_hakmem 500000 256 42` → キルされた
### Root Cause
**Cross-thread check の always-on 化** (直前の修正)
- `core/tiny_free_fast_v2.inc.h:175-204` で ENV ゲート削除
- Single-thread でも毎回 SuperSlab lookup 実行
### ハング箇所の推定 (確度順)
| 箇所 | ファイル:行 | 原因 | 確度 |
|------|-----------|------|------|
| `hak_super_lookup()` registry probing | `core/hakmem_super_registry.h:119-187` | 線形探索 32-64 iterations / free | **高** |
| Node pool exhausted fallback | `core/hakmem_shared_pool.c:394-400` | sp_freelist_push_lockfree fallback の unsafe | 中 |
| `tls_sll_push()` CAS loop | `core/box/tls_sll_box.h:75-184` | 単純実装、無限ループはなさそう | 低 |
### パフォーマンス影響
```
Before (header-based): 5-10 cycles/free
After (cross-thread): 110-520 cycles/free (11-51倍遅い)
500K iterations:
500K × 200 cycles = 100M cycles @ 3GHz = 33ms
→ Overhead は大きいが単なる遅さ?
```
### Node pool exhausted の真実
- `MAX_FREE_NODES_PER_CLASS = 4096`
- 500K iterations > 4096 → exhausted ⚠️
- しかし fallback (`sp_freelist_push()`) は lock-free で安全
- **副作用であり、直接的ハング原因ではない可能性高い**
### 推奨修正
✅ **ENV ゲートで cross-thread check を復活**
```c
// core/tiny_free_fast_v2.inc.h:175
static int g_larson_fix = -1;
if (__builtin_expect(g_larson_fix == -1, 0)) {
const char* e = getenv("HAKMEM_TINY_LARSON_FIX");
g_larson_fix = (e && *e && *e != '0') ? 1 : 0;
}
if (__builtin_expect(g_larson_fix, 0)) {
// Cross-thread check - only for MT
SuperSlab* ss = hak_super_lookup(base);
// ... rest of check
}
```
**利点:**
- Single-thread ベンチ: 5-10 cycles (fast)
- Larson MT: `HAKMEM_TINY_LARSON_FIX=1` で有効 (safe)
### 検証コマンド
```bash
# 1. ハング確認
timeout 5 ./out/release/bench_fixed_size_hakmem 1 16 128
echo $? # 124 = timeout
# 2. 修正後確認
HAKMEM_TINY_LARSON_FIX=0 ./out/release/bench_fixed_size_hakmem 1 16 128
# Should complete fast
# 3. 500K テスト
./out/release/bench_random_mixed_hakmem 500000 256 42 2>&1 | grep "Node pool"
# Output: [P0-4 WARN] Node pool exhausted for class 7
```
### 詳細レポート
- **HANG分析**: `/tmp/HAKMEM_HANG_INVESTIGATION_FINAL.md`