Files
hakmem/docs/analysis/PERF_ULTRA_ALLOC_OPT_1_PLAN.md

322 lines
9.6 KiB
Markdown
Raw Normal View History

Phase PERF-ULTRA-REBASE-1 計測完了 + PERF-ULTRA-ALLOC-OPT-1 計画策定 ## Phase PERF-ULTRA-REBASE-1 実施 - C4-C7 ULTRA 全て ON 状態での CPU ホットパス計測 - Mixed 16-1024B, 10M cycles での perf 分析 - **発見**: C7 ULTRA alloc が新しい最大ボトルネック(7.66% self%) ## ホットパス分析結果 | 順位 | 関数 | self% | |------|------|-------| | #1 | C7 ULTRA alloc | **7.66%** ← 最大ボトルネック | | #2 | C4-C7 ULTRA free群 | 5.41% | | #3 | gate/front前段 | 2.51% ← 既に十分薄い | | #4 | header | < 0.17% ← ULTRA で削減済み | ## 戦略転換(重要) これまで: 新しい箱や世代(v4/v5/v6)を追加 → 今後: 既に当たりが出ている ULTRA 内部を細かく削る 理由: - v6/v5 拡張は -12〜33% の大幅回帰 - gate/front や header はもう改善の余地が少ない - C7 ULTRA alloc の 7.66% → 5-6% 削減で全体効果 2-3% ## Phase PERF-ULTRA-ALLOC-OPT-1 計画策定 - ターゲット: tiny_c7_ultra_alloc() の hot path を直線化 - 施策: 1. TLS ヒットパスの直線化(env check/snapshot 削除) 2. TLS freelist レイアウト最適化(L1 キャッシュ親和性) 3. segment/page_meta アクセスの確認(slow path 確認) - 計測: C7-only + Mixed での A/B テスト - 期待: 7.66% → 5-6%、全体で +2-3M ops/s ## ドキュメント更新 - CURRENT_TASK.md: PERF-ULTRA-REBASE-1 結果と ALLOC-OPT-1 計画を追記 - TINY_C7_ULTRA_DESIGN.md: Phase PERF-ULTRA-ALLOC-OPT-1 セクション追加 - NEW: docs/analysis/PERF_ULTRA_ALLOC_OPT_1_PLAN.md - 詳細な実装計画書 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-11 20:05:09 +09:00
# Phase PERF-ULTRA-ALLOC-OPT-1 実装計画
**フェーズ名**: Phase PERF-ULTRA-ALLOC-OPT-1: C7 ULTRA alloc 内部最適化
**目的**: C7 ULTRA alloc現在 7.66% self%)の hot path を直線化し、5-6% まで削減
**期待効果**: 全体 Mixed throughput で +2-3M ops/s31.6M ops/s → 33-35M ops/s
---
## 背景
### Phase PERF-ULTRA-REBASE-1 の発見
2025-12-11 の perf 計測結果C4-C7 ULTRA 全て ON, Mixed 16-1024B, 10M cycles:
| 順位 | 関数 | self% | 判定 |
|------|------|-------|------|
| #1 | **C7 ULTRA alloc** | **7.66%** | ← **最大ボトルネック(新規発見)** |
| #2 | C4-C7 ULTRA free群 | 5.41% | 次の候補 |
| #3 | gate/front前段 | 2.51% | ✅ 既に十分薄い |
| #4 | header関連 | < 0.17% | ULTRA で削減済み |
### 戦略転換
**これまで**: v4/v5/v6 などの新世代を追加
**今後**: 既に当たりが出ている **ULTRA 内部を細かく削る**
理由:
- v6/v5 拡張は -12〜33% の大幅回帰C5/C4 対応で失敗)
- gate/front や header はもう改善の余地が少ない
- C7 ULTRA alloc の 7.66% を 5-6% に削れば全体効果 2-3%
---
## 実装対象ファイル
### 主要ファイル
- **core/box/tiny_c7_ultra_free_box.h**
- TinyC7UltraFreeTLS 構造体定義
- tiny_c7_ultra_alloc_fast() / tiny_c7_ultra_alloc_cold() の宣言
- **core/box/tiny_c7_ultra_free_box.c**
- tiny_c7_ultra_alloc_fast() 実装(メイン最適化対象)
- TLS context の定義と初期化
- **core/front/malloc_tiny_fast.h**
- tiny_c7_ultra_alloc() の呼び出し箇所
- alloc dispatcher からの pop ロジック
### 参照/確認ファイル
- **core/box/tiny_c7_ultra_free_env_box.h**
- tiny_c7_ultra_free_enabled() - ENV gate の状態確認
- **core/link_stubs.c** / **core/hakmem.c**
- 起動時の ENV 初期化タイミング確認
---
## 実装施策
### 1. TLS ヒットパスの直線化
**確認項目**:
```c
// tiny_c7_ultra_alloc_fast() のコード流
TinyC7UltraFreeTLS* ctx = tiny_c7_ultra_free_tls();
if (ctx->count > 0) {
void* base = ctx->freelist[--ctx->count];
return tiny_base_to_user_inline(base);
}
```
**チェック項目**:
- [ ] `tiny_c7_ultra_free_enabled()` が hot path に含まれていないか
- → lazy init 後は ENV 参照が不要。guard は不要。
- → if (!tiny_c7_ultra_free_enabled()) return NULL; のような early guard は削除
- [ ] `tiny_c7_ultra_free_tls()` が毎回呼ばれているか
- → TLS pointer cache で 1 回だけ取得し、ローカル変数に格納
- → 複数回アクセスなら cache 再利用
- [ ] hot path に条件分岐が何個あるか(目標: 1-2個
- count > 0 チェックのみ
- ユーザーポインタ計算は単純な演算のみ
**実装例**:
```c
// 最適化前の可能性が高い形
void* tiny_c7_ultra_alloc_fast(void) {
if (!tiny_c7_ultra_free_enabled()) return NULL;
TinyC7UltraFreeTLS* ctx = tiny_c7_ultra_free_tls();
if (ctx == NULL) return NULL; // ← 不要な null check
if (ctx->count == 0) return NULL;
...
}
// 最適化後expected
void* tiny_c7_ultra_alloc_fast(void) {
// tiny_c7_ultra_free_enabled() check は呼び出し側で済ませる
// malloc_tiny_fast.h で if (tiny_c7_ultra_free_enabled()) { tiny_c7_ultra_alloc_fast(); } の形)
TinyC7UltraFreeTLS* ctx = __thread_local_tls_c7; // 直接 TLS access
if (likely(ctx->count > 0)) {
void* base = ctx->freelist[--ctx->count];
return tiny_base_to_user_inline(base);
}
return NULL;
}
```
### 2. TLS freelist レイアウト最適化
**確認項目**:
```c
// TinyC7UltraFreeTLS 構造体の定義確認
typedef struct TinyC7UltraFreeTLS {
void* freelist[TINY_C7_ULTRA_FREE_CAP]; // 128 * 8B = 1024B
uint8_t count; // + 1B = 1025B
uintptr_t seg_base, seg_end; // + 16B = 1041B
} TinyC7UltraFreeTLS;
```
**チェック項目**:
- [ ] freelist と count が 1 cache line64Bに収まるか
- freelist[TINY_C7_ULTRA_FREE_CAP] サイズを確認(デフォルト 128 要素 = 1024B
- → 1024B は L1 キャッシュ(通常 32-64KBを超過しているので、count のみが hot
- → count アクセスは cache line 1 本で十分
- → freelist アクセスは cache misses が避けられないalloc pop は 128 個のブロックを引き出すのに 1 個アクセスだから許容)
- [ ] alloc hot datacountが先頭に配置されているか
- 現行は freq[capacity/count] が後ろ
- → count を先頭に移動すれば、alloc pop 時の cache line access 1 本count チェック)で済む
- [ ] seg_base / seg_end は確実に slow pathfree 時の segment learning
- → alloc は seq_base を参照しない → hot path から外すべき
**実装例**:
```c
// 最適化後(期待値)
typedef struct TinyC7UltraFreeTLS {
// Hot path 用64B以内想定
uint16_t count; // ← alloc pop で必須
uint8_t pad;
void* freelist[128]; // ← large block, only used for pop
// Cold path 用segment learning など)
uintptr_t seg_base, seg_end; // free 時のみ
} TinyC7UltraFreeTLS;
```
### 3. segment / page_meta アクセスの確認
**確認項目**:
```c
// tiny_c7_ultra_free_fast() の segment learning ロジック確認
if (unlikely(ctx->seg_base == 0)) {
SuperSlab* ss = ss_fast_lookup(base);
ctx->seg_base = (uintptr_t)ss;
ctx->seg_end = ctx->seg_base + (1u << ss->lg_size);
}
```
**チェック項目**:
- [ ] segment learning は cold pathunlikelyとして外出しされているか
- → 初回 free で 1 回だけ実行
- → 以降のすべての free は segment cached チェックで済む
- → alloc は segment を参照しない
- [ ] alloc hot path に page_meta access が混入していないか
- → alloc は count チェックと base pop だけ
- → page_meta は free 側のみで十分
- [ ] ss_fast_lookup() が cache miss 時のみか
- → segment learning 時unlikelyのみ
- → これは現状で十分1 回だけ)
---
## 計測戦略
### Phase 0: ベースライン(実装前)
```bash
# C7-only bench
HAKMEM_TINY_C7_ULTRA_FREE_ENABLED=1 \
perf record -F 5000 --call-graph dwarf -e cycles:u \
./bench_allocators_hakmem C7 1000000 400 1
# Mixed bench
HAKMEM_TINY_C7_ULTRA_FREE_ENABLED=1 HAKMEM_FREE_PATH_STATS=1 \
perf record -F 5000 --call-graph dwarf -e cycles:u \
./bench_random_mixed_hakmem 10000000 8192 1
# perf report で self% を記録
perf report --stdio | grep -A 5 "tiny_c7_ultra_alloc"
```
**期待値**: C7 ULTRA alloc の self% = **7.66%**(ベースライン)
### Phase 1: 各施策の実装と計測
実装後、同じ条件で 3 回計測して平均を取る:
```bash
# 最適化後の計測(同じコマンド)
for i in 1 2 3; do
HAKMEM_TINY_C7_ULTRA_FREE_ENABLED=1 \
perf record -F 5000 --call-graph dwarf -e cycles:u \
./bench_random_mixed_hakmem 10000000 8192 1
perf report --stdio > perf_opt_run$i.txt
done
```
**目標**:
- self% = 5-6%(削減幅 2-3%
- throughput = +2-3M ops/s31.6M → 33-35M ops/s
### Phase 2: 詳細分析
```bash
# 各関数の self% を比較表にまとめる
# - tiny_c7_ultra_alloc_fast vs tiny_c7_ultra_alloc_cold
# - ss_fast_lookup / segment learning の slow path confirmation
# - freelist access パターン
```
---
## 検証チェックリスト
実装完了時、以下をすべて確認:
- [ ] コンパイル成功warning なし)
- [ ] リンク成功
- [ ] C7-only bench で SEGV/assert なし
- [ ] Mixed bench で SEGV/assert なし
- [ ] perf 計測で self% が 5-6% に達している
- [ ] throughput が +2-3M ops/s 改善
- [ ] 各関数の分岐数が max 2-3直線化目標
- [ ] TLS access が 1 回だけcache 再利用)
---
## 実装時の注意点
### 1. ENV チェックの配置
```c
// ❌ Hot path 内で ENV check
if (tiny_c7_ultra_free_enabled()) { // ← hot path で毎回?
...
}
// ✅ 呼び出し側malloc_tiny_fast.h dispatcherでチェック
if (tiny_c7_ultra_free_enabled()) {
void* p = tiny_c7_ultra_alloc_fast();
if (p) return p;
}
```
### 2. TLS cache 再利用
```c
// ❌ 複数回 TLS access
TinyC7UltraFreeTLS* ctx = tiny_c7_ultra_free_tls();
if (ctx->count > 0) {
void* base = ctx->freelist[--ctx->count]; // ← 1回目
...
}
if (ctx->count > 0) { // ← 2回目の access
...
}
// ✅ ローカル変数に cache
TinyC7UltraFreeTLS* ctx = tiny_c7_ultra_free_tls();
uint16_t count = ctx->count;
if (likely(count > 0)) {
void* base = ctx->freelist[--count];
ctx->count = count;
return tiny_base_to_user_inline(base);
}
```
### 3. 構造体レイアウトの確認
```c
// 実装後、以下で hot field 配置を確認
// (gdb) p sizeof(TinyC7UltraFreeTLS)
// (gdb) p &ctx->count, &ctx->freelist
// → count が freelist より先頭にあることを確認
```
---
## 次フェーズへのつなぎ
### このフェーズの成功条件
- self% が 5-6% に低下
- throughput が +2-3M ops/s 達成
- 新しい bottleneck が浮上page_of/segment 判定, so_alloc など)
### Phase 2 の候補(自動昇格)
self% が 5-6% に達したら、次は **C4-C7 ULTRA free群5.41%** の軽量化を検討:
- free side のTLS push パス直線化
- page_of / segment 判定との連携最適化
---
## 参考資料
- **ホットパス分析**: `docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md`
- **C7 ULTRA 設計**: `docs/analysis/TINY_C7_ULTRA_DESIGN.md`
- **全体方針**: `CURRENT_TASK.md` 「Phase PERF-ULTRA-ALLOC-OPT-1 計画」