**ALLOC-TINY-FAST-DUALHOT-1** (this phase): - Implementation: malloc_tiny_fast() C0-C3 early-exit with policy snapshot skip - ENV: HAKMEM_TINY_ALLOC_DUALHOT=0/1 (default OFF) - A/B Result: -1.17% median regression (Mixed, 10-run) - Root Cause: Branch prediction penalty on C4-C7 outweighs policy skip benefit - Decision: Freeze as research box (default OFF) - Difference from FREE: ALLOC requires structural changes (per-class paths) **FREE-TINY-FAST-DUALHOT-1** (verified): - A/B Confirmation: +13.00% improvement (42.08M → 47.81M ops/s, Mixed, 10-run) - Success Criteria: +2% target ACHIEVED - Health Check: PASS (verify_health_profiles.sh, ENV OFF/ON) - Safety: HAKMEM_TINY_LARSON_FIX guard in place - Decision: Promotion to MIXED_TINYV3_C7_SAFE profile candidate **Next Steps**: - Profile adoption of FREE DUALHOT for MIXED workload - No further deep-dive on ALLOC optimization (deferred to future phases) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
4.4 KiB
4.4 KiB
Phase ALLOC-TINY-FAST-DUALHOT-1 設計(C0–C3 を第2ホットとして扱う)
背景(現状のボトルネック)
FREE-TINY-FAST-DUALHOT-1 により free の self% が大きく低下したため、Mixed の次のボトルネックが alloc 側に移った。
(例: tiny_alloc_gate_fast + malloc が合計 ~30% 付近)
ここで重要なのは、FREE 側の学びと同じ:
- C7 は ULTRA で “第1ホット”
- C0–C3 は LEGACY(UC/SFC/SLL 等)で “第2ホット”
- “第2ホット” を rare 扱いして
policy snapshotを毎回踏むと損
目的
malloc_tiny_fast() の alloc 経路で、C0–C3 については
small_policy_v7_snapshot()(policy snapshot)route_kind判定(switch)
を スキップし、LEGACY の最短経路(TLS unified cache hit → refill)へ直行させる。
非目標(やらないこと)
- C4–C7 のルーティング設計変更(ULTRA/MID/v7 の構造は触らない)
- “PGO build 前提の大改造” はやらない(まずは小パッチで A/B)
- 統計の常時 ON(global atomic)を入れない(外乱要因になる)
設計(Box Theory)
箱と境界
- 対象ホット関数:
core/front/malloc_tiny_fast.hのmalloc_tiny_fast(size) - 境界:
class_idx確定直後(size→class の 1 回目)に “第2ホット” を判定して early-exit - 既存の Box は変更しない(
tiny_hot_alloc_fast()とtiny_cold_refill_and_alloc()を再利用)
戻せる(A/B)
- ENV gate を 1 つ追加する:
HAKMEM_TINY_ALLOC_DUALHOT=0/1- 初期は default OFF(A/B しやすくする)
Fail-Fast / Safety
- alloc は cross-thread free と違い “所有者” 概念がないため、Larson ガード不要。
- ただし、将来 C0–C3 を v6/v7 等へ載せる実験に備え、ENV でいつでも OFF に戻せるようにする。
具体案(擬似コード)
差し込み位置は class_idx を確定し、C7 ULTRA early-exit を試した 直後。
// C7 ULTRA early-exit (既存)
if (class_idx == 7 && tiny_c7_ultra_enabled_env()) { ... }
// NEW: C0–C3 DUALHOT
if (alloc_dualhot_enabled() && class_idx <= 3) {
void* p = tiny_hot_alloc_fast(class_idx);
if (p) return p;
return tiny_cold_refill_and_alloc(class_idx);
}
// 既存: policy snapshot + route_kind switch
const SmallPolicyV7* policy = small_policy_v7_snapshot();
switch (policy->route_kind[class_idx]) { ... }
計測手順(GO/NO-GO)
Gate 1: 健康診断
scripts/verify_health_profiles.sh を default 設定(ENV OFF)で 1 回。
Gate 2: A/B(Mixed)
- Baseline:
HAKMEM_TINY_ALLOC_DUALHOT=0 - Opt:
HAKMEM_TINY_ALLOC_DUALHOT=1
同一条件で 10-run。中央値と分散を比較。
Gate 3: perf(Mixed)
期待:
tiny_alloc_gate_fast/mallocself% が下がるmainが相対的に上がる(= allocator 側の余地を削った証拠)
成功条件
- Mixed: +2% 以上(または free DUALHOT と同等の “明確な改善”)
- C6-heavy: ±2% 以内(回帰なし)
- 回帰が出たら default OFF の研究箱として freeze(保持して次の学びに使う)
実測結果(2025-12-13)
計測条件:
- Mixed:
HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE ./bench_random_mixed_hakmem 100000000 400 1(10-run) - C6-heavy:
HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1 ./bench_mid_large_mt_hakmem 1 10000000 400 1(10-run)
結果:
Mixed(MIXED_TINYV3_C7_SAFE)
- Baseline(
HAKMEM_TINY_ALLOC_DUALHOT=0): mean=50.60M, median=50.87M ops/s - Opt(
HAKMEM_TINY_ALLOC_DUALHOT=1): mean=50.27M, median=50.28M ops/s - 差分(median): -1.17%(許容範囲内だが “勝ち筋” ではない)
C6-heavy(C6_HEAVY_LEGACY_POOLV1)
- Baseline(
HAKMEM_TINY_ALLOC_DUALHOT=0): mean=24.73M, median=24.69M ops/s - Opt(
HAKMEM_TINY_ALLOC_DUALHOT=1): mean=24.62M, median=24.78M ops/s - 差分(median): +0.36%(実質ニュートラル)
判定
- ✅ Gate 1: health(ENV OFF/ON)PASS
- ✅ Gate 2: 性能(±2% 以内)PASS
- ❌ Gate 3: Mixed の +2% は未達
結論:
- default OFF の研究箱として freeze(保持はするが、標準プロファイルでは有効化しない)
- 次に alloc を攻めるなら「C0–C3 だけ」ではなく、
malloc/front-gate まわりの構造的オーバーヘッドを狙う(別フェーズに切る)