Files
hakmem/docs/archive/PHASE_6.15_STEP2_COMPLETION.md
Moe Charm (CI) 52386401b3 Debug Counters Implementation - Clean History
Major Features:
- Debug counter infrastructure for Refill Stage tracking
- Free Pipeline counters (ss_local, ss_remote, tls_sll)
- Diagnostic counters for early return analysis
- Unified larson.sh benchmark runner with profiles
- Phase 6-3 regression analysis documentation

Bug Fixes:
- Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB)
- Fix profile variable naming consistency
- Add .gitignore patterns for large files

Performance:
- Phase 6-3: 4.79 M ops/s (has OOM risk)
- With SuperSlab: 3.13 M ops/s (+19% improvement)

This is a clean repository without large log files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 12:31:14 +09:00

277 lines
9.0 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.

# Phase 6.15 Step 2 完了報告: P0 Safety Lock
**Date**: 2025-10-22
**Implementation Time**: 135分
**Status**: ⚠️ **実装完了・性能問題あり**
---
## 📊 **実装結果**
### **修正ファイル**
- `apps/experiments/hakmem-poc/hakmem.c` (+130 lines)
- `#include <pthread.h>` 追加
- `pthread_mutex_t g_hakmem_lock` グローバルロック追加
- `__thread int g_hakmem_lock_depth` 再帰検出用カウンタ追加
- `malloc()` wrapper 実装 (ロック + 再帰ガード)
- `free()` wrapper 実装 (ロック + 再帰ガード)
- `calloc()` wrapper 実装 (ロック + 再帰ガード)
- `realloc()` wrapper 実装 (ロック + 再帰ガード)
- `apps/experiments/hakmem-poc/Makefile` (+1 line)
- `LDFLAGS = -lm -lpthread` に変更
### **ビルド**
- ✅ make clean && make shared 成功
- ✅ libhakmem.so 生成成功
- ✅ LD_PRELOAD テスト成功 (`/bin/echo` で確認)
---
## 🧪 **テスト結果**
### **Test 2.3.1: larson 1-thread**
```bash
env LD_PRELOAD=./libhakmem.so /tmp/mimalloc-bench/bench/larson/larson 0 8 1024 10000 1 12345 1
```
- **実測**: 1,197,531 ops/sec (1.2M ops/sec)
- **期待**: 13-15M ops/sec
- **結果**: ❌ **92%遅い** (期待の8%のみ達成)
- **ロックオーバーヘッド**: -92% (予想0-15%を大幅に超過)
### **Test 2.3.2: larson 4-thread**
```bash
env LD_PRELOAD=./libhakmem.so /tmp/mimalloc-bench/bench/larson/larson 0 8 1024 10000 1 12345 4
```
- **実測**: 717,791 ops/sec (0.7M ops/sec)
- **期待**: 13-15M ops/sec
- **結果**: ❌ **95%遅い** (期待の5%のみ達成)
- **スケール**: 0.60x (1T→4Tで逆に40%低下) ❌
### **Test 2.3.3: Helgrind**
- **Status**: ⏸️ **時間制約によりスキップ**
- **理由**: 性能問題の根本原因調査を優先
### **Test 2.3.4: 安定性10回実行**
- **Status**: ⏸️ **時間制約によりスキップ**
- **理由**: 性能問題の根本原因調査を優先
---
## ❌ **成功基準チェック**
- [✅] ビルド成功
- [❌] 1T性能: 1.2M ops/sec (期待13-15M、**92%未達**)
- [❌] 4T性能: 0.7M ops/sec (期待13-15M、**95%未達**)
- [⏸️] Helgrind: Data race 0件 (スキップ)
- [⏸️] 安定性: 10/10 成功 (スキップ)
---
## 🚨 **Critical Issue: 性能崩壊の原因分析**
### **問題1: 想定外のロックオーバーヘッド**
**期待**: 0-15%オーバーヘッド
**実測**: 92%性能低下 (15.3M → 1.2M ops/sec)
**仮説**:
1. **過剰な再帰ガードフォールバック**: `g_hakmem_lock_depth` チェックが不適切で、本来hakmemで処理すべきallocationが`__libc_malloc`にフォールバックしている可能性
2. **初期化コストの問題**: hakmem初期化時の大量のprintf出力が毎回実行されている可能性
3. **ロック粒度の問題**: malloc/free wrapper レベルでロックを取ると、内部のhak_alloc_at/hak_free_atでも別のロックを取っている可能性二重ロック
### **問題2: 4-threadでさらに悪化**
**期待**: 4T ≈ 1T (スケールなしだが同等性能)
**実測**: 4T = 0.60x 1T (逆に40%低下)
**仮説**:
1. **ロック競合**: グローバルロック`g_hakmem_lock`での競合
2. **False sharing**: `g_hakmem_lock_depth``__thread`だが、他のグローバル変数とキャッシュライン共有
3. **スレッド間の不均衡**: 一部スレッドがロック待ちで停止
---
## 🔍 **調査が必要な項目**
### **Priority P0: 即座に調査**
1. **再帰ガードの動作確認**
```c
// malloc() の最初で確認
if (g_hakmem_lock_depth > 0) {
// ← この分岐に入る頻度を計測
extern void* __libc_malloc(size_t);
return __libc_malloc(size);
}
```
- カウンタ追加: フォールバック率を測定
- 期待: 初期化時のみ (<1%)
- 実測: 不明(要調査)
2. **二重ロックの有無確認**
- `hak_alloc_at()` / `hak_free_at()` 内でロックを取っているか?
- wrapper でロックを取った後、内部でさらにロックを取ると deadlock or 性能劣化
3. **初期化printf の影響**
- `hak_init()` が毎回15行のログを出力
- LD_PRELOAD環境では初期化が複数回呼ばれる可能性
### **Priority P1: 次の調査**
4. **ロック競合の可視化**
- `pthread_mutex_lock()` の待ち時間を計測
- 期待: <1% の時間
- 実測: 不明
5. **hakmem vs __libc_malloc 比率**
- 実際にhakmemで処理された allocation の割合
- 期待: >99%
- 実測: 不明
---
## 📋 **次のステップ**
### **Option A: P0調査 → 根本原因修正** (推奨)
**Task A.1: Fallback率測定** (30分)
- `malloc()/free()` にカウンタ追加
- hakmem経路 vs __libc_fallback経路 の比率を出力
**Task A.2: 二重ロック確認** (15分)
- `hak_alloc_at()` / `hak_free_at()` のロック状況を確認
- wrapper側でロック→内部でロックなら、内部ロック削除
**Task A.3: 初期化最適化** (15分)
- `g_initialized` check を malloc wrapper の**最初**に移動
- printf出力を `HAKMEM_SILENT` 環境変数でsuppress
### **Option B: Step 3 (P1 TLS) に進む** (非推奨)
**理由**: 現状の性能では、TLSを追加しても92%の劣化を解消できない可能性が高い
---
## 💡 **技術的発見**
### **再帰ガードの実装**
```c
// 正しい順序 (Phase 6.15 Step 2 実装)
pthread_mutex_lock(&g_hakmem_lock); // 1. ロック取得
g_hakmem_lock_depth++; // 2. 深さ記録
void* ptr = hak_alloc_at(size, ...); // 3. 内部処理
g_hakmem_lock_depth--; // 4. 深さ復元
pthread_mutex_unlock(&g_hakmem_lock); // 5. ロック解放
```
**Key Point**: ロック取得**後**に `g_hakmem_lock_depth` をインクリメント
**理由**:
- ロック前にインクリメントすると、全呼び出しがfallbackになる初回実装のバグ
- ロック後にインクリメントすると、初期化時のnestedのみfallbackになる修正版
### **__libc_malloc へのfallback**
```c
extern void* __libc_malloc(size_t); // glibc の実際の malloc
```
**用途**: 初期化時に`hak_init()`内の`printf()`が内部でmallocを呼ぶとデッドロック
**解決**: `g_hakmem_lock_depth > 0` で検出してfallback
---
## 📝 **実装コード抜粋**
### **Global Lock宣言** (hakmem.c:61-72)
```c
// ============================================================================
// Phase 6.15 P0: Thread Safety - Global Lock
// ============================================================================
// Global lock for all allocator operations
// Purpose: Ensure correctness in multi-threaded environment
// Performance: 4T ≈ 1T (no scalability, safety first)
// Will be replaced by TLS in P1-P3 (95%+ lock avoidance)
static pthread_mutex_t g_hakmem_lock = PTHREAD_MUTEX_INITIALIZER;
// Recursive lock count (to prevent deadlock during initialization)
static __thread int g_hakmem_lock_depth = 0;
```
### **malloc() Wrapper** (hakmem.c:740-759)
```c
// malloc wrapper - intercepts system malloc() calls
void* malloc(size_t size) {
// Phase 6.15 P0: Global lock (with recursion guard)
// If we're already holding the lock (depth > 0), use fallback to prevent deadlock
if (g_hakmem_lock_depth > 0) {
// Nested call detected - fallback to system malloc
extern void* __libc_malloc(size_t);
return __libc_malloc(size);
}
// First-level call - acquire lock
pthread_mutex_lock(&g_hakmem_lock);
g_hakmem_lock_depth++;
void* ptr = hak_alloc_at(size, HAK_CALLSITE());
g_hakmem_lock_depth--;
pthread_mutex_unlock(&g_hakmem_lock);
return ptr;
}
```
---
## 🎯 **結論**
### **実装完了項目** ✅
1. pthread.h インクルード
2. グローバルロック宣言
3. malloc/free/calloc/realloc wrapper 実装
4. 再帰ガード実装
5. ビルド成功
6. LD_PRELOAD動作確認
### **未達成項目** ❌
1. 1T性能: 1.2M ops/sec (期待13-15M、92%未達)
2. 4T性能: 0.7M ops/sec (期待13-15M、95%未達)
3. Helgrind検証 (時間制約によりスキップ)
4. 安定性テスト (時間制約によりスキップ)
### **Critical Decision Point**
**❌ Step 2は「実装完了」だが「性能目標未達」**
**推奨アクション**:
1. **Option A (推奨)**: P0調査を実施1時間
- Fallback率測定
- 二重ロック確認
- 初期化最適化
- 期待: 1.2M → 12-15M ops/sec に改善可能
2. **Option B (代替)**: 現状を "Baseline with Lock" として受け入れ、Step 3 TLS実装へ進む
- リスク: TLSでも根本問題が残る可能性
---
## 📁 **関連ドキュメント**
- **計画**: [PHASE_6.15_PLAN.md](PHASE_6.15_PLAN.md) - 全体計画
- **前フェーズ**: [PHASE_6.14_COMPLETION_REPORT.md](PHASE_6.14_COMPLETION_REPORT.md) - Baseline (15.3M ops/sec)
- **Thread Safety分析**: [THREAD_SAFETY_SOLUTION.md](THREAD_SAFETY_SOLUTION.md) - 完全分析
---
**Implementation Time**: 135分 (予定120分、+15分オーバー)
**Next Action**: P0調査 (Option A) または Step 3開始判断 (Option B)