Files
hakmem/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md
Moe Charm (CI) b381219a68 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

240 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TINY CPU Hotpath Userland Analysis (Phase49)
- プロファイル: Mixed 161024B, ws=400, iters=1,000,000
`HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_HOTHEAP_V2=0 HAKMEM_TINY_LARSON_FIX=1`
- コマンド: `perf stat -e cycles:u,instructions:u,branch-misses:u ./bench_random_mixed_hakmem 1000000 400 1`
`perf record -g -e cycles:u -o perf.data.mixed_u ./bench_random_mixed_hakmem 1000000 400 1`
## perf statuserlandのみ
- Throughput: **41,000,086 ops/s**
- cycles:u=126,239,279 / instructions:u=324,810,642 → IPC≈2.57
- branch-misses:u=1,186,675
- time=0.0438suser 0.0295s / sys 0.0143s
## perf recordcycles:u上位シンボルself%
- free: 24.3% — front入口/libc wrapper 部分
- malloc: 18.0% — 同上
- main: 15.3% — ベンチハーネス
- tiny_heap_page_pop.lto_priv.0: 8.8% — TinyHeapBox ホット pop
- hak_super_lookup.lto_priv.*: 7.9% — Superslab 判定front→TinyHeapBox 境界前)
- tiny_heap_page_becomes_empty.constprop.0: 5.9% — empty 遷移処理
- __memset_avx2_unaligned_erms: 4.0% — ユーザランド初期化first-touch
- tiny_region_id_write_header: 2.4% — header 書き込み
- その他: __pthread_self / hak_free_at / tiny_heap_meta_flush_page などが1〜2%台
## 所感
- ベンチ自身の malloc/free/main が大きいが、allocator 側では **tiny_heap_page_pop / hak_super_lookup / tiny_heap_page_becomes_empty** が目立つ。
- userland側でも memset が残っており、first-touch 削減(ヘッダ書き込み削減や初期化遅延)余地がある。
## Phase50 で削るターゲット箱(提案)
- **TinyHeapBoxC7/C6の pop/empty + hak_super_lookup 前段**
- super_lookup 依存の範囲チェックを軽量化 or キャッシュ化。
- pop/empty 内の分岐を整理し、C7 SAFE の理想パスcurrent_page固定に寄せる。
- header write / memset を最小化する実験スイッチを検討。
## C7 v3 ON, Mixed 161024B (ws=400, iters=1,000,000, userland cycles)
環境: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_HOTHEAP_V2=0 HAKMEM_POOL_V2_ENABLED=0 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80`
- Throughput: **48.96M ops/s**(前回 v3 ON と同レンジ)
- perf record `cycles:u` (171 samples, release build without symbols):
- 上位は `free` / `malloc` / `main` の無名フレームに潰れてしまい、非C7 Tiny front の細かい関数名が出ず。
- シンボル再取得には DEBUG/記号付きビルドで perf し直す必要あり。
- 所感: C7 v3 以外のホットパス特定には、size→class→route 前段や unified cache hit パスを再シンボル化して見る必要がある。現状のバイナリでは細部が見えない。
## Mixed 161024B (ws=400, iters=1,000,000, userland cycles, C7 v3 ON, DEBUGビルド)
環境: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_HOTHEAP_V2=0 HAKMEM_POOL_V2_ENABLED=0 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80`
ビルド: `make clean && CFLAGS='-O2 -g …' USE_LTO=0 OPT_LEVEL=2 NATIVE=0 make bench_random_mixed_hakmem`
- Throughput: **46.146.3M ops/s**(リリース時の ~49M よりやや低いが符号付きビルドで許容)
- perf record `cycles:u -F5000 --call-graph dwarf` (200 samples) の self% 上位C7 v3 以外を抜粋):
- free 23.5%, malloc 18.8%, main 13.7%(ベンチハーネス由来)
- **tiny_region_id_write_header 6.7%**
- **ss_map_lookup 3.6%**
- unified_cache_enabled 2.8%
- tiny_guard_is_enabled 2.2%
- classify_ptr 1.4%size→class 判定系)
- mid_desc_lookup 1.3%
- hak_free_at 0.9%, hak_pool_mid_lookup 0.7%
- so_alloc/so_free 合計 ~7%C7 v3 本体)
- 所感非C7 Tiny front 目線):
- header 書き込みtiny_region_id_write_headerが依然目立つ。
- Superslab 判定前の `ss_map_lookup` が 34% 程度残っている。
- route/guard 判定unified_cache_enabled / tiny_guard_is_enabled / classify_ptrが合わせて ~6% 程度。
- 次は「size→class→route 前段header」をフラット化するターゲットが有力。
## TF3 事前計測DEBUGシンボル, front v3+LUT ON, C7-only v3
環境: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_HOTHEAP_V2=0 HAKMEM_POOL_V2_ENABLED=0 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80 HAKMEM_TINY_FRONT_V3_ENABLED=1 HAKMEM_TINY_FRONT_V3_LUT_ENABLED=1`
ビルド: `BUILD_FLAVOR=debug OPT_LEVEL=0 USE_LTO=0 EXTRA_CFLAGS=-g`
ベンチ: `perf record -F5000 --call-graph dwarf -e cycles:u -o perf.data.tiny_front_tf3 ./bench_random_mixed_hakmem 1000000 400 1`
Throughput: **12.39M ops/s**DEBUG/-O0 相当)
- `ss_map_lookup`: **7.3% self**free 側での ptr→SuperSlab 判定が主、C7 v3 でも多い)
- `hak_super_lookup`: **4.0% self**lookup fallback 分)
- `classify_ptr`: **0.64% self**free の入口 size→class 判定)
- `mid_desc_lookup`: **0.43% self**mid 経路の記述子検索)
- そのほか: free/malloc/main が約 30% 強、header write 系は今回のデバッグログに埋もれて確認できず。
所感:
## Phase HF1DEBUG, front v3+LUT+fast classify+mid_desc_cache ON
- ビルド: `CFLAGS='-O0 -g' USE_LTO=0 OPT_LEVEL=0 NATIVE=0`
- ENV: `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE`, `HAKMEM_MID_DESC_CACHE_ENABLED=1`
- コマンド: `perf record -F 5000 --call-graph dwarf -e cycles:u -o perf.data.tiny_mixed_hf1 ./bench_random_mixed_hakmem 1000000 400 1`
- self% 上位perf_tiny_mixed_hf1.txt 抜粋):
- tiny_alloc_gate_fast 16.85%
- free 13.63% / malloc 13.34% / main 9.02%(ベンチ枠)
- __memset_avx2_unaligned_erms 5.65%(初期化)
- hak_super_registry_init 5.57%(初期化)
- so_alloc_fast 2.41%, unified_cache_push 2.23%
- tiny_front_v3_enabled 2.23%, tiny_front_v3_lut_lookup 2.21%
- smallobject_hotbox_v3_can_own_c7 1.94%
- tiny_region_id_write_header 1.82%
- ss_map_lookup 1.61%, mid_desc_lookup_cached 0.98%, classify_ptr 0.65%
所感: TF3 + mid_desc_cache 適用後、ss_map_lookup/self% は 1.6% まで沈み、tiny_region_id_write_header が引き続き ~1.8% で上位。次の削り候補は header 書き込み回数削減 or front前段の小枝刈り。
- front v3 + LUT ON でも free 側の `ss_map_lookup` / `hak_super_lookup` が ~11% 程度残っており、ここを FAST classify で直叩きする余地が大きい。
- `classify_ptr` は 1% 未満だが、`ss_map_lookup` とセットで落とせれば +5〜10% の目標に寄せられる見込み。
### Front v3 snapshot 導入メモ
- `TinyFrontV3Snapshot` を追加し、`unified_cache_on / tiny_guard_on / header_mode` を 1 回だけキャッシュする経路を front v3 ON 時に通すようにした(デフォルト OFF
- Mixed 161024B (ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF) で挙動変化なしslow=1 維持)。ホットスポットは依然 front 前段 (`tiny_region_id_write_header`, `ss_map_lookup`, guard/route 判定) が中心。
### Front v3 size→class LUT メモPhase2-A 実装済み、A/B これから)
- ENV `HAKMEM_TINY_FRONT_V3_LUT_ENABLED` を追加(デフォルト OFF。front v3 ON 時に size→class→route を Tiny 専用 LUT から 1 ルックアップで取得し、従来の `hak_tiny_size_to_class` + route 読みを代替する。
- LUT は起動時に既存の size→class 変換と route スナップショットをそのまま写経して構築するため挙動は変えない。
- A/B (Mixed 161024B, ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF, front v3 ON):
- LUT=0: 44.820M ops/s
- LUT=1: 45.231M ops/s+0.9%
- HEAP_STATS は TinyHeap v1 経路外のため出力なし。C7_PAGE_STATS は prepare_calls=2446 で変化なし。
### Header v3 (C7-only) 簡易スキップ実験
- ENV: `HAKMEM_TINY_HEADER_V3_ENABLED` / `HAKMEM_TINY_HEADER_V3_SKIP_C7` を追加。C7 v3 alloc 時だけ tiny_region_id_write_header を通さず 1byte store にする。
- Mixed 161024B (ws=400, iters=1M, front v3 ON, LUT ON, route_fast=0, Tiny/Pool v2 OFF):
- header_v3=0: 44.29M ops/s, C7_PAGE_STATS prepare_calls=2446
- header_v3=1 + SKIP_C7=1: 43.68M ops/s約 -1.4%、prepare_calls=2446、fallback/page_of_fail=0
- 所感: C7 v3 のヘッダ簡略だけでは perf 改善は見えず。free 側のヘッダ依存を落とす or header light/off を別箱で検討する必要あり。
## TF3: ptr fast classify 実装後の A/BC7-only v3, front v3+LUT ON
- Releaseビルド, ws=400, iters=1M, ENV は TF3 基準 (`C7_SAFE`, C7_HOT=1, v2/pool v2=0, v3 classes=0x80, front v3/LUT ON)。
- Throughput (ops/s):
- PTR_FAST_CLASSIFY=0: **33.91M**
- PTR_FAST_CLASSIFY=1: **36.67M**(約 +8.1%
- DEBUG perf同ENV, gate=1, cycles@5k, dwarf: `ss_map_lookup` self が **7.3% → 0.9%**`hak_super_lookup` はトップから消失。代わりに TLS 内のページ判定 (`smallobject_hotbox_v3_can_own_c7` / `so_page_of`) が合計 ~5.5% へ移動。`classify_ptr` は 23% まで微増(外れ時のフォールバック分)。
- 所感: C7 v3 free の Superslab lookup 往復をほぼ除去でき、目標の +5〜10% に収まる結果。fast path 判定の TLS 走査が新たなホットスポットだが、現状コストは lookup より低く許容範囲。
## Phase PERF-ULTRA-REBASE-1 Results (2025-12-11 19:43:49)
### 計測環境
- **日時**: 2025-12-11 19:43:49
- **ワークロード**: Mixed 16-1024B, ws=8192, iters=10,000,000
- **ENV設定**:
- `HAKMEM_TINY_C7_ULTRA_FREE_ENABLED=1`
- `HAKMEM_TINY_C6_ULTRA_FREE_ENABLED=1`
- `HAKMEM_TINY_C5_ULTRA_FREE_ENABLED=1`
- `HAKMEM_TINY_C4_ULTRA_FREE_ENABLED=1`
- その他 ULTRA 以外のフラグは OFFv6/v4/v5/free-front-v3 等)
- **perf コマンド**: `perf record -F 5000 --call-graph dwarf -e cycles:u`
- **Throughput**: **31.61M ops/s**
- **Samples**: 1842 samples, 約1.36B cycles
### perf report 主要関数 self% トップ20
1. **free**: 25.48%libc wrapper/ベンチ由来)
2. **main**: 23.60%(ベンチマークハーネス)
3. **malloc**: 21.13%libc wrapper/ベンチ由来)
4. **tiny_c7_ultra_alloc**: 7.66%
5. **tiny_c7_ultra_free**: 3.50%
6. **so_free**: 2.47%
7. **so_alloc_fast**: 2.39%
8. **tiny_c7_ultra_page_of**: 1.78%
9. **classify_ptr**: 1.15%
10. **tiny_c7_ultra_segment_from_ptr**: 0.96%
11. **tiny_front_v3_lut_lookup**: 0.91%
12. **ss_map_lookup**: 0.79%
13. **tiny_c5_ultra_free_fast**: 0.69%
14. **hak_free_at**: 0.68%
15. **tiny_c6_ultra_free_fast**: 0.54%
16. **tiny_guard_is_enabled**: 0.45%
17. **tiny_c6_ultra_free_tls**: 0.34%
18. **tiny_heap_page_becomes_empty**: 0.23%
19. **tiny_c4_ultra_free_fast**: 0.17%
20. **tiny_c5_ultra_free_tls**: 0.17%
### カテゴリ別集計
- **ベンチマーク関連main + free + malloc wrapper**: 70.21%
- **C4-C7 ULTRA free関数群の合計**: 5.41%
- tiny_c7_ultra_free: 3.50%
- tiny_c5_ultra_free_fast: 0.69%
- tiny_c6_ultra_free_fast: 0.54%
- tiny_c6_ultra_free_tls: 0.34%
- tiny_c4_ultra_free_fast: 0.17%
- tiny_c5_ultra_free_tls: 0.17%
- **C7 ULTRA alloc**: 7.66%
- **so_alloc系v3 backend alloc**: 3.60%
- so_alloc_fast: 2.39%
- so_alloc: 1.21%
- **so_free系v3 backend free**: 2.47%
- **gate/front関連**: 2.51%
- classify_ptr: 1.15%
- tiny_front_v3_lut_lookup: 0.91%
- tiny_guard_is_enabled: 0.45%
- **page_of/segment判定**: 2.74%
- tiny_c7_ultra_page_of: 1.78%
- tiny_c7_ultra_segment_from_ptr: 0.96%
- **ss_map_lookupSuperslab判定**: 0.79%
- **hak_free_at**: 0.68%
- **tiny_heap_page_becomes_empty**: 0.23%
### 分析コメント
1. **C7 ULTRA alloc が最大ホットスポット7.66%**
- C7 ULTRA の allocate パスが allocator 内で最も重いボトルネック
- 次点は ULTRA free 群5.41%だが、alloc が約1.4倍重い
2. **so_alloc系v3 backendが3.60%で続く**
- C7 v3 の backend alloc 処理が依然として可視
- so_free は2.47%でバランス良好
3. **page_of/segment判定が2.74%**
- tiny_c7_ultra_page_of1.78%とsegment_from_ptr0.96%)の合計
- ULTRA free内でのptr→page/segment解決コストが目立つ
4. **gate/front前段は2.51%に留まる**
- classify_ptr1.15%、LUT lookup0.91%、guard判定0.45%
- 以前のフェーズより改善されており、現時点では相対的に軽い
5. **ss_map_lookup は0.79%まで低下**
- TF3 + PTR_FAST_CLASSIFY の効果で Superslab lookup が大幅減
- 依然残っているが、優先度は下がった
6. **header書き込みが不可視**
- tiny_region_id_write_header が上位20に入っていない< 0.17%
- ULTRA経路では header 書き込みコストが削減されている可能性
### 次の候補箱(ボトルネック優先順位)
1. **最優先: C7 ULTRA alloc7.66%**
- tiny_c7_ultra_alloc の内部最適化が最大の削減ポテンシャル
- キャッシュヒット率向上TLS構造簡素化分岐削減などを検討
2. **第2優先: C4-C7 ULTRA free群5.41%**
- 特に tiny_c7_ultra_free3.50%が中心
- page_of/segment判定2.74%との重複があるためptr解決の高速化が有効
3. **第3優先: so_alloc系 backend3.60%**
- C7 v3 backend alloc 処理の軽量化
- fast path のインライン化や TLS キャッシュ強化
4. **第4優先: page_of/segment判定2.74%**
- ptrpage/segment 解決の最適化
- TLS キャッシュや LUT ベースの高速化を検討
5. **監視対象: gate/front前段2.51%**
- 現状は許容範囲だがさらなる改善余地あり
- classify_ptr fast path 強化や LUT の効率化
### 所感
- **C7 ULTRA alloc が明確な最大ボトルネック**として浮上次のフェーズでは alloc パスの内部最適化TLS キャッシュヒット率向上構造簡素化分岐削減に注力すべき
- ULTRA free 群も5.41%と無視できないがalloc が約1.4倍重いためalloc を先に削るのが効率的
- gate/front 前段は以前のフェーズより改善されており現時点での優先度は下がった
- header 書き込みが上位20に入っていないのはULTRA 経路での削減効果が出ている可能性がある