Files
hakmem/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md
Moe Charm (CI) 0f15adae4e Phase ALLOC-GATE-OPT-1: tiny_alloc_gate_fast 統計計測
- AllocGateStats 構造体追加(size2class/route/env/class分布)
- malloc_tiny_fast にカウンタ埋め込み
- ENV: HAKMEM_ALLOC_GATE_STATS (default 0)
- 挙動変更なし(計測のみ)

計測結果:
- Mixed: total=542k, size2class=0, route_calls=0, env_checks=275k, C4-C7=95.2%
  - size_to_class/route_for_class は完全削減済み(LUT 効果)
  - C4-C7 が 95% → ULTRA fast path が有効
  - env_checks ≈ c7_calls → C7 ULTRA の ENV gate が毎回呼ばれる
- C6-heavy: total=11 → malloc_tiny_fast はほぼ通らない(mid/pool 主体)

結論:
- alloc gate は既に十分最適化済み(LUT + ULTRA で削減済み)
- さらなる最適化余地は小さい(env_checks は軽量化済み、数%以下の効果)
- 次フェーズでは free dispatcher (29%) や C7 ULTRA refill (7%) など、他のボトルネックを狙う

詳細: docs/analysis/ALLOC_GATE_ANALYSIS.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-11 21:32:40 +09:00

19 KiB
Raw Blame History

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/sDEBUG/-O0 相当)

  • ss_map_lookup: 7.3% selffree 側での ptr→SuperSlab 判定が主、C7 v3 でも多い)
  • hak_super_lookup: 4.0% selflookup fallback 分)
  • classify_ptr: 0.64% selffree の入口 size→class 判定)
  • mid_desc_lookup: 0.43% selfmid 経路の記述子検索)
  • そのほか: 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%

    • ptr→page/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 経路での削減効果が出ている可能性がある。

Phase PERF-ULTRA-REBASE-2: C4-C7 ULTRA free最適化後の hotpath分析 (2025-12-11)

計測条件

  • ENV: HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE
  • ULTRA: C4-C7 全て ON
  • v4/v5/v6/free-front-v3: OFF
  • ワークロード: Mixed 16-1024B (1M iter, ws=400)
  • perf コマンド: perf record -F 5000 --call-graph dwarf -e cycles:u
  • Throughput: 42.63M ops/s(前回 31.61M から大幅改善、ws=400 vs 8192の差

Mixed 16-1024B ホットパスself% 上位)

順位 関数 self% 分類
#1 free 27.88% ベンチマーク wrapper
#2 tiny_alloc_gate_fast 23.57% alloc gate/front
#3 main 17.66% ベンチマーク harness
#4 malloc 6.94% ベンチマーク wrapper
#5 tiny_region_id_write_header.lto_priv.0 5.30% header 書き込み
#6 tiny_region_id_write_header.constprop.0 2.77% header 書き込み
#7 hak_super_lookup.lto_priv.1.lto_priv.0 0.69% Superslab 判定
#8 hak_pool_free 0.64% pool free

分析コメント

WARNING: サンプル数が極めて少ない238 samples

  • perf 計測時のサンプル数が238と非常に少なく、統計的信頼性が低い
  • ベンチマーク時間が0.023s23msと極めて短く、iters=1M / ws=400 の組み合わせでワークロードが軽すぎた可能性
  • 結果として、allocator 本体のホットパスULTRA alloc/freeがほとんど可視化されていない

可視化されたボトルネック:

  • tiny_alloc_gate_fast: 23.57% - alloc の gate/front 入口が最大のホットスポット
  • header 書き込み合計: 8.07%lto_priv.0: 5.30% + constprop.0: 2.77%
  • ULTRA 関連関数が不可視: tiny_c7_ultra_alloc や ULTRA free 群が上位20に入っていない
  • so_alloc/so_free も不可視: v3 backend 処理も検出されず

前フェーズPERF-ULTRA-REBASE-1との比較:

  • 前回ws=8192, iters=10M: C7 ULTRA alloc 7.66%, ULTRA free群 5.41%, so_alloc 3.60%
  • 今回ws=400, iters=1M: これらが全て不可視(< 0.63%
  • サンプル数: 前回1842 samples vs 今回238 samples約1/8

結論:

  • 計測条件の再検討が必要: ワークロードを重くするiters を 10M に増やす、または ws を拡大)
  • 現状の結果では次の最大ボトルネックを確定できない
  • gate/front23.57%)と header8.07%)が可視範囲での上位だが、これは軽すぎるワークロードで allocator 本体が見えていない可能性が高い

C6-heavy ホットパスself% 上位)

計測条件:

  • ENV: HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1
  • Throughput: 26.49M ops/s
  • Samples: 292 samplesやはり少ない
順位 関数 self% 分類
#1 hak_pool_free_v1_impl.part.0 19.89% pool v1 free
#2 hak_pool_try_alloc_v1_impl.part.0 14.46% pool v1 alloc
#3 free 11.80% ベンチマーク wrapper
#4 hak_free_at.constprop.0 9.26% 解放処理
#5 pthread_once@GLIBC_2.2.5 8.21% 初期化同期
#6 hak_super_lookup.lto_priv.1.lto_priv.0 7.07% Superslab 判定
#7 malloc 6.81% ベンチマーク wrapper
#8 __GI___pthread_self 2.62% TLS アクセス
#9 hak_pool_free 1.08% pool free wrapper

分析:

  • pool v1 が支配的: alloc 14.46% + free 19.89% = 34.35%
  • ULTRA は可視化されず: C6/C5/C4 ULTRA 関数が上位に入っていない
  • pthread_once が8.21%: 初期化同期のオーバーヘッドが目立つ(ワークロードが軽い証拠)

所感: C6-heavy でも pool v1 が主要経路として機能しているが、ULTRA の効果測定には不十分なサンプル数


Phase ALLOC-GATE-OPT-1 計測前の前提 (2025-12-11)

最新 perfREBASE-3 より:

  • tiny_alloc_gate_fast: self% ≈ 18%
  • tiny_route_for_class_calls: 267,967 calls alloc 側が主体)
  • FREE_DISPATCHER では ENV/route が既に snapshot で削減済み

→ alloc 側が未最適化の可能性が高い

計測目的:

  • size→class 変換の回数(毎回か?)
  • route_for_class 呼び出し回数(毎回か?初期化時のみか?)
  • alloc-side ENV check 回数C4-C7 ULTRA の ENV gate 等)
  • クラス別分布C0〜C7 のどれが主体か)

期待される発見:

  • route_for_class が alloc 毎に呼ばれているなら → snapshot 化で削減可能
  • size_to_class が重いなら → インライン化・LUT 化
  • C4〜C7 が 80% 以上なら → class-specific fast path 検討