6.1 KiB
6.1 KiB
TINY FRONT v3 FLATTENING GUIDE
Mixed 16–1024B で C7 v3 を ON にしたときの前段ホットパスを薄くするための設計メモ。実装は別フェーズ担当 AI 向けの TODO リストです。
現状の malloc_tiny_fast 前段フロー(ざっくり)
- size → 「Tiny かどうか」判定。
- Tiny なら size → class_idx (C0〜C7) 変換。
- route LUT (
tiny_route_for_class(class_idx)) で route 決定。 - route switch で Tiny v1 / v2 / v3 / legacy を呼び分け。
- C7 v3 は早期パスで direct に
so_alloc/so_freeへ行くが、他クラスの前段 if/switch がまだ残っている。
perf で見えたボトルネック(Mixed 16–1024B, v3 ON, DEBUGビルド)
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(size→class 判定) ~1.4%mid_desc_lookup~1.3%- so_alloc/so_free 自体は合計 ~7%(C7 v3 本体)。ここでは C7 以外の前段を削るのが目的。
フラット化方針(次フェーズで実装する項目)
-
size→class→route を 1 LUT + 1 switch に寄せる
- C7 v3 の早期 if を最小限にし、C5/C6 などの分岐を共通 switch にまとめる。
- route の再判定・重複チェックを減らす。デバッグ/稀パスは
unlikely側へ。
-
header/guard 系の前段整理
tiny_region_id_write_headerの呼び出し回数・書き込みバイト数を確認し、必要最小限にする。- guard 判定 (
tiny_guard_is_enabledなど) を Snapshot 側に寄せ、front では値を読むだけにする。
-
Superslab 判定の軽量化
- C7 v3 で self-thread が確定している場合の
ss_map_lookupを避けられるか検討。 - lookup が必要なケースを TinyLookupBox に閉じ込め、ホットパスは lookup なしで通す。
- C7 v3 で self-thread が確定している場合の
A/B 用プロファイル(固定)
HAKMEM_BENCH_MIN_SIZE=16HAKMEM_BENCH_MAX_SIZE=1024HAKMEM_TINY_HEAP_PROFILE=C7_SAFEHAKMEM_TINY_C7_HOT=1HAKMEM_TINY_HOTHEAP_V2=0HAKMEM_POOL_V2_ENABLED=0HAKMEM_SMALL_HEAP_V3_ENABLED=1HAKMEM_SMALL_HEAP_V3_CLASSES=0x80- ベンチ:
./bench_random_mixed_hakmem 1000000 400 1
成功ライン: 上記環境で v3 ON のまま +5〜10% か、少なくとも回帰なし& HEAP_STATS に異常なし。
Phase1 (done): フラグ判定のスナップショット化
- ENV ゲート:
HAKMEM_TINY_FRONT_V3_ENABLED… デフォルト OFF(有効時のみ v3 フロント経路)HAKMEM_TINY_FRONT_V3_STATS… 任意のデバッグカウンタ用
- Snapshot(
TinyFrontV3Snapshot)に- unified_cache_on
- tiny_guard_on
- header_mode
を 1 回だけキャッシュし、front v3 ON のときは
unified_cache_enabled/tiny_guard_is_enabled/tiny_header_modeの呼び出しをホットパスから排除。
- malloc/free とも snapshot を読むブロックに入り、UC/guard 判定をキャッシュ経由に統一。
- A/B(Mixed 16–1024B, ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF)で挙動変化なし(slow=1 維持)。次は size→class 前段のフラット化に進める。
Phase2-A: size→class LUT 化(実装済み、A/B 待ち)
- ENV:
HAKMEM_TINY_FRONT_V3_LUT_ENABLED(デフォルト OFF、v3 ON 時のみ有効化可能)。 - Tiny 前段専用の LUT (
TinyFrontV3SizeClassEntry) を 1 回だけ構築し、front v3 が有効かつ LUT ON のときはmalloc_tiny_fastが size→class→route を 1 ルックアップで取得(挙動は既存hak_tiny_size_to_class/ route スナップショットに一致)。 - フォールバック: LUT が無効/範囲外/未初期化のときは従来の size→class ロジックに自動で戻る。
- Mixed 16–1024B A/B(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%)
- C7_PAGE_STATS: prepare_calls=2446(短尺時と同値)、HEAP_STATS は TinyHeap v1 経路外のため出力なし。
- 挙動回帰なしで微プラス。次は size→class→route 前段のさらなるフラット化を検討。
Phase2-B: route fast path(LUT→1 switch)
- ENV:
HAKMEM_TINY_FRONT_V3_ROUTE_FAST_ENABLED(デフォルト OFF、front v3 + LUT ON 時だけ opt-in)。 - 仕様:
- size→class→route を LUT 2 バイト load で取得し、即 1 switch で v3/v2/v1/legacy に分岐。
- route helper(tiny_route_for_class)呼び出しをホットパスから外し、挙動は LUT 構築時のスナップショットに従う。
- ROUTE_FAST=0 のときは Phase2-A と同じ挙動に自動フォールバック。
- A/B(Mixed 16–1024B, ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF, front v3 ON, LUT ON)
- route_fast=0: 45.066M ops/s
- route_fast=1: 44.821M ops/s(約 -0.5%)
- C7_PAGE_STATS: prepare_calls=2446、回帰なし。HEAP_STATS は TinyHeap v1 経路外のため未出力。
- メモ: 微小マイナスだったためデフォルトは ROUTE_FAST=0 のまま。size→class 前段や header/guard 整理の方が効果が出そう。
Phase2-C: Header v3 (C7-only skip) 実験
- ENV:
HAKMEM_TINY_HEADER_V3_ENABLED(デフォルト 0)HAKMEM_TINY_HEADER_V3_SKIP_C7(デフォルト 0、C7 v3 alloc 時に tiny_region_id_write_header をスキップして簡易 1byte だけ書く)
- 実装ポイント:
- TinyFrontV3Snapshot に header_v3_{enabled,skip_c7} を追加。
- so_alloc_fast(C7) で header_v3_skip_c7 が有効なときは header を簡易 1store のみで書き、ガード/重い処理を省略。
- front/free 側の挙動は不変(ヘッダは class 判定用に 1byte だけ残す)。
- A/B(Mixed 16–1024B, ws=400, iters=1M, front v3/LUT ON, route_fast=0, C7 v3 ON)
- 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, v3 fallback/page_of_fail=0
- 所感: 短尺の header スキップだけでは改善なし。free 側の header 依存を外す or header_light 再設計を別フェーズで検討。