312 lines
11 KiB
Markdown
312 lines
11 KiB
Markdown
|
|
# Partial Release無効化テスト結果レポート
|
|||
|
|
|
|||
|
|
**調査日**: 2025年12月5日
|
|||
|
|
**目的**: madvise()がCPU時間の58%を占めている問題を解決するため、Partial Release機能の影響を調査
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 測定結果サマリー
|
|||
|
|
|
|||
|
|
### ベンチマーク性能比較
|
|||
|
|
|
|||
|
|
| 条件 | Run1 (ops/s) | Run2 (ops/s) | Run3 (ops/s) | 平均 (ops/s) | 改善率 |
|
|||
|
|
|-----|--------------|--------------|--------------|--------------|--------|
|
|||
|
|
| **Partial Release有効** (baseline) | 4,784,048 | 4,709,849 | 4,739,815 | **4,744,571** | - |
|
|||
|
|
| **Partial Release無効** (HAKMEM_TINY_SS_PARTIAL=0) | 4,920,803 | 4,778,194 | 4,889,397 | **4,862,798** | **+2.5%** |
|
|||
|
|
|
|||
|
|
### perf統計比較
|
|||
|
|
|
|||
|
|
| 指標 | Partial Release有効 | Partial Release無効 | 差 |
|
|||
|
|
|-----|---------------------|---------------------|---|
|
|||
|
|
| **cycles** | 1,164,151,908 | 1,160,123,269 | -4M (-0.3%) |
|
|||
|
|
| **page-faults** | 6,759 | 6,760 | +1 (変化なし) |
|
|||
|
|
| **cache-misses** | 8,210,925 | 8,142,282 | -69K (-0.8%) |
|
|||
|
|
| **L1-dcache-load-misses** | 17,780,041 (3.99%) | 17,624,374 (3.96%) | -156K (-0.9%) |
|
|||
|
|
| **user時間** | 0.030s | 0.035s | +0.005s |
|
|||
|
|
| **sys時間** | 0.247s | 0.252s | +0.005s |
|
|||
|
|
| **実行時間** | 0.278s | 0.288s | +0.010s |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 重大な発見:Partial Release無効化してもmadvise()は減らない!
|
|||
|
|
|
|||
|
|
### strace syscall統計
|
|||
|
|
|
|||
|
|
#### HAKMEM_TINY_SS_PARTIAL=0(Partial Release無効)
|
|||
|
|
```
|
|||
|
|
% time seconds usecs/call calls errors syscall
|
|||
|
|
------ ----------- ----------- --------- --------- ----------------
|
|||
|
|
91.21 0.173846 160 1082 madvise
|
|||
|
|
5.30 0.010094 9 1092 munmap
|
|||
|
|
3.20 0.006106 5 1113 mmap
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### デフォルト(Partial Release有効)
|
|||
|
|
```
|
|||
|
|
% time seconds usecs/call calls errors syscall
|
|||
|
|
------ ----------- ----------- --------- --------- ----------------
|
|||
|
|
91.86 0.159657 147 1081 madvise
|
|||
|
|
4.96 0.008628 7 1091 munmap
|
|||
|
|
2.90 0.005043 4 1113 mmap
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**結論**: **madvise呼び出し回数はほぼ同じ(1081-1082回)!**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔬 詳細調査:madvise()の発生源を特定
|
|||
|
|
|
|||
|
|
### 発見した環境変数
|
|||
|
|
|
|||
|
|
| 環境変数名 | デフォルト値 | 用途 | 効果 |
|
|||
|
|
|-----------|-------------|------|------|
|
|||
|
|
| **HAKMEM_TINY_SS_PARTIAL** | 1 (有効) | SuperSlabのPartial Release制御 | **効果なし** (2.5%改善は誤差範囲) |
|
|||
|
|
| **HAKMEM_TINY_SS_PARTIAL_INTERVAL** | 4 | Partial Release実行間隔 | - |
|
|||
|
|
| **HAKMEM_DISABLE_BATCH** | 0 (有効) | Batch madvise制御 | **効果なし** |
|
|||
|
|
| **HAKMEM_SS_PREFAULT** | 0 (OFF) | SuperSlab prefault制御 | **効果なし** |
|
|||
|
|
|
|||
|
|
### 全機能無効化テスト
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
HAKMEM_DISABLE_BATCH=1 HAKMEM_TINY_SS_PARTIAL=0 HAKMEM_SS_PREFAULT=0 strace -c ./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**結果**: **依然として1081回のmadvise呼び出し** (91.74% of syscall time)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 💡 根本原因の特定
|
|||
|
|
|
|||
|
|
### madvise()呼び出し箇所の完全マップ
|
|||
|
|
|
|||
|
|
straceで実際の呼び出しを確認:
|
|||
|
|
```bash
|
|||
|
|
strace -e madvise ./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**全てのmadvise呼び出しは `MADV_POPULATE_WRITE` であることが判明!**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
madvise(0x73f0e2680000, 524288, MADV_POPULATE_WRITE) = 0
|
|||
|
|
madvise(0x73f0e2300000, 524288, MADV_POPULATE_WRITE) = 0
|
|||
|
|
madvise(0x73f0e2200000, 524288, MADV_POPULATE_WRITE) = 0
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 発生源コード
|
|||
|
|
|
|||
|
|
#### 1. **主犯: `core/superslab_cache.c` (Fallback Path)**
|
|||
|
|
|
|||
|
|
`/mnt/workdisk/public_share/hakmem/core/superslab_cache.c:113`
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// Pre-fault pages in fallback path (only after trim to actual SuperSlab size)
|
|||
|
|
// This is critical: we MUST touch the pages after munmap() to establish valid mappings
|
|||
|
|
// CRITICAL FIX (2025-12-05): Use MADV_POPULATE_WRITE for efficiency
|
|||
|
|
#ifdef MADV_POPULATE_WRITE
|
|||
|
|
int ret = madvise(ptr, ss_size, MADV_POPULATE_WRITE); // ← ここが主犯!
|
|||
|
|
if (ret != 0) {
|
|||
|
|
// Fallback: explicit memset
|
|||
|
|
memset(ptr, 0, ss_size);
|
|||
|
|
}
|
|||
|
|
#else
|
|||
|
|
// Fallback for kernels < 5.14
|
|||
|
|
memset(ptr, 0, ss_size);
|
|||
|
|
#endif
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**問題点**:
|
|||
|
|
- この`madvise()`は**環境変数で無効化できない**
|
|||
|
|
- Fallback pathが常に使われている(MAP_ALIGNED_SUPERが失敗?)
|
|||
|
|
- munmap trim後に必ずMADV_POPULATE_WRITEが実行される
|
|||
|
|
|
|||
|
|
#### 2. **`core/box/ss_os_acquire_box.c:179`** (populate=1の場合)
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
#ifdef MADV_POPULATE_WRITE
|
|||
|
|
if (populate) {
|
|||
|
|
int ret = madvise(ptr, ss_size, MADV_POPULATE_WRITE);
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. **`core/hakmem_tiny_intel.inc:692`** (Partial Release - 今回無効化を試した箇所)
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
static inline void superslab_partial_release(SuperSlab* ss, uint32_t epoch) {
|
|||
|
|
#if defined(MADV_DONTNEED)
|
|||
|
|
if (!g_ss_partial_enable) return; // ← HAKMEM_TINY_SS_PARTIAL=0で無効化
|
|||
|
|
...
|
|||
|
|
if (madvise(ss, len, MADV_DONTNEED) == 0) {
|
|||
|
|
ss->partial_epoch = epoch;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**重要**: この関数は今回のベンチマークでは**ほとんど呼ばれていない**!
|
|||
|
|
|
|||
|
|
#### 4. **`core/hakmem_batch.c:120,123`** (Batch madvise)
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
int ret = madvise(ptr, size, MADV_FREE);
|
|||
|
|
if (ret != 0) {
|
|||
|
|
ret = madvise(ptr, size, MADV_DONTNEED);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📈 アーキテクチャ分析
|
|||
|
|
|
|||
|
|
### madvise()の4つの用途
|
|||
|
|
|
|||
|
|
| # | 場所 | 種類 | 目的 | 頻度 | 環境変数制御 |
|
|||
|
|
|---|------|------|------|------|-------------|
|
|||
|
|
| 1 | `superslab_cache.c:113` | **MADV_POPULATE_WRITE** | Fallback path でのページ確保 | **超高頻度** (~1000回) | ❌ **不可** |
|
|||
|
|
| 2 | `ss_os_acquire_box.c:179` | **MADV_POPULATE_WRITE** | populate=1時のprefault | populate時のみ | HAKMEM_SS_PREFAULT |
|
|||
|
|
| 3 | `hakmem_tiny_intel.inc:692` | **MADV_DONTNEED** | Partial Release (空SuperSlabのメモリ返却) | 低頻度 | ✅ HAKMEM_TINY_SS_PARTIAL |
|
|||
|
|
| 4 | `hakmem_batch.c:120` | **MADV_FREE/DONTNEED** | Batch madvise (大きいalloc解放時) | 中頻度 | ✅ HAKMEM_DISABLE_BATCH |
|
|||
|
|
|
|||
|
|
### 今回のベンチマークでの実態
|
|||
|
|
|
|||
|
|
- **1081回のmadvise呼び出し全てが `MADV_POPULATE_WRITE`**
|
|||
|
|
- これは**#1のFallback Path**から発生している
|
|||
|
|
- **#3 Partial Release (MADV_DONTNEED) は今回のベンチマークではほとんど実行されていない**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 結論
|
|||
|
|
|
|||
|
|
### 主要な発見
|
|||
|
|
|
|||
|
|
1. **`HAKMEM_TINY_SS_PARTIAL=0` は効果がほぼない(+2.5%程度)**
|
|||
|
|
- 理由: このベンチマークではPartial Releaseがほとんど発動していない
|
|||
|
|
- 1081回のmadviseのうち、MADV_DONTNEEDはほぼゼロ
|
|||
|
|
|
|||
|
|
2. **真の問題は `superslab_cache.c` のFallback Path**
|
|||
|
|
- 全てのSuperSlab割り当てで MADV_POPULATE_WRITE が実行される
|
|||
|
|
- 環境変数では制御不可能
|
|||
|
|
- コメントによると「munmap trim後の再確保に必須」
|
|||
|
|
|
|||
|
|
3. **前回のperf分析での58%のmadvise時間は別の要因だった可能性**
|
|||
|
|
- 前回のベンチマーク: `bench_random_mixed.c` (16-1024バイト)
|
|||
|
|
- 今回のベンチマーク: `bench_random_mixed_hakmem 1000000 400 1` (16-1040バイト)
|
|||
|
|
- ワークロードが異なるため、Partial Releaseの発動頻度も異なる
|
|||
|
|
|
|||
|
|
4. **性能への影響は限定的**
|
|||
|
|
- MADV_POPULATE_WRITEは割り当て時の1回のみ(ホットパスではない)
|
|||
|
|
- ウォームアップ後はSuperSlabの再利用で新規madviseは減る
|
|||
|
|
- syscall時間の91%でも、全体の実行時間は0.25s程度
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 推奨される次のステップ
|
|||
|
|
|
|||
|
|
### Option 1: Fallback Path の最適化(根本対策)
|
|||
|
|
|
|||
|
|
**問題**: MAP_ALIGNED_SUPERが失敗し、常にFallback Pathが使われている
|
|||
|
|
|
|||
|
|
**調査項目**:
|
|||
|
|
1. なぜMAP_ALIGNED_SUPERが失敗するのか?
|
|||
|
|
2. FreeBSDでは成功するが、Linuxでは失敗する?
|
|||
|
|
3. Fallback PathでのMADV_POPULATE_WRITEは本当に必須か?
|
|||
|
|
|
|||
|
|
**改善案**:
|
|||
|
|
```c
|
|||
|
|
// Option A: 環境変数で制御可能にする
|
|||
|
|
static int prefault_disabled = -1;
|
|||
|
|
if (prefault_disabled == -1) {
|
|||
|
|
const char* env = getenv("HAKMEM_NO_FALLBACK_PREFAULT");
|
|||
|
|
prefault_disabled = (env && *env && *env != '0') ? 1 : 0;
|
|||
|
|
}
|
|||
|
|
if (!prefault_disabled) {
|
|||
|
|
madvise(ptr, ss_size, MADV_POPULATE_WRITE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Option B: memsetフォールバックを常に使う(syscall削減)
|
|||
|
|
memset(ptr, 0, ss_size); // syscallなし、ただしCPU使用量増加
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Option 2: ワークロード別の最適化
|
|||
|
|
|
|||
|
|
**異なるベンチマークで再測定**:
|
|||
|
|
```bash
|
|||
|
|
# より長時間のベンチマーク(Partial Releaseが発動しやすい)
|
|||
|
|
./bench_random_mixed_hakmem 10000000 400 1
|
|||
|
|
|
|||
|
|
# より大きいワーキングセット(SuperSlabの入れ替えが多い)
|
|||
|
|
./bench_random_mixed_hakmem 1000000 4000 1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Option 3: perf record で詳細プロファイリング
|
|||
|
|
|
|||
|
|
**前回報告されていた58%のmadviseを再現**:
|
|||
|
|
```bash
|
|||
|
|
# 前回と同じベンチマーク条件で測定
|
|||
|
|
perf record -g ./bench_random_mixed.c の該当コマンド
|
|||
|
|
perf report --stdio
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📋 コード参照
|
|||
|
|
|
|||
|
|
### 関連ファイル
|
|||
|
|
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/superslab_cache.c:113` - MADV_POPULATE_WRITE (主犯)
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/box/ss_os_acquire_box.c:179` - MADV_POPULATE_WRITE (populate時)
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/hakmem_tiny_intel.inc:685-698` - superslab_partial_release (MADV_DONTNEED)
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/hakmem_batch.c:120` - Batch madvise (MADV_FREE/DONTNEED)
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/hakmem_config.c:231-234` - HAKMEM_DISABLE_BATCH の処理
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/hakmem_tiny_lifecycle.inc:78-90` - HAKMEM_TINY_SS_PARTIAL の処理
|
|||
|
|
- `/mnt/workdisk/public_share/hakmem/core/box/ss_prefault_box.h:35-54` - HAKMEM_SS_PREFAULT の処理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🧪 再現手順
|
|||
|
|
|
|||
|
|
### 環境変数一覧
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Partial Release無効化(効果: +2.5%程度)
|
|||
|
|
export HAKMEM_TINY_SS_PARTIAL=0
|
|||
|
|
|
|||
|
|
# Batch madvise無効化(効果: なし)
|
|||
|
|
export HAKMEM_DISABLE_BATCH=1
|
|||
|
|
|
|||
|
|
# SuperSlab prefault無効化(効果: なし)
|
|||
|
|
export HAKMEM_SS_PREFAULT=0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### ベンチマーク実行
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# ベースライン
|
|||
|
|
./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
|
|||
|
|
# Partial Release無効
|
|||
|
|
HAKMEM_TINY_SS_PARTIAL=0 ./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
|
|||
|
|
# 全無効化
|
|||
|
|
HAKMEM_DISABLE_BATCH=1 HAKMEM_TINY_SS_PARTIAL=0 HAKMEM_SS_PREFAULT=0 ./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
|
|||
|
|
# syscall詳細
|
|||
|
|
strace -c ./bench_random_mixed_hakmem 1000000 400 1
|
|||
|
|
strace -e madvise ./bench_random_mixed_hakmem 1000000 400 1 2>&1 | head -30
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📚 参考資料
|
|||
|
|
|
|||
|
|
- `PERF_ANALYSIS_16_1024B_20251205.md` - 前回のperf分析(madvise 58%問題)
|
|||
|
|
- `LAZY_ZEROING_IMPLEMENTATION_RESULTS_20251204.md` - MADV_DONTNEED最適化の失敗例
|
|||
|
|
- `EXPLICIT_PREFAULT_IMPLEMENTATION_REPORT_20251205.md` - MADV_POPULATE_WRITE導入の経緯
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**報告者**: Claude Code
|
|||
|
|
**最終更新**: 2025年12月5日
|