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>
9.0 KiB
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
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
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)
仮説:
- 過剰な再帰ガードフォールバック:
g_hakmem_lock_depthチェックが不適切で、本来hakmemで処理すべきallocationが__libc_mallocにフォールバックしている可能性 - 初期化コストの問題: hakmem初期化時の大量のprintf出力が毎回実行されている可能性
- ロック粒度の問題: malloc/free wrapper レベルでロックを取ると、内部のhak_alloc_at/hak_free_atでも別のロックを取っている可能性(二重ロック)
問題2: 4-threadでさらに悪化
期待: 4T ≈ 1T (スケールなしだが同等性能) 実測: 4T = 0.60x 1T (逆に40%低下)
仮説:
- ロック競合: グローバルロック
g_hakmem_lockでの競合 - False sharing:
g_hakmem_lock_depthが__threadだが、他のグローバル変数とキャッシュライン共有 - スレッド間の不均衡: 一部スレッドがロック待ちで停止
🔍 調査が必要な項目
Priority P0: 即座に調査
-
再帰ガードの動作確認
// malloc() の最初で確認 if (g_hakmem_lock_depth > 0) { // ← この分岐に入る頻度を計測 extern void* __libc_malloc(size_t); return __libc_malloc(size); }- カウンタ追加: フォールバック率を測定
- 期待: 初期化時のみ (<1%)
- 実測: 不明(要調査)
-
二重ロックの有無確認
hak_alloc_at()/hak_free_at()内でロックを取っているか?- wrapper でロックを取った後、内部でさらにロックを取ると deadlock or 性能劣化
-
初期化printf の影響
hak_init()が毎回15行のログを出力- LD_PRELOAD環境では初期化が複数回呼ばれる可能性
Priority P1: 次の調査
-
ロック競合の可視化
pthread_mutex_lock()の待ち時間を計測- 期待: <1% の時間
- 実測: 不明
-
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_initializedcheck を malloc wrapper の最初に移動- printf出力を
HAKMEM_SILENT環境変数でsuppress
Option B: Step 3 (P1 TLS) に進む (非推奨)
理由: 現状の性能では、TLSを追加しても92%の劣化を解消できない可能性が高い
💡 技術的発見
再帰ガードの実装
// 正しい順序 (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
extern void* __libc_malloc(size_t); // glibc の実際の malloc
用途: 初期化時にhak_init()内のprintf()が内部でmallocを呼ぶとデッドロック
解決: g_hakmem_lock_depth > 0 で検出してfallback
📝 実装コード抜粋
Global Lock宣言 (hakmem.c:61-72)
// ============================================================================
// 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)
// 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;
}
🎯 結論
実装完了項目 ✅
- pthread.h インクルード
- グローバルロック宣言
- malloc/free/calloc/realloc wrapper 実装
- 再帰ガード実装
- ビルド成功
- LD_PRELOAD動作確認
未達成項目 ❌
- 1T性能: 1.2M ops/sec (期待13-15M、92%未達)
- 4T性能: 0.7M ops/sec (期待13-15M、95%未達)
- Helgrind検証 (時間制約によりスキップ)
- 安定性テスト (時間制約によりスキップ)
Critical Decision Point
❌ Step 2は「実装完了」だが「性能目標未達」
推奨アクション:
-
Option A (推奨): P0調査を実施(1時間)
- Fallback率測定
- 二重ロック確認
- 初期化最適化
- 期待: 1.2M → 12-15M ops/sec に改善可能
-
Option B (代替): 現状を "Baseline with Lock" として受け入れ、Step 3 TLS実装へ進む
- リスク: TLSでも根本問題が残る可能性
📁 関連ドキュメント
- 計画: PHASE_6.15_PLAN.md - 全体計画
- 前フェーズ: PHASE_6.14_COMPLETION_REPORT.md - Baseline (15.3M ops/sec)
- Thread Safety分析: THREAD_SAFETY_SOLUTION.md - 完全分析
Implementation Time: 135分 (予定120分、+15分オーバー) Next Action: P0調査 (Option A) または Step 3開始判断 (Option B)