Phase 11: ENV Snapshot maybe-fast API - NO-GO (-8.35%)
Phase 11 attempted to consolidate ENV snapshot overhead by: - Adding hakmem_env_snapshot_maybe_fast() API - Caching front_v3_snap pointer in HakmemEnvSnapshot - Replacing separate calls with single API at call sites Result: -8.35% regression (51.65M → 47.33M ops/s) Root cause: - maybe_fast() called in inline hot path functions - ctor_mode check accumulated on every call - Compiler optimization inhibited - Even 2-3 instructions are expensive at high frequency Lesson: ENV gate optimization should target gate itself, not call sites. All changes rolled back. Phase 11 FROZEN. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,206 @@
|
|||||||
|
# Phase 11: ENV Snapshot "maybe-fast" API - A/B テスト結果
|
||||||
|
|
||||||
|
## 判定: **NO-GO** (-8.35%)
|
||||||
|
|
||||||
|
Phase 11 の実装は **大幅な性能低下 (-8.35%)** を引き起こしたため、**rollback 済み**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 目的(Phase 11)
|
||||||
|
|
||||||
|
Phase 10 までで `free_tiny_fast()` 側の policy/route 固定費は削減されたが、Perf(Phase 10 後, Mixed)では次が目立っていた:
|
||||||
|
|
||||||
|
- `hakmem_env_snapshot` / `hakmem_env_snapshot_enabled`(合計 ~2%)
|
||||||
|
- `tiny_front_v3_snapshot_get`(~1%)
|
||||||
|
|
||||||
|
**Phase 11 の狙い**: ENV gate を維持したまま、hot path の参照回数を 1 回に集約し、同時に `tiny_front_v3_snapshot_get()` の ready-check を hot から消すこと。
|
||||||
|
|
||||||
|
**設計**:
|
||||||
|
1. `hakmem_env_snapshot_maybe_fast()` API を追加(enabled + snapshot を 1 回で取得)
|
||||||
|
2. `HakmemEnvSnapshot` に `front_v3_snap` ポインタをキャッシュ(ready-check を消す)
|
||||||
|
3. hot call sites (`tiny_legacy_fallback_box.h`, `malloc_tiny_fast.h`, `tiny_metadata_cache_hot_box.h`) を maybe-fast API に移行
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. A/B テスト結果(Mixed 10-run, clean env)
|
||||||
|
|
||||||
|
### Baseline (Phase 11 前)
|
||||||
|
|
||||||
|
```
|
||||||
|
Run 1/10: 52.40 M ops/s
|
||||||
|
Run 2/10: 51.44 M ops/s
|
||||||
|
Run 3/10: 52.21 M ops/s
|
||||||
|
Run 4/10: 51.94 M ops/s
|
||||||
|
Run 5/10: 51.49 M ops/s
|
||||||
|
Run 6/10: 50.86 M ops/s
|
||||||
|
Run 7/10: 51.59 M ops/s
|
||||||
|
Run 8/10: 51.38 M ops/s
|
||||||
|
Run 9/10: 51.29 M ops/s
|
||||||
|
Run 10/10: 51.90 M ops/s
|
||||||
|
|
||||||
|
Mean: 51.65 M ops/s
|
||||||
|
Median: 51.54 M ops/s
|
||||||
|
Stdev: 0.46 M ops/s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 11 後(最終版, CTOR=1)
|
||||||
|
|
||||||
|
```
|
||||||
|
Run 1/10: 47.56 M ops/s
|
||||||
|
Run 2/10: 47.45 M ops/s
|
||||||
|
Run 3/10: 47.62 M ops/s
|
||||||
|
Run 4/10: 47.97 M ops/s
|
||||||
|
Run 5/10: 47.59 M ops/s
|
||||||
|
Run 6/10: 45.89 M ops/s
|
||||||
|
Run 7/10: 47.96 M ops/s
|
||||||
|
Run 8/10: 47.23 M ops/s
|
||||||
|
Run 9/10: 47.33 M ops/s
|
||||||
|
Run 10/10: 46.72 M ops/s
|
||||||
|
|
||||||
|
Mean: 47.33 M ops/s
|
||||||
|
Median: 47.51 M ops/s
|
||||||
|
Stdev: 0.62 M ops/s
|
||||||
|
```
|
||||||
|
|
||||||
|
### 性能差分
|
||||||
|
|
||||||
|
| 指標 | Phase 11 前 | Phase 11 後 | 差分 |
|
||||||
|
|------|-------------|-------------|------|
|
||||||
|
| 平均 | 51.65 M ops/s | 47.33 M ops/s | **-4.32 M ops/s (-8.35%)** |
|
||||||
|
| 中央値 | 51.54 M ops/s | 47.51 M ops/s | -4.03 M ops/s (-7.82%) |
|
||||||
|
| 標準偏差 | 0.46 M ops/s | 0.62 M ops/s | +0.16 M ops/s |
|
||||||
|
|
||||||
|
**判定**: **NO-GO** (目標: +1.0% 以上、実際: **-8.35%**)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 根本原因分析
|
||||||
|
|
||||||
|
### 2.1 設計の致命的な欠陥
|
||||||
|
|
||||||
|
Phase 11 の `hakmem_env_snapshot_maybe_fast()` API は、以下の理由で **逆に遅くなった**:
|
||||||
|
|
||||||
|
1. **ctor_mode チェックのオーバーヘッド**
|
||||||
|
- 既存の `hakmem_env_snapshot_enabled()` は **1 回だけ**呼ばれ、結果が分岐に使われる
|
||||||
|
- Phase 11 では、`maybe_fast()` を **複数の call site で毎回**呼ぶため、**ctor_mode チェックが累積**
|
||||||
|
- 特に `tiny_legacy_fallback_free_base()` は free path で **毎回**呼ばれるため、オーバーヘッドが顕著
|
||||||
|
|
||||||
|
2. **call site の変更による最適化の阻害**
|
||||||
|
- 元のコード: `if (hakmem_env_snapshot_enabled()) { ... } else { legacy }`
|
||||||
|
- コンパイラが分岐予測を最適化しやすい(enabled==0 が大半)
|
||||||
|
- Phase 11: `env = hakmem_env_snapshot_maybe_fast(); if (env) { ... } else { legacy }`
|
||||||
|
- `maybe_fast()` が **無条件に呼ばれる**ため、gate チェックが毎回発生
|
||||||
|
- `ctor_mode` の読み取りが毎回発生(TLS read または global read)
|
||||||
|
|
||||||
|
3. **HAKMEM_ENV_SNAPSHOT_CTOR の未設定**
|
||||||
|
- 初期実装では `HAKMEM_ENV_SNAPSHOT_CTOR=1` をプロファイルに追加していなかった
|
||||||
|
- `ctor_mode == -1` のとき、lazy init path が毎回走る(getenv 呼び出しは不要だが、gate チェックは発生)
|
||||||
|
- `CTOR=1` を追加しても性能は改善せず(-8.35%)
|
||||||
|
|
||||||
|
### 2.2 試行錯誤の履歴
|
||||||
|
|
||||||
|
1. **Version 1**: `ctor_mode` チェックなし、gate チェックのみ
|
||||||
|
- 結果: -7.6% (NO-GO)
|
||||||
|
- 原因: gate チェックが毎回発生
|
||||||
|
|
||||||
|
2. **Version 2**: `ctor_mode` チェックなし、gate==0 を LIKELY に設定
|
||||||
|
- 結果: -8.6% (NO-GO)
|
||||||
|
- 原因: 分岐予測ヒントが MIXED プロファイル(ENV_SNAPSHOT=1)で逆効果
|
||||||
|
|
||||||
|
3. **Version 3**: `ctor_mode` チェックを復活(既存の `hakmem_env_snapshot_enabled()` と同等)
|
||||||
|
- 結果: -5.9% (NO-GO)
|
||||||
|
- 原因: `ctor_mode` チェック自体がオーバーヘッド
|
||||||
|
|
||||||
|
4. **Final**: `HAKMEM_ENV_SNAPSHOT_CTOR=1` をプロファイルに追加
|
||||||
|
- 結果: **-8.35% (NO-GO)**
|
||||||
|
- 原因: `ctor_mode==1` でも、**`maybe_fast()` 呼び出し自体がオーバーヘッド**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 正しいアプローチ(Phase 11 では不可能)
|
||||||
|
|
||||||
|
Phase 11 の設計は **根本的に誤り**。正しくは:
|
||||||
|
|
||||||
|
1. **`maybe_fast()` を関数の入口で 1 回だけ呼ぶ**
|
||||||
|
- 複数の call site で再利用する(ローカル変数にキャッシュ)
|
||||||
|
|
||||||
|
2. **しかし、`tiny_legacy_fallback_free_base()` は free path で毎回呼ばれる**
|
||||||
|
- そこで `maybe_fast()` を呼ぶと、毎回 `ctor_mode` チェックが発生
|
||||||
|
- 既存のコードでは、`hakmem_env_snapshot_enabled()` が **1 回だけ**呼ばれる設計になっている
|
||||||
|
|
||||||
|
3. **結論**: **Phase 11 の maybe-fast API は構造的に不可能**
|
||||||
|
- ENV snapshot 参照の固定費削減は、**call site の変更ではなく、ENV snapshot 自体の最適化**(例: TLS → register cache)が必要
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Perf 確認(未実施)
|
||||||
|
|
||||||
|
Phase 11 が -8.35% の大幅な性能低下を引き起こしたため、perf 確認は実施せず。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 健康診断(未実施)
|
||||||
|
|
||||||
|
NO-GO のため、健康診断は実施せず。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Rollback 状況
|
||||||
|
|
||||||
|
Phase 11 の全変更を rollback 済み:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -- core/bench_profile.h core/box/hakmem_env_snapshot_box.c \
|
||||||
|
core/box/hakmem_env_snapshot_box.h core/box/tiny_legacy_fallback_box.h \
|
||||||
|
core/box/tiny_metadata_cache_hot_box.h core/front/malloc_tiny_fast.h
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 次のステップ
|
||||||
|
|
||||||
|
Phase 11 は **設計ミス** のため、放棄。
|
||||||
|
|
||||||
|
ENV snapshot 参照の固定費削減(~2-3%)を狙う場合、以下の代替アプローチを検討:
|
||||||
|
|
||||||
|
1. **ENV snapshot を TLS → レジスタにキャッシュ**
|
||||||
|
- 関数入口で 1 回だけ TLS read し、関数内で再利用
|
||||||
|
- ただし、`tiny_legacy_fallback_free_base()` などの **inline 関数では効果が薄い**
|
||||||
|
|
||||||
|
2. **ENV snapshot をコンストラクタで確定**
|
||||||
|
- `HAKMEM_ENV_SNAPSHOT_CTOR=1` を常に有効化
|
||||||
|
- gate を **const に昇格**(ただし、ENV の動的変更が不可能になる)
|
||||||
|
|
||||||
|
3. **ENV snapshot 自体を廃止し、個別 gate に戻す**
|
||||||
|
- Phase 4 E1 の ENV snapshot は +3.92% の効果があったが、その後のフェーズでオーバーヘッドが累積している可能性
|
||||||
|
- ただし、rollback は大規模
|
||||||
|
|
||||||
|
4. **別の最適化ターゲットを探す**
|
||||||
|
- Perf の最新プロファイルで、次の高コストパスを特定
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 教訓
|
||||||
|
|
||||||
|
1. **inline 関数で毎回呼ばれる helper は、1 命令でも重い**
|
||||||
|
- `hakmem_env_snapshot_maybe_fast()` は 2-3 命令だが、free path で毎回呼ばれると -8% の劣化
|
||||||
|
|
||||||
|
2. **ENV gate の最適化は、call site ではなく gate 自体で行うべき**
|
||||||
|
- call site を変更すると、コンパイラの最適化を阻害する可能性が高い
|
||||||
|
|
||||||
|
3. **Constructor init (CTOR=1) は万能ではない**
|
||||||
|
- gate が確定しても、**呼び出しコスト**は残る
|
||||||
|
|
||||||
|
4. **A/B テストは必須**
|
||||||
|
- Phase 11 は "理論的には速くなるはず" だったが、実測で -8.35% の劣化
|
||||||
|
- 小さな変更でも、必ず A/B テストで検証すること
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## まとめ
|
||||||
|
|
||||||
|
Phase 11 の ENV Snapshot "maybe-fast" API は、**-8.35% の大幅な性能低下**を引き起こし、**NO-GO** と判定。
|
||||||
|
|
||||||
|
**原因**: `maybe_fast()` 呼び出しが free path で毎回発生し、`ctor_mode` チェックのオーバーヘッドが累積。
|
||||||
|
|
||||||
|
**結論**: Phase 11 は**設計ミス**であり、rollback 済み。ENV snapshot 参照の固定費削減は、別のアプローチ(TLS → register cache, constructor 確定など)を検討する必要がある。
|
||||||
Reference in New Issue
Block a user