diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index aefda789..02eb1025 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -694,3 +694,138 @@ C7 ULTRA alloc は tiny_c7_ultra.c 内最適化で self%/throughput ともほぼ - C4/C5/C6 ULTRA により Mixed throughput +9.3% - 全クラス(C4-C7)で統一された TLS push パターン確立 + + +--- + +## Phase PERF-ULTRA-REBASE-3: 正しいパラメータで再計測 (2025-12-11) + +**問題**: Phase REBASE-2 で iters=1M, ws=400 は軽すぎて ULTRA 関数が invisible(238 samples のみ)だったため、正しいパラメータで再実施。 + +**修正内容**: iters=10M, ws=8192(Phase REBASE-1 と同じパラメータで再計測) + +### Mixed 16-1024B ホットパス(self% 上位, 1890 samples) + +| 順位 | 関数 | self% | 分類 | +|------|------|-------|------| +| **#1** | **free** | **29.22%** | free dispatcher | +| **#2** | **main** | **19.27%** | benchmark overhead | +| **#3** | **tiny_alloc_gate_fast** | **18.17%** | alloc gate | +| #4 | tiny_c7_ultra_refill | 6.92% | C7 ULTRA refill | +| #5 | malloc | 5.00% | malloc dispatcher | +| #6 | tiny_region_id_write_header (lto_priv) | 4.29% | header write | +| #7 | hak_super_lookup | 2.90% | segment lookup | +| #8 | hak_free_at | 2.36% | free routing | +| #9 | so_free | 2.60% | v3 free | +| #10 | so_alloc_fast | 2.46% | v3 alloc | + +**スループット**: +- Mixed 16-1024B: **30.6M ops/s** (10M iter, ws=8192) +- C6-heavy 257-768B: **17.0M ops/s** (10M iter, ws=8192) + +### C6-heavy ホットパス(self% 上位, 3027 samples) + +| 順位 | 関数 | self% | 分類 | +|------|------|-------|------| +| **#1** | **worker_run** | **10.66%** | benchmark loop | +| **#2** | **free** | **25.13%** | free dispatcher | +| **#3** | **hak_free_at** | **19.89%** | free routing | +| #4 | hak_pool_free_v1_impl | 10.16% | pool v1 free | +| #5 | hak_pool_try_alloc_v1_impl | 10.95% | pool v1 alloc | +| #6 | pthread_once | 5.94% | initialization | +| #7 | hak_pool_free_fast_v2_impl | 3.94% | pool v2 fallback | +| #8 | hak_super_lookup | 4.39% | segment lookup | +| #9 | malloc | 3.77% | malloc dispatcher | +| #10 | hak_pool_try_alloc (part) | 0.66% | pool alloc slow | + +### 分析 + +**Mixed 16-1024B での変化**: +- free: 29.22% (benchmark 外のディスパッチャ部分) +- tiny_alloc_gate_fast: 18.17% (前回 REBASE-1 の計測と一致) +- C7 ULTRA refill: 6.92% (前回 REBASE-1 では 7.66% だったが、ワークロードにより変動範囲内) +- C4-C7 ULTRA free 群: 個別には invisible (< 1% each) だが、合計で数%程度 +- so_alloc系: 2.46% (so_alloc_fast) + 1.16% (so_alloc) = 約 3.62% +- page_of/segment: hak_super_lookup 2.90% + +**C6-heavy での状況**: +- pool v1 経路が dominant: hak_pool_free_v1_impl (10.16%) + hak_pool_try_alloc_v1_impl (10.95%) +- hak_free_at: 19.89% (free routing overhead が大きい) +- hak_super_lookup: 4.39% (segment lookup) +- C6-heavy は完全に pool v1 経路を使用(前回の FREE_PATH_STATS 分析と一致) + +### 次のボトルネック確定 + +**Mixed では**: +- **free dispatcher 全体(29.22%)** が最大 +- tiny_alloc_gate_fast(18.17%)が第二 +- C7 ULTRA refill(6.92%)は既に薄い部類 + +**C6-heavy では**: +- **hak_free_at(19.89%)** が最大の allocator 内部ボトルネック +- pool v1 alloc/free(各 10%)は構造的なコスト +- hak_super_lookup(4.39%)も削減余地あり + +### 次フェーズ候補 + +1. **Option A: free dispatcher 最適化** (Mixed 向け) + - free() 内部の routing logic を最適化 + - hak_free_at の分岐を削減 + - 期待効果: Mixed で free 29% → 25% 程度に削減(+1-2M ops/s) + +2. **Option B: alloc gate 最適化** (Mixed 向け) + - tiny_alloc_gate_fast(18.17%)の内部最適化 + - class 判定や routing の直線化 + - 期待効果: Mixed で alloc gate 18% → 15% 程度に削減(+1-2M ops/s) + +3. **Option C: C6-heavy mid/pool 再設計** (C6 向け) + - hak_free_at(19.89%)の C6 専用 fast path 追加 + - pool v1 の lookup overhead 削減 + - 期待効果: C6-heavy で 17M → 20-25M ops/s + +**推奨**: Option A または B(Mixed が本線のため)。C6-heavy は別途 mid 再設計フェーズで対応。 + +**次フェーズ決定**: +- Mixed: free dispatcher ≈29%, alloc gate ≈18%, C7 ULTRA refill ≈6.9% +- 次は **FREE-DISPATCHER-OPT-1** で hak_free_at 系のルーティング層を薄くする + +--- + +### 生成ファイル + +1. `/mnt/workdisk/public_share/hakmem/perf_ultra_mixed_v3.txt` - Mixed 16-1024B の complete perf report (1890 samples) +2. `/mnt/workdisk/public_share/hakmem/perf_ultra_c6_v3.txt` - C6-heavy の complete perf report (3027 samples) +3. `/mnt/workdisk/public_share/hakmem/CURRENT_TASK_PERF_REBASE3.md` - 詳細レポート + +--- + +## Phase FREE-DISPATCHER-OPT-1: free dispatcher 統計計測 (2025-12-11) + +**目的**: free dispatcher(29%)の内訳を細分化 +- domain 判定(tiny/mid/large)の比率 +- route 判定(ULTRA/legacy/pool/v6)の比率 +- ENV check / route_for_class 呼び出し回数 + +**方針**: 統計カウンタを追加し、挙動は変えない。次フェーズ(OPT-2)で最適化実装を判断。 + +**実装内容**: +- FreeDispatchStats 構造体追加(ENV gated, default OFF) +- hak_free_at / fg_classify_domain / tiny_free_gate にカウンタ埋め込み +- 挙動変更なし(計測のみ) + +**ENV**: `HAKMEM_FREE_DISPATCH_STATS=1` で有効化(デフォルト 0) + +**計測結果**: +- Mixed: total=8,081, route_calls=267,967, env_checks=9 + - BENCH_FAST_FRONT により大半は早期リターン + - route_for_class は主に alloc 側で呼ばれる + - ENV check は初期化時の 9回のみ +- C6-heavy: total=500,099, route_calls=1,034, env_checks=9 + - fg_classify_domain に到達する free が多い + - route_for_class 呼び出しは極小(snapshot 効果) + +**結論**: +- ENV check は既に十分最適化されている(初期化時のみ) +- route_for_class は alloc 側での呼び出しが主で、free 側は snapshot で O(1) +- 次フェーズ(OPT-2)では別のアプローチを検討(domain 判定の早期化など) + diff --git a/CURRENT_TASK_PERF_REBASE3.md b/CURRENT_TASK_PERF_REBASE3.md new file mode 100644 index 00000000..b0dcf0aa --- /dev/null +++ b/CURRENT_TASK_PERF_REBASE3.md @@ -0,0 +1,94 @@ +## Phase PERF-ULTRA-REBASE-3: 正しいパラメータで再計測 (2025-12-11) + +**問題**: Phase REBASE-2 で iters=1M, ws=400 は軽すぎて ULTRA 関数が invisible(238 samples のみ)だったため、正しいパラメータで再実施。 + +**修正内容**: iters=10M, ws=8192(Phase REBASE-1 と同じパラメータで再計測) + +### Mixed 16-1024B ホットパス(self% 上位, 1890 samples) + +| 順位 | 関数 | self% | 分類 | +|------|------|-------|------| +| **#1** | **free** | **29.22%** | free dispatcher | +| **#2** | **main** | **19.27%** | benchmark overhead | +| **#3** | **tiny_alloc_gate_fast** | **18.17%** | alloc gate | +| #4 | tiny_c7_ultra_refill | 6.92% | C7 ULTRA refill | +| #5 | malloc | 5.00% | malloc dispatcher | +| #6 | tiny_region_id_write_header (lto_priv) | 4.29% | header write | +| #7 | hak_super_lookup | 2.90% | segment lookup | +| #8 | hak_free_at | 2.36% | free routing | +| #9 | so_free | 2.60% | v3 free | +| #10 | so_alloc_fast | 2.46% | v3 alloc | + +**スループット**: +- Mixed 16-1024B: **30.6M ops/s** (10M iter, ws=8192) +- C6-heavy 257-768B: **17.0M ops/s** (10M iter, ws=8192) + +### C6-heavy ホットパス(self% 上位, 3027 samples) + +| 順位 | 関数 | self% | 分類 | +|------|------|-------|------| +| **#1** | **worker_run** | **10.66%** | benchmark loop | +| **#2** | **free** | **25.13%** | free dispatcher | +| **#3** | **hak_free_at** | **19.89%** | free routing | +| #4 | hak_pool_free_v1_impl | 10.16% | pool v1 free | +| #5 | hak_pool_try_alloc_v1_impl | 10.95% | pool v1 alloc | +| #6 | pthread_once | 5.94% | initialization | +| #7 | hak_pool_free_fast_v2_impl | 3.94% | pool v2 fallback | +| #8 | hak_super_lookup | 4.39% | segment lookup | +| #9 | malloc | 3.77% | malloc dispatcher | +| #10 | hak_pool_try_alloc (part) | 0.66% | pool alloc slow | + +### 分析 + +**Mixed 16-1024B での変化**: +- free: 29.22% (benchmark 外のディスパッチャ部分) +- tiny_alloc_gate_fast: 18.17% (前回 REBASE-1 の計測と一致) +- C7 ULTRA refill: 6.92% (前回 REBASE-1 では 7.66% だったが、ワークロードにより変動範囲内) +- C4-C7 ULTRA free 群: 個別には invisible (< 1% each) だが、合計で数%程度 +- so_alloc系: 2.46% (so_alloc_fast) + 1.16% (so_alloc) = 約 3.62% +- page_of/segment: hak_super_lookup 2.90% + +**C6-heavy での状況**: +- pool v1 経路が dominant: hak_pool_free_v1_impl (10.16%) + hak_pool_try_alloc_v1_impl (10.95%) +- hak_free_at: 19.89% (free routing overhead が大きい) +- hak_super_lookup: 4.39% (segment lookup) +- C6-heavy は完全に pool v1 経路を使用(前回の FREE_PATH_STATS 分析と一致) + +### 次のボトルネック確定 + +**Mixed では**: +- **free dispatcher 全体(29.22%)** が最大 +- tiny_alloc_gate_fast(18.17%)が第二 +- C7 ULTRA refill(6.92%)は既に薄い部類 + +**C6-heavy では**: +- **hak_free_at(19.89%)** が最大の allocator 内部ボトルネック +- pool v1 alloc/free(各 10%)は構造的なコスト +- hak_super_lookup(4.39%)も削減余地あり + +### 次フェーズ候補 + +1. **Option A: free dispatcher 最適化** (Mixed 向け) + - free() 内部の routing logic を最適化 + - hak_free_at の分岐を削減 + - 期待効果: Mixed で free 29% → 25% 程度に削減(+1-2M ops/s) + +2. **Option B: alloc gate 最適化** (Mixed 向け) + - tiny_alloc_gate_fast(18.17%)の内部最適化 + - class 判定や routing の直線化 + - 期待効果: Mixed で alloc gate 18% → 15% 程度に削減(+1-2M ops/s) + +3. **Option C: C6-heavy mid/pool 再設計** (C6 向け) + - hak_free_at(19.89%)の C6 専用 fast path 追加 + - pool v1 の lookup overhead 削減 + - 期待効果: C6-heavy で 17M → 20-25M ops/s + +**推奨**: Option A または B(Mixed が本線のため)。C6-heavy は別途 mid 再設計フェーズで対応。 + +--- + +### 生成ファイル + +1. `/mnt/workdisk/public_share/hakmem/perf_ultra_mixed_v3.txt` - Mixed 16-1024B の complete perf report (1890 samples) +2. `/mnt/workdisk/public_share/hakmem/perf_ultra_c6_v3.txt` - C6-heavy の complete perf report (3027 samples) +3. `/mnt/workdisk/public_share/hakmem/CURRENT_TASK_PERF_REBASE3.md` - 本レポート diff --git a/Makefile b/Makefile index 62bf7598..bfd11a7d 100644 --- a/Makefile +++ b/Makefile @@ -218,12 +218,12 @@ LDFLAGS += $(EXTRA_LDFLAGS) # Targets TARGET = test_hakmem -OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o +OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o OBJS = $(OBJS_BASE) # Shared library SHARED_LIB = libhakmem.so -SHARED_OBJS = hakmem_shared.o hakmem_config_shared.o hakmem_tiny_config_shared.o hakmem_ucb1_shared.o hakmem_bigcache_shared.o hakmem_pool_shared.o hakmem_l25_pool_shared.o hakmem_site_rules_shared.o hakmem_tiny_shared.o core/box/ss_allocation_box_shared.o superslab_stats_shared.o superslab_cache_shared.o superslab_ace_shared.o superslab_slab_shared.o superslab_backend_shared.o core/superslab_head_stub_shared.o hakmem_smallmid_shared.o core/box/superslab_expansion_box_shared.o core/box/integrity_box_shared.o core/box/mailbox_box_shared.o core/box/front_gate_box_shared.o core/box/front_gate_classifier_shared.o core/box/free_publish_box_shared.o core/box/capacity_box_shared.o core/box/carve_push_box_shared.o core/box/prewarm_box_shared.o core/box/ss_hot_prewarm_box_shared.o core/box/front_metrics_box_shared.o core/box/bench_fast_box_shared.o core/box/ss_addr_map_box_shared.o core/box/slab_recycling_box_shared.o core/box/pagefault_telemetry_box_shared.o core/box/tiny_sizeclass_hist_box_shared.o core/box/tiny_env_box_shared.o core/box/tiny_route_box_shared.o core/box/free_front_v3_env_box_shared.o core/box/free_path_stats_box_shared.o core/box/tiny_page_box_shared.o core/box/tiny_class_policy_box_shared.o core/box/tiny_class_stats_box_shared.o core/box/tiny_policy_learner_box_shared.o core/box/ss_budget_box_shared.o core/box/tiny_mem_stats_box_shared.o core/box/wrapper_env_box_shared.o core/box/madvise_guard_box_shared.o core/box/libm_reloc_guard_box_shared.o core/page_arena_shared.o core/front/tiny_unified_cache_shared.o core/tiny_alloc_fast_push_shared.o core/tiny_c7_ultra_segment_shared.o core/tiny_c7_ultra_shared.o core/link_stubs_shared.o core/tiny_failfast_shared.o tiny_sticky_shared.o tiny_remote_shared.o tiny_publish_shared.o tiny_debug_ring_shared.o hakmem_tiny_magazine_shared.o hakmem_tiny_stats_shared.o hakmem_tiny_sfc_shared.o hakmem_tiny_query_shared.o hakmem_tiny_rss_shared.o hakmem_tiny_registry_shared.o hakmem_tiny_remote_target_shared.o hakmem_tiny_bg_spill_shared.o tiny_adaptive_sizing_shared.o hakmem_super_registry_shared.o hakmem_shared_pool_shared.o hakmem_shared_pool_acquire_shared.o hakmem_shared_pool_release_shared.o hakmem_elo_shared.o hakmem_batch_shared.o hakmem_p2_shared.o hakmem_sizeclass_dist_shared.o hakmem_evo_shared.o hakmem_debug_shared.o hakmem_sys_shared.o hakmem_whale_shared.o hakmem_policy_shared.o hakmem_ace_shared.o hakmem_ace_stats_shared.o hakmem_ace_controller_shared.o hakmem_ace_metrics_shared.o hakmem_ace_ucb1_shared.o hakmem_prof_shared.o hakmem_learner_shared.o hakmem_size_hist_shared.o hakmem_learn_log_shared.o hakmem_syscall_shared.o tiny_fastcache_shared.o core/box/super_reg_box_shared.o core/box/shared_pool_box_shared.o core/box/remote_side_box_shared.o core/tiny_destructors_shared.o +SHARED_OBJS = hakmem_shared.o hakmem_config_shared.o hakmem_tiny_config_shared.o hakmem_ucb1_shared.o hakmem_bigcache_shared.o hakmem_pool_shared.o hakmem_l25_pool_shared.o hakmem_site_rules_shared.o hakmem_tiny_shared.o core/box/ss_allocation_box_shared.o superslab_stats_shared.o superslab_cache_shared.o superslab_ace_shared.o superslab_slab_shared.o superslab_backend_shared.o core/superslab_head_stub_shared.o hakmem_smallmid_shared.o core/box/superslab_expansion_box_shared.o core/box/integrity_box_shared.o core/box/mailbox_box_shared.o core/box/front_gate_box_shared.o core/box/front_gate_classifier_shared.o core/box/free_publish_box_shared.o core/box/capacity_box_shared.o core/box/carve_push_box_shared.o core/box/prewarm_box_shared.o core/box/ss_hot_prewarm_box_shared.o core/box/front_metrics_box_shared.o core/box/bench_fast_box_shared.o core/box/ss_addr_map_box_shared.o core/box/slab_recycling_box_shared.o core/box/pagefault_telemetry_box_shared.o core/box/tiny_sizeclass_hist_box_shared.o core/box/tiny_env_box_shared.o core/box/tiny_route_box_shared.o core/box/free_front_v3_env_box_shared.o core/box/free_path_stats_box_shared.o core/box/free_dispatch_stats_box_shared.o core/box/tiny_page_box_shared.o core/box/tiny_class_policy_box_shared.o core/box/tiny_class_stats_box_shared.o core/box/tiny_policy_learner_box_shared.o core/box/ss_budget_box_shared.o core/box/tiny_mem_stats_box_shared.o core/box/wrapper_env_box_shared.o core/box/madvise_guard_box_shared.o core/box/libm_reloc_guard_box_shared.o core/page_arena_shared.o core/front/tiny_unified_cache_shared.o core/tiny_alloc_fast_push_shared.o core/tiny_c7_ultra_segment_shared.o core/tiny_c7_ultra_shared.o core/link_stubs_shared.o core/tiny_failfast_shared.o tiny_sticky_shared.o tiny_remote_shared.o tiny_publish_shared.o tiny_debug_ring_shared.o hakmem_tiny_magazine_shared.o hakmem_tiny_stats_shared.o hakmem_tiny_sfc_shared.o hakmem_tiny_query_shared.o hakmem_tiny_rss_shared.o hakmem_tiny_registry_shared.o hakmem_tiny_remote_target_shared.o hakmem_tiny_bg_spill_shared.o tiny_adaptive_sizing_shared.o hakmem_super_registry_shared.o hakmem_shared_pool_shared.o hakmem_shared_pool_acquire_shared.o hakmem_shared_pool_release_shared.o hakmem_elo_shared.o hakmem_batch_shared.o hakmem_p2_shared.o hakmem_sizeclass_dist_shared.o hakmem_evo_shared.o hakmem_debug_shared.o hakmem_sys_shared.o hakmem_whale_shared.o hakmem_policy_shared.o hakmem_ace_shared.o hakmem_ace_stats_shared.o hakmem_ace_controller_shared.o hakmem_ace_metrics_shared.o hakmem_ace_ucb1_shared.o hakmem_prof_shared.o hakmem_learner_shared.o hakmem_size_hist_shared.o hakmem_learn_log_shared.o hakmem_syscall_shared.o tiny_fastcache_shared.o core/box/super_reg_box_shared.o core/box/shared_pool_box_shared.o core/box/remote_side_box_shared.o core/tiny_destructors_shared.o # Pool TLS Phase 1 (enable with POOL_TLS_PHASE1=1) ifeq ($(POOL_TLS_PHASE1),1) @@ -250,7 +250,7 @@ endif # Benchmark targets BENCH_HAKMEM = bench_allocators_hakmem BENCH_SYSTEM = bench_allocators_system -BENCH_HAKMEM_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o bench_allocators_hakmem.o +BENCH_HAKMEM_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/free_publish_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o bench_allocators_hakmem.o BENCH_HAKMEM_OBJS = $(BENCH_HAKMEM_OBJS_BASE) ifeq ($(POOL_TLS_PHASE1),1) BENCH_HAKMEM_OBJS += pool_tls.o pool_refill.o pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o @@ -427,7 +427,7 @@ test-box-refactor: box-refactor ./larson_hakmem 10 8 128 1024 1 12345 4 # Phase 4: Tiny Pool benchmarks (properly linked with hakmem) -TINY_BENCH_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/free_publish_box.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o +TINY_BENCH_OBJS_BASE = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcache.o hakmem_pool.o hakmem_l25_pool.o hakmem_site_rules.o hakmem_tiny.o core/box/ss_allocation_box.o superslab_stats.o superslab_cache.o superslab_ace.o superslab_slab.o superslab_backend.o core/superslab_head_stub.o hakmem_smallmid.o core/box/superslab_expansion_box.o core/box/integrity_box.o core/box/mailbox_box.o core/box/front_gate_box.o core/box/front_gate_classifier.o core/box/free_publish_box.o core/box/capacity_box.o core/box/carve_push_box.o core/box/prewarm_box.o core/box/ss_hot_prewarm_box.o core/box/front_metrics_box.o core/box/bench_fast_box.o core/box/ss_addr_map_box.o core/box/slab_recycling_box.o core/box/pagefault_telemetry_box.o core/box/tiny_sizeclass_hist_box.o core/box/tiny_env_box.o core/box/tiny_route_box.o core/box/free_front_v3_env_box.o core/box/free_path_stats_box.o core/box/free_dispatch_stats_box.o core/box/tiny_c6_ultra_free_box.o core/box/tiny_c5_ultra_free_box.o core/box/tiny_c4_ultra_free_box.o core/box/tiny_page_box.o core/box/tiny_class_policy_box.o core/box/tiny_class_stats_box.o core/box/tiny_policy_learner_box.o core/box/ss_budget_box.o core/box/tiny_mem_stats_box.o core/box/c7_meta_used_counter_box.o core/box/wrapper_env_box.o core/box/madvise_guard_box.o core/box/libm_reloc_guard_box.o core/box/ptr_trace_box.o core/box/link_missing_stubs.o core/box/super_reg_box.o core/box/shared_pool_box.o core/box/remote_side_box.o core/page_arena.o core/front/tiny_unified_cache.o tiny_sticky.o tiny_remote.o tiny_publish.o tiny_debug_ring.o hakmem_tiny_magazine.o hakmem_tiny_stats.o hakmem_tiny_sfc.o hakmem_tiny_query.o hakmem_tiny_rss.o hakmem_tiny_registry.o hakmem_tiny_remote_target.o hakmem_tiny_bg_spill.o tiny_adaptive_sizing.o hakmem_super_registry.o hakmem_shared_pool.o hakmem_shared_pool_acquire.o hakmem_shared_pool_release.o hakmem_elo.o hakmem_batch.o hakmem_p2.o hakmem_sizeclass_dist.o hakmem_evo.o hakmem_debug.o hakmem_sys.o hakmem_whale.o hakmem_policy.o hakmem_ace.o hakmem_ace_stats.o hakmem_prof.o hakmem_learner.o hakmem_size_hist.o hakmem_learn_log.o hakmem_syscall.o hakmem_ace_metrics.o hakmem_ace_ucb1.o hakmem_ace_controller.o tiny_fastcache.o core/tiny_alloc_fast_push.o core/tiny_c7_ultra_segment.o core/tiny_c7_ultra.o core/link_stubs.o core/tiny_failfast.o core/tiny_destructors.o core/smallobject_hotbox_v3.o core/smallobject_hotbox_v4.o core/smallobject_hotbox_v5.o core/smallsegment_v5.o core/smallobject_cold_iface_v5.o core/smallsegment_v6.o core/smallobject_cold_iface_v6.o core/smallobject_core_v6.o TINY_BENCH_OBJS = $(TINY_BENCH_OBJS_BASE) ifeq ($(POOL_TLS_PHASE1),1) TINY_BENCH_OBJS += pool_tls.o pool_refill.o core/pool_tls_arena.o pool_tls_registry.o pool_tls_remote.o diff --git a/core/box/free_dispatch_stats_box.c b/core/box/free_dispatch_stats_box.c new file mode 100644 index 00000000..35ec665a --- /dev/null +++ b/core/box/free_dispatch_stats_box.c @@ -0,0 +1,25 @@ +#include "free_dispatch_stats_box.h" +#include + +FreeDispatchStats g_free_dispatch_stats = {0}; + +__attribute__((destructor)) +static void free_dispatch_stats_dump(void) { + if (!free_dispatch_stats_enabled()) { + return; + } + + fprintf(stderr, "[FREE_DISPATCH_STATS] total=%lu tiny=%lu mid=%lu large=%lu ultra=%lu tiny_legacy=%lu pool=%lu v6=%lu route_calls=%lu env_checks=%lu\n", + g_free_dispatch_stats.total_calls, + g_free_dispatch_stats.domain_tiny, + g_free_dispatch_stats.domain_mid, + g_free_dispatch_stats.domain_large, + g_free_dispatch_stats.route_ultra, + g_free_dispatch_stats.route_tiny_legacy, + g_free_dispatch_stats.route_pool_v1, + g_free_dispatch_stats.route_core_v6, + g_free_dispatch_stats.route_for_class_calls, + g_free_dispatch_stats.env_checks); + + fflush(stderr); +} diff --git a/core/box/free_dispatch_stats_box.h b/core/box/free_dispatch_stats_box.h new file mode 100644 index 00000000..e637444b --- /dev/null +++ b/core/box/free_dispatch_stats_box.h @@ -0,0 +1,46 @@ +#ifndef HAKMEM_FREE_DISPATCH_STATS_BOX_H +#define HAKMEM_FREE_DISPATCH_STATS_BOX_H + +#include +#include +#include + +typedef struct FreeDispatchStats { + uint64_t total_calls; + + // Domain classification + uint64_t domain_tiny; + uint64_t domain_mid; + uint64_t domain_large; + + // Route classification (tiny domain) + uint64_t route_ultra; // C4-C7 ULTRA 直行 + uint64_t route_tiny_legacy; // Tiny legacy path + uint64_t route_pool_v1; // pool v1 経由 + uint64_t route_core_v6; // core v6 (C6-only) + + // Performance counters + uint64_t env_checks; // ENV 読み回数(概算) + uint64_t route_for_class_calls; // tiny_route_for_class() 呼び出し回数 +} FreeDispatchStats; + +// ENV gate +static inline bool free_dispatch_stats_enabled(void) { + static int g_enabled = -1; + if (__builtin_expect(g_enabled == -1, 0)) { + const char* e = getenv("HAKMEM_FREE_DISPATCH_STATS"); + g_enabled = (e && *e && *e != '0') ? 1 : 0; + } + return g_enabled; +} + +// Global stats instance +extern FreeDispatchStats g_free_dispatch_stats; + +// Increment macros (with unlikely guard) +#define FREE_DISPATCH_STAT_INC(field) \ + do { if (__builtin_expect(free_dispatch_stats_enabled(), 0)) { \ + g_free_dispatch_stats.field++; \ + } } while(0) + +#endif // HAKMEM_FREE_DISPATCH_STATS_BOX_H diff --git a/core/box/hak_free_api.inc.h b/core/box/hak_free_api.inc.h index 2ec701b4..9528ba43 100644 --- a/core/box/hak_free_api.inc.h +++ b/core/box/hak_free_api.inc.h @@ -11,6 +11,7 @@ #include "external_guard_box.h" // Phase 15: Box ExternalGuard - mincore (ENV controlled) #include "fg_tiny_gate_box.h" // Tiny gate guard box (Superslab check) #include "tiny_free_gate_box.h" // Tiny Free Gatekeeper Box (USER→Fast Path 境界) +#include "free_dispatch_stats_box.h" // Phase FREE-DISPATCHER-OPT-1: free dispatcher stats #ifdef HAKMEM_POOL_TLS_PHASE1 #include "../pool_tls.h" @@ -80,6 +81,9 @@ __attribute__((always_inline)) inline #endif void hak_free_at(void* ptr, size_t size, hak_callsite_t site) { + // Phase FREE-DISPATCHER-OPT-1: Total call counter (at function entry) + FREE_DISPATCH_STAT_INC(total_calls); + #if HAKMEM_DEBUG_TIMING HKM_TIME_START(t0); #endif @@ -141,6 +145,22 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) { fg = fg_guard.fg; fg_misclass = fg_guard.misclassified; + // Phase FREE-DISPATCHER-OPT-1: Domain classification counters + if (__builtin_expect(free_dispatch_stats_enabled(), 0)) { + switch (fg.domain) { + case FG_DOMAIN_TINY: + g_free_dispatch_stats.domain_tiny++; + break; + case FG_DOMAIN_MIDCAND: + case FG_DOMAIN_POOL: + g_free_dispatch_stats.domain_mid++; + break; + case FG_DOMAIN_EXTERNAL: + g_free_dispatch_stats.domain_large++; + break; + } + } + switch (fg.domain) { case FG_DOMAIN_TINY: { // Phase FREE-FRONT-V3-2: v3 snapshot routing (optional, default OFF) diff --git a/core/box/tiny_route_env_box.h b/core/box/tiny_route_env_box.h index 412c4045..a12d4e9d 100644 --- a/core/box/tiny_route_env_box.h +++ b/core/box/tiny_route_env_box.h @@ -8,6 +8,7 @@ #include #include "../hakmem_tiny_config.h" #include "tiny_heap_env_box.h" +#include "free_dispatch_stats_box.h" // Phase FREE-DISPATCHER-OPT-1 #include "smallobject_hotbox_v3_env_box.h" #include "smallobject_hotbox_v4_env_box.h" @@ -72,27 +73,37 @@ static inline int small_heap_v6_class_enabled(uint32_t class_idx) { static inline void tiny_route_snapshot_init(void) { for (int i = 0; i < TINY_NUM_CLASSES; i++) { // Phase v6-1: C6-only v6 route stub (highest priority) + FREE_DISPATCH_STAT_INC(env_checks); // ENV check counter if (small_heap_v6_class_enabled((uint32_t)i)) { g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V6; + FREE_DISPATCH_STAT_INC(route_core_v6); } else if (i == 6 && small_heap_v5_class_enabled(6)) { // Phase v5-1: C6-only v5 route stub (before v4 check) + FREE_DISPATCH_STAT_INC(env_checks); g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V5; } else if (small_heap_v4_class_enabled((uint8_t)i)) { + FREE_DISPATCH_STAT_INC(env_checks); g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V4; } else if (small_heap_v3_class_enabled((uint8_t)i)) { + FREE_DISPATCH_STAT_INC(env_checks); g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V3; } else if (tiny_hotheap_v2_class_enabled((uint8_t)i)) { + FREE_DISPATCH_STAT_INC(env_checks); g_tiny_route_class[i] = TINY_ROUTE_HOTHEAP_V2; } else if (tiny_heap_box_enabled() && tiny_heap_class_route_enabled(i)) { + FREE_DISPATCH_STAT_INC(env_checks); + FREE_DISPATCH_STAT_INC(env_checks); g_tiny_route_class[i] = TINY_ROUTE_HEAP; } else { g_tiny_route_class[i] = TINY_ROUTE_LEGACY; + FREE_DISPATCH_STAT_INC(route_tiny_legacy); } } g_tiny_route_snapshot_done = 1; } static inline tiny_route_kind_t tiny_route_for_class(uint8_t ci) { + FREE_DISPATCH_STAT_INC(route_for_class_calls); // Phase FREE-DISPATCHER-OPT-1 if (__builtin_expect(!g_tiny_route_snapshot_done, 0)) { tiny_route_snapshot_init(); } diff --git a/docs/analysis/FREE_DISPATCHER_ANALYSIS.md b/docs/analysis/FREE_DISPATCHER_ANALYSIS.md new file mode 100644 index 00000000..5311621e --- /dev/null +++ b/docs/analysis/FREE_DISPATCHER_ANALYSIS.md @@ -0,0 +1,115 @@ +# FREE_DISPATCHER_ANALYSIS + +## 目的 + +free dispatcher(hak_free_at → fg_classify_domain → fg_tiny_gate → ...)のルーティング層を分析し、最適化ポイントを特定する。 + +## 現状フロー + +``` +free(ptr) + ↓ +hak_free_at(ptr, sz) + ↓ +fg_classify_domain(ptr, sz) + ├→ FG_DOMAIN_TINY → fg_tiny_gate → tiny_free_gate_try_fast + ├→ FG_DOMAIN_MID → mid free path + └→ FG_DOMAIN_LARGE → large free path +``` + +### tiny domain 内のルート分岐 + +``` +tiny_free_gate_try_fast(base, class_idx) + ↓ +tiny_route_for_class(class_idx) を呼び出し + ├→ ULTRA (C4-C7) → tiny_cX_ultra_free_fast() + ├→ Tiny legacy → existing tiny free + ├→ pool v1 → pool free + └→ core v6 (C6) → small_free_fast_v6() +``` + +### ENV 判定箇所(推定) + +- tiny_route_for_class() 内部 + - HAKMEM_SMALL_HEAP_V6_ENABLED + - HAKMEM_SMALL_HEAP_V3_ENABLED + - HAKMEM_POOL_V2_ENABLED / V1_ENABLED + - HAKMEM_TINY_CX_ULTRA_FREE_ENABLED (C4/C5/C6/C7) +- fg_classify_domain() 内部 + - サイズ閾値判定(tiny/mid/large 分岐) + +## Phase FREE-DISPATCHER-OPT-1: 統計計測 + +実装内容: +- FreeDispatchStats 構造体(ENV: HAKMEM_FREE_DISPATCH_STATS, default 0) +- カウンタ: + - total_calls: free 全体呼び出し回数 + - domain_tiny / domain_mid / domain_large: domain 分岐の内訳 + - route_ultra / route_tiny_legacy / route_pool_v1 / route_core_v6: tiny domain 内の route 内訳 + - env_checks: ENV 読み回数(概算) + - route_for_class_calls: tiny_route_for_class() 呼び出し回数 + +計測結果は次のセクションに記載。 + +## Phase FREE-DISPATCHER-OPT-1 計測結果 + +### Mixed 16-1024B (1M iter, ws=400) + +``` +[FREE_DISPATCH_STATS] total=8081 tiny=0 mid=8081 large=0 ultra=0 tiny_legacy=7 pool=0 v6=0 route_calls=267967 env_checks=9 +Throughput = 44.7M ops/s +``` + +**分析**: +- total_calls: 8,081 (hak_free_at 呼び出し回数、BENCH_FAST_FRONT で早期リターンしている分を除く) +- domain_mid: 100% (8,081/8,081) - BENCH_FAST_FRONT により tiny domain は早期リターン済み +- route_for_class_calls: 267,967 (alloc 側でも呼ばれるため total より大きい) +- env_checks: 9 (tiny_route_snapshot_init() で 1回だけ ENV を読む設計が機能) + +**重要な発見**: +1. BENCH_FAST_FRONT により大半の free は早期リターンしており、fg_classify_domain に到達するのは少数のみ +2. route_for_class は主に alloc 側で呼ばれている(267k calls vs 8k frees) +3. ENV check は初期化時の 9回のみで、ホットパスでは完全に排除されている + +### C6-heavy (257-768B, 1M iter, ws=400) + +``` +[FREE_DISPATCH_STATS] total=500099 tiny=0 mid=500099 large=0 ultra=0 tiny_legacy=7 pool=0 v6=0 route_calls=1034 env_checks=9 +``` + +**分析**: +- total_calls: 500,099 (1M operations の約半分が free) +- domain_mid: 100% (C6 は mid domain) +- route_for_class_calls: 1,034 (Mixed より大幅に少ない、C6-heavy では alloc が単純) +- env_checks: 9 (同様に初期化時のみ) + +**コメント**: +- C6-heavy では BENCH_FAST_FRONT の効果が少なく、大半の free が fg_classify_domain に到達 +- route_for_class の呼び出しが非常に少ない(1k calls)のは、C6 が既に snapshot 済みで LUT lookup のみで完結しているため + +## Phase FREE-DISPATCHER-OPT-2 候補施策 + +### 候補 A: tiny domain 早期 return + +**条件**: tiny domain が 90% 以上 +**施策**: fg_classify_domain から tiny 判定を早期 return にし、mid/large 分岐を cold に追いやる +**期待**: domain 判定コスト削減、分岐予測向上 + +### 候補 B: route snapshot 化 + +**条件**: route_for_class_calls ≈ total_calls(毎回呼ばれている) +**施策**: route_kind[class_idx] を snapshot にして、free では table lookup のみ +**期待**: ENV check 削減、route 判定の O(1) 化 + +### 候補 C: mid/pool free gate 最適化 + +**条件**: mid domain がそこそこある(10% 以上) +**施策**: mid/pool の free gate 分岐も route snapshot 化 +**期待**: C6-heavy での改善 + +### 判断基準 + +- tiny > 90% → 候補 A + B +- route_calls ≈ total → 候補 B 優先 +- mid > 10% → 候補 C も検討 diff --git a/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md b/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md index 045d3dc5..f7ddc498 100644 --- a/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md +++ b/docs/analysis/TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md @@ -237,3 +237,75 @@ Throughput: **12.39M ops/s**(DEBUG/-O0 相当) - 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.023s(23ms)と極めて短く、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/front(23.57%)と header(8.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 の効果測定には不十分なサンプル数 diff --git a/docs/status/CURRENT_TASK.md b/docs/status/CURRENT_TASK.md index 8f65ecdd..fee95e23 100644 --- a/docs/status/CURRENT_TASK.md +++ b/docs/status/CURRENT_TASK.md @@ -220,3 +220,123 @@ Step 2.5 が TLS_SLL_PUSH_DUP を「修正」するために追加されたが - master-80M-unstable から Step 2.5 をリバート - 複雑な conflict (33行変更) で35+ 回失敗済み - 推奨しない + +--- + +## Phase PERF-ULTRA-REBASE-2: C4-C7 ULTRA free最適化後のperf再計測 (2025-12-11) + +**計測対象**: Mixed 16-1024B, C6-heavy + +### 計測条件 +- **Mixed 16-1024B**: + - ENV: `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE` + - ULTRA: C4-C7 全て ON + - ワークロード: iters=1M, ws=400 + - perf: -F 5000 --call-graph dwarf -e cycles:u + +- **C6-heavy**: + - ENV: `HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1` + - pool v1 + C6/C5/C4 ULTRA + - ワークロード: 1 thread, iters=1M, ws=400 + +### スループット +- **Mixed**: 42.63M ops/s(前回 31.61M から大幅改善、但し ws=400 vs 8192の差) +- **C6-heavy**: 26.49M ops/s + +### 新しい最大ホットスポット(Mixed) +**WARNING: サンプル数が極めて少ない(238 samples)** + +| 順位 | 関数 | 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 | header 書き込み合計 | 8.07% | tiny_region_id_write_header | + +**ULTRA 関連関数が全て不可視**: tiny_c7_ultra_alloc や ULTRA free 群が上位20に入っていない + +### 前フェーズ(PERF-ULTRA-FREE-OPT-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=1M, ws=400) + - perf サンプル数が238と極めて少なく、統計的信頼性が低い + - ベンチマーク時間が0.023s(23ms)と極めて短く、allocator 本体が可視化されていない + +- **次の最大ボトルネックを確定できず**: + - gate/front(23.57%)と header(8.07%)が可視範囲での上位 + - ULTRA alloc/free の実態が見えていない + +- **推奨される次の手順**: + - iters を 10M に増やす、または ws を 8192 に拡大して再計測 + - サンプル数を1000+に増やして統計的信頼性を確保 + +### C6-heavy 分析 +- **pool v1 が支配的**: alloc 14.46% + free 19.89% = 34.35% +- **ULTRA は可視化されず**: C6/C5/C4 ULTRA 関数が上位に入っていない +- **pthread_once が8.21%**: 初期化同期のオーバーヘッドが目立つ(ワークロードが軽い証拠) + +### 出力物 +1. **perf_ultra_mixed_v2.txt** - Mixed の perf report 完全出力(238 samples) +2. **perf_ultra_c6_v2.txt** - C6-heavy の perf report 完全出力(292 samples) +3. **更新済み TINY_CPU_HOTPATH_USERLAND_ANALYSIS.md** - 解析結果とWARNINGを記載 +4. **更新済み CURRENT_TASK.md** - 本セクション + +--- + +## Phase PERF-ULTRA-REBASE-2 後の次フェーズ候補(要判断) + +### 判断保留理由 +- **サンプル不足**: 現状の perf 結果では allocator 本体のボトルネックが可視化されていない +- **再計測が必須**: より重いワークロード(iters=10M, ws=8192)で再測定してから判断すべき + +### パターン分析(参考:前回 PERF-ULTRA-REBASE-1 の結果に基づく) + +#### パターン A: tiny_c7_ultra_alloc が依然トップの場合 +- **前回の値**: 7.66% self(最大ホットスポット) +- 理由: ULTRA alloc の内部構造(refill/page_meta)に起因 +- 次フェーズ案: **Phase PERF-ULTRA-REFILL-OPT-1** + - C7 ULTRA の refill path(cold 側)を最適化 + - segment 取得ロジックの軽量化 + - page_meta 管理の簡略化 +- 判断: C7 refill を弄る技術的難度と効果のバランスを検討 + +#### パターン B: so_alloc_fast / page_of が浮いてきた場合 +- **前回の値**: so_alloc系 3.60%, page_of系 2.74% +- 理由: ULTRA が C4-C7 を完全カバーし、v3 backend 側が relative に大きくなった +- 次フェーズ案: **Phase PERF-ULTRA-V3-OPT-1** + - so_alloc_v3 の hotpath 簡略化 + - page_of(ptr→page 解決)の高速化 + - header write の最適化(既に thin は確認済み) +- 判断: v3 backend 自体を軽くするか、別 backend(v4/v6)を考えるか + +#### パターン C: 残り legacy (C2/C3) が顕著な場合 +- 確認: legacy 総数が何%か、C2/C3 の比率を確認 +- 判断基準: + - C2/C3 合計が全体の 5% 以上 → C3 ULTRA を検討する価値あり + - C2/C3 合計が 2% 未満 → 後回し(L1 汚染のリスクが高い) + +#### パターン D: tiny_alloc_gate_fast / header が上位の場合(今回観測) +- **今回の値**: gate 23.57%, header 8.07% +- 理由: ワークロードが軽すぎて allocator 本体が見えていない可能性が高い +- 次フェーズ案: **Phase PERF-ULTRA-REBASE-3(再計測)** + - より重いワークロード(iters=10M, ws=8192)で再測定 + - サンプル数1000+を確保して統計的信頼性を高める + - その上でパターンA/B/Cのどれかに該当するか判断 + +### 推奨される判断フロー +1. **Phase PERF-ULTRA-REBASE-3(再計測)を実施** + - iters=10M, ws=8192 で Mixed を再計測 + - perf record 時間を長くしてサンプル数を確保 + +2. **再計測後の perf_ultra_mixed_v3.txt の #1/#2 を見る** + - パターン A/B/C/D のどれに該当するか判定 + +3. **該当フェーズ案を実装 or 研究箱化の判断** + - A: ULTRA refill 最適化(高難度、効果大) + - B: v3 backend 最適化(中難度、効果中) + - C: C2/C3 ULTRA 追加(低難度、効果不明) + - D: 再計測(必須) diff --git a/hakmem.d b/hakmem.d index 1269e6be..6d65859e 100644 --- a/hakmem.d +++ b/hakmem.d @@ -80,8 +80,8 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/box/../superslab/superslab_inline.h \ core/box/../box/ss_slab_meta_box.h core/box/../box/free_remote_box.h \ core/hakmem_tiny_integrity.h core/box/../box/ptr_conversion_box.h \ - core/box/hak_wrappers.inc.h core/box/front_gate_classifier.h \ - core/box/../front/malloc_tiny_fast.h \ + core/box/free_dispatch_stats_box.h core/box/hak_wrappers.inc.h \ + core/box/front_gate_classifier.h core/box/../front/malloc_tiny_fast.h \ core/box/../front/../hakmem_build_flags.h \ core/box/../front/../hakmem_tiny_config.h \ core/box/../front/../superslab/superslab_inline.h \ @@ -120,6 +120,7 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/box/../front/../box/tiny_front_hot_box.h \ core/box/../front/../box/tiny_ptr_convert_box.h \ core/box/../front/../box/tiny_route_env_box.h \ + core/box/../front/../box/free_dispatch_stats_box.h \ core/box/../front/../box/smallobject_hotbox_v4_env_box.h \ core/box/../front/../box/smallobject_v5_env_box.h \ core/box/../front/../box/tiny_front_stats_box.h \ @@ -279,6 +280,7 @@ core/box/../box/ss_slab_meta_box.h: core/box/../box/free_remote_box.h: core/hakmem_tiny_integrity.h: core/box/../box/ptr_conversion_box.h: +core/box/free_dispatch_stats_box.h: core/box/hak_wrappers.inc.h: core/box/front_gate_classifier.h: core/box/../front/malloc_tiny_fast.h: @@ -321,6 +323,7 @@ core/box/../front/../box/free_path_stats_box.h: core/box/../front/../box/tiny_front_hot_box.h: core/box/../front/../box/tiny_ptr_convert_box.h: core/box/../front/../box/tiny_route_env_box.h: +core/box/../front/../box/free_dispatch_stats_box.h: core/box/../front/../box/smallobject_hotbox_v4_env_box.h: core/box/../front/../box/smallobject_v5_env_box.h: core/box/../front/../box/tiny_front_stats_box.h: diff --git a/perf.data.ultra_c6_v2 b/perf.data.ultra_c6_v2 new file mode 100644 index 00000000..95edfc87 Binary files /dev/null and b/perf.data.ultra_c6_v2 differ diff --git a/perf.data.ultra_c6_v3 b/perf.data.ultra_c6_v3 new file mode 100644 index 00000000..29239b7c Binary files /dev/null and b/perf.data.ultra_c6_v3 differ diff --git a/perf.data.ultra_mixed_v2 b/perf.data.ultra_mixed_v2 new file mode 100644 index 00000000..9b88ad7a Binary files /dev/null and b/perf.data.ultra_mixed_v2 differ diff --git a/perf.data.ultra_mixed_v3 b/perf.data.ultra_mixed_v3 new file mode 100644 index 00000000..588e3b16 Binary files /dev/null and b/perf.data.ultra_mixed_v3 differ