# 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_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)