2025-12-13 04:28:52 +09:00
|
|
|
|
# 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 を試した **直後**。
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
// 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` / `malloc` self% が下がる
|
|
|
|
|
|
- `main` が相対的に上がる(= allocator 側の余地を削った証拠)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 成功条件
|
|
|
|
|
|
|
|
|
|
|
|
- Mixed: +2% 以上(または free DUALHOT と同等の “明確な改善”)
|
|
|
|
|
|
- C6-heavy: ±2% 以内(回帰なし)
|
|
|
|
|
|
- 回帰が出たら default OFF の研究箱として freeze(保持して次の学びに使う)
|
|
|
|
|
|
|
2025-12-13 05:10:45 +09:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 実測結果(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 まわりの構造的オーバーヘッドを狙う(別フェーズに切る)
|