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>
219 lines
6.1 KiB
Markdown
219 lines
6.1 KiB
Markdown
# Phase 6.15 P0.2 調査報告: clock_gettime 影響調査
|
||
|
||
**Date**: 2025-10-22
|
||
**Status**: ✅ 調査完了
|
||
**Goal**: Gemini診断(clock_gettime がボトルネック)の検証
|
||
|
||
---
|
||
|
||
## 📊 **Executive Summary**
|
||
|
||
### **発見事実**
|
||
|
||
1. ✅ **軽量ベンチマーク(64KB)**: hakmem は system malloc と**ほぼ同等**(+0.2%)
|
||
2. ❌ **larsonベンチマーク(8-1024B混合)**: 非常に遅い(0.62M ops/sec)
|
||
3. ⚠️ **EVOLUTION無効化**: むしろ性能悪化(1.05M → 0.62M、-41%)
|
||
|
||
### **結論**
|
||
|
||
- **基本性能は正常**(64KB allocations で system と同等)
|
||
- **小サイズ混合allocation** で mutex オーバーヘッドが顕在化
|
||
- **clock_gettime だけが原因ではない**(無効化で改善せず)
|
||
|
||
---
|
||
|
||
## 🔬 **テスト結果詳細**
|
||
|
||
### **Test 1: bench_allocators(軽量、64KB固定)**
|
||
|
||
#### **hakmem-baseline**
|
||
```bash
|
||
$ ./bench_allocators --allocator hakmem-baseline --scenario json --iterations 10000
|
||
allocator,scenario,iterations,avg_ns,soft_pf,hard_pf,rss_kb,ops_per_sec
|
||
hakmem-baseline,json,10000,214,17,0,0,4667120
|
||
```
|
||
|
||
#### **system malloc**
|
||
```bash
|
||
$ ./bench_allocators --allocator system --scenario json --iterations 10000
|
||
allocator,scenario,iterations,avg_ns,soft_pf,hard_pf,rss_kb,ops_per_sec
|
||
system,json,10000,213,17,0,0,4678406
|
||
```
|
||
|
||
#### **比較**
|
||
| Allocator | 平均時間 | ops/sec | vs system |
|
||
|-----------|---------|---------|-----------|
|
||
| hakmem | 214ns | 4.67M | +0.2% |
|
||
| system | 213ns | 4.68M | baseline |
|
||
|
||
**結論**: ✅ **64KB allocations では問題なし**
|
||
|
||
---
|
||
|
||
### **Test 2: larson(重量、8-1024B混合)**
|
||
|
||
#### **EVOLUTION有効時(修正前)**
|
||
```bash
|
||
# 実行: 以前のテスト結果
|
||
Throughput = 1,050,000 ops/sec (1.05M)
|
||
```
|
||
|
||
#### **EVOLUTION無効時(#if 0)**
|
||
```bash
|
||
$ cd /tmp/mimalloc-bench/bench/larson
|
||
$ env LD_PRELOAD=.../libhakmem.so ./larson 0 8 1024 10000 1 12345 1
|
||
|
||
[SiteRules] Initialized (MVP: 4-probe hash, capacity=2048)
|
||
Throughput = 623377 operations per second, relative time: 1604.167s.
|
||
[EVO] Initialized (policy=AUTO, freeze_sec=180, relearn_delta=20.00%)
|
||
Done sleeping...
|
||
[ELO] Initialized 12 strategies (thresholds: 512KB-32MB)
|
||
[Batch] Initialized (threshold=8 MB, min_size=64 KB)
|
||
[Pool] ERROR: Invalid magic in pool block!\n
|
||
```
|
||
|
||
#### **比較**
|
||
| 状態 | ops/sec | 実行時間 | エラー |
|
||
|------|---------|---------|-------|
|
||
| EVOLUTION有効 | 1.05M | 不明 | なし |
|
||
| EVOLUTION無効 | 0.62M | 1604秒(26分) | Pool ERROR ✅ |
|
||
|
||
**結論**: ❌ **EVOLUTION無効化で41%悪化** + エラー発生
|
||
|
||
---
|
||
|
||
## 🔍 **原因分析**
|
||
|
||
### **1. なぜEVOLUTION無効化で悪化したのか?**
|
||
|
||
#### **仮説A: 初期化順序の問題**
|
||
|
||
出力ログの順序:
|
||
```
|
||
[SiteRules] Initialized ← 最初
|
||
Throughput = ... ← ベンチマーク実行(ここでallocations発生)
|
||
[EVO] Initialized ← 後から初期化!
|
||
[ELO] Initialized
|
||
[Batch] Initialized
|
||
[Pool] ERROR
|
||
```
|
||
|
||
**問題**: EVOが無効でも、`hak_init()` 内で各サブシステムが初期化される。しかし、EVOLUTION無効時は `g_cached_strategy_id` が初期化されない可能性。
|
||
|
||
#### **仮説B: Pool ERROR との関連**
|
||
|
||
```c
|
||
[Pool] ERROR: Invalid magic in pool block!\n
|
||
```
|
||
|
||
該当箇所を確認する必要がある(`hakmem_pool.c` の error メッセージ)。
|
||
|
||
---
|
||
|
||
### **2. larson vs bench_allocators の違い**
|
||
|
||
| 項目 | larson | bench_allocators |
|
||
|------|--------|------------------|
|
||
| サイズ範囲 | 8-1024B(混合) | 64KB(固定) |
|
||
| パターン | ランダム | 順次 |
|
||
| 実行時間 | 26分(異常) | <1秒 |
|
||
| mutex競合 | 高頻度 | 低頻度 |
|
||
|
||
**結論**: **小サイズ・高頻度allocation で mutex オーバーヘッドが支配的**
|
||
|
||
---
|
||
|
||
### **3. Gemini診断の評価**
|
||
|
||
**Gemini仮説**: `clock_gettime()` がボトルネック(1024回に1回)
|
||
|
||
**検証結果**:
|
||
- ✅ `clock_gettime` は確かに高コスト(数μs)
|
||
- ❌ **しかし無効化で改善せず、むしろ悪化**
|
||
|
||
**新たな仮説**:
|
||
- mutex lock/unlock 自体のオーバーヘッドが主因
|
||
- 小サイズallocationsで頻度が高すぎる(8-1024Bを10,000 chunks × rounds)
|
||
|
||
---
|
||
|
||
## 🎯 **次のステップ**
|
||
|
||
### **Option A: EVOLUTION を元に戻す**(推奨)
|
||
|
||
**理由**:
|
||
- 無効化で悪化した
|
||
- Pool ERROR が発生
|
||
- 軽量ベンチマークでは問題なし
|
||
|
||
**実装**:
|
||
```c
|
||
// hakmem.c:378
|
||
#if HAKMEM_FEATURE_EVOLUTION // #if 0 から戻す
|
||
```
|
||
|
||
---
|
||
|
||
### **Option B: サンプリング頻度調整**(並行実施)
|
||
|
||
**現状**: 1024回に1回 `clock_gettime()`
|
||
**提案**: 環境変数で制御可能に
|
||
|
||
```c
|
||
// 環境変数: HAKMEM_EVO_SAMPLE
|
||
// 0 = disabled (default)
|
||
// 10 = 1024回に1回
|
||
// 16 = 65536回に1回
|
||
|
||
char* sample = getenv("HAKMEM_EVO_SAMPLE");
|
||
if (sample && atoi(sample) > 0) {
|
||
int freq = atoi(sample);
|
||
uint64_t mask = (1ULL << freq) - 1;
|
||
if ((atomic_fetch_add(&tick_counter, 1) & mask) == 0) {
|
||
clock_gettime(...);
|
||
}
|
||
}
|
||
```
|
||
|
||
**デフォルト**: 0(無効)で最速、必要時のみ有効化
|
||
|
||
---
|
||
|
||
### **Option C: TLS 実装を優先**(最終手段)
|
||
|
||
P0での性能改善を諦め、Step 3 (TLS) で根本解決。
|
||
|
||
**理由**:
|
||
- 軽量ベンチマークでは既に system と同等
|
||
- larson の遅さは mutex 競合が主因
|
||
- TLS で 95%+ のロック回避が可能
|
||
|
||
---
|
||
|
||
## 📝 **学んだこと**
|
||
|
||
1. **ベンチマーク選択の重要性**:
|
||
- larson は重すぎて調査に不向き
|
||
- 軽量ベンチマークで基本性能を先に確認すべき
|
||
|
||
2. **clock_gettime だけではない**:
|
||
- Gemini診断は部分的に正しいが、主因ではなかった
|
||
- mutex lock/unlock の頻度が最大のボトルネック
|
||
|
||
3. **EVOLUTION の依存関係**:
|
||
- 無効化すると他の機能に影響
|
||
- 環境変数で制御する方が安全
|
||
|
||
---
|
||
|
||
## 🚀 **推奨アクション**
|
||
|
||
1. ✅ **EVOLUTION を元に戻す**(5分)
|
||
2. ✅ **環境変数制御を実装**(デフォルト無効、15分)
|
||
3. ✅ **軽量ベンチマークで再テスト**(1分)
|
||
4. ⏭️ **larson は後回し**(TLS実装後に再評価)
|
||
|
||
---
|
||
|
||
**Status**: ✅ 調査完了、次は Option A + B 実装へ
|