**Changes:** - core/box/pool_api.inc.h: Code organization and micro-optimizations - CURRENT_TASK.md: Updated Phase MD1 (mid_desc TLS cache: +3.2% for C6-heavy) - docs/analysis files: Various analysis and documentation updates - AGENTS.md: Agent role clarifications - TINY_FRONT_V3_FLATTENING_GUIDE.md: Flattening strategy documentation **Verification:** - random_mixed_hakmem: 44.8M ops/s (1M iterations, 400 working set) - No segfaults or assertions across all benchmark variants - Stable performance across multiple runs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
109 KiB
109 KiB
HAKMEM 状況メモ (2025-12-05 更新 / C7 Warm/TLS Bind 反映)
Phase FP1: Mixed 16–1024B madvise A/B(C7-only v3, front v3+LUT+fast classify ON, ws=400, iters=1M, Release)
- Baseline (MIXED_TINYV3_C7_SAFE, SS_OS_STATS=1): 32.76M ops/s。
[SS_OS_STATS] madvise=4 madvise_enomem=1 madvise_disabled=1(warmup で ENOMEM→madvise 停止)。perf: task-clock 50.88ms / minor-faults 6,742 / user 35.3ms / sys 16.2ms。 - Low-madvise(+
HAKMEM_FREE_POLICY=keep HAKMEM_DISABLE_BATCH=1 HAKMEM_SS_MADVISE_STRICT=0, SS_OS_STATS=1): 32.69M ops/s。madvise=3 enomem=0 disabled=0。perf: task-clock 54.96ms / minor-faults 6,724 / user 35.1ms / sys 20.8ms。 - Batch+THP 寄り(+
HAKMEM_FREE_POLICY=batch HAKMEM_DISABLE_BATCH=0 HAKMEM_THP=auto, SS_OS_STATS=1): 33.24M ops/s。madvise=3 enomem=0 disabled=0。perf: task-clock 49.57ms / minor-faults 6,731 / user 35.4ms / sys 15.1ms。 - 所感: pf/OPS とも大差なし。低 madvise での改善は見られず、Batch+THP 側がわずかに良好(+1〜2%)。vm.max_map_count が厳しい環境で failfast を避けたい場合のみ keep/STRICT=0 に切替える運用が現実的。
Hotfix: madvise(ENOMEM) を握りつぶし、以降の madvise を停止(Superslab OS Box)
- 変更:
ss_os_madvise_guarded()を追加し、madvise が ENOMEM を返したらg_ss_madvise_disabled=1にして以降の madvise をスキップ。EINVAL だけは従来どおり STRICT=1 で Fail-Fast(ENVHAKMEM_SS_MADVISE_STRICTで緩和可)。 - stats:
[SS_OS_STATS]にmadvise_enomem/madvise_other/madvise_disabledを追加。HAKMEM_SS_OS_STATS=1 で確認可能。 - ねらい: vm.max_map_count 到達時の大量 ENOMEM で VMA がさらに分割されるのを防ぎ、アロケータ自体は走り続ける。
PhaseS1: SmallObject v3 C6 トライ前のベースライン(C7-only)
- 条件: Release,
./bench_random_mixed_hakmem 1000000 400 1、ENVHAKMEM_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_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80 HAKMEM_POOL_V2_ENABLED=0(C7 v3 のみ)。 - 結果: Throughput ≈ 46.31M ops/s(segv/assert なし、SS/Rel ログのみ)。Phase S1 で C6 v3 を追加する際の比較用ベースとする。
- C6-only v3(research / bench 専用):
HAKMEM_BENCH_MIN_SIZE=257 MAX_SIZE=768 TINY_HEAP_PROFILE=C7_SAFE TINY_C7_HOT=1 TINY_C6_HOT=1 TINY_HOTHEAP_V2=0 SMALL_HEAP_V3_ENABLED=1 SMALL_HEAP_V3_CLASSES=0x40 POOL_V2_ENABLED=0→ Throughput ≈ 36.77M ops/s(segv/assert なし)。C6 statsroute_hits=266,930 alloc_refill=5 fb_v1=0 page_of_fail=0(C7 は v1 ルート)。 - Mixed 16–1024B C6+C7 v3:
HAKMEM_SMALL_HEAP_V3_CLASSES=0xC0 SMALL_HEAP_V3_STATS=1 TINY_C6_HOT=1で./bench_random_mixed_hakmem 1000000 400 1→ Throughput ≈ 44.45M ops/s、cls6 route_hits=137,307 alloc_refill=1 fb_v1=0 page_of_fail=0/cls7 route_hits=283,170 alloc_refill=2,446 fb_v1=0 page_of_fail=0。C7 slow/refill は従来レンジ。 - 追加 A/B(C6-heavy v1 vs v3): 同条件
MIN=257 MAX=768 ws=400 iters=1MでCLASSES=0x80(C6 v1)→ 47.71M ops/s(v3 stats は cls7 のみ)、CLASSES=0x40(C6 v3)→ 36.77M ops/s。約 -23% で v3 が劣後。 - Mixed 16–1024B 追加 A/B:
CLASSES=0x80(C7-only)→ 47.45M ops/s、CLASSES=0xC0(C6+C7 v3)→ 44.45M ops/s(約 -6%)。cls6 stats は route_hits=137,307 alloc_refill=1 fb_v1=0 page_of_fail=0。 - 方針: デフォルトは C7-only(mask 0x80)のまま。C6 v3 は
HAKMEM_SMALL_HEAP_V3_CLASSESbit6 で明示 opt-in(研究箱)。ベンチ時はHAKMEM_TINY_C6_HOT=1を併用して tiny front を確実に通す。C6 v3 は現状 C6-heavy/Mixed とも性能マイナスのため、研究箱据え置き。 - 確定: 標準プロファイルは
HAKMEM_SMALL_HEAP_V3_CLASSES=0x80(C7-only v3 固定)。bit6(C6)は研究専用で本線に乗せない。 - C6-heavy / C6 を v1 固定で走らせる推奨プリセット:
HAKMEM_BENCH_MIN_SIZE=257 HAKMEM_BENCH_MAX_SIZE=768 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C6_HOT=1 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80 # C7-only v3
Mixed 16–1024B 新基準(C7-only v3 / front v3 ON, 2025-12-05)
- ENV:
HAKMEM_BENCH_MIN_SIZE=16 MAX_SIZE=1024 TINY_HEAP_PROFILE=C7_SAFE TINY_C7_HOT=1 TINY_HOTHEAP_V2=0 SMALL_HEAP_V3_ENABLED=1 SMALL_HEAP_V3_CLASSES=0x80 POOL_V2_ENABLED=0(front v3/LUT はデフォルト ON、v3 stats ON)。 - HAKMEM: 44.45M ops/s、
cls7 alloc_refill=2446 fb_v1=0 page_of_fail=0(segv/assert なし)。 - mimalloc: 117.20M ops/s。system: 90.95M ops/s。→ HAKMEM は mimalloc の約 38%、system の約 49%。
C6-heavy 最新ベースライン(C6 v1 固定 / flatten OFF, 2025-12-05)
- ENV:
HAKMEM_BENCH_MIN_SIZE=257 MAX_SIZE=768 TINY_HEAP_PROFILE=C7_SAFE TINY_C6_HOT=1 SMALL_HEAP_V3_ENABLED=1 SMALL_HEAP_V3_CLASSES=0x80 POOL_V2_ENABLED=0 POOL_V1_FLATTEN_ENABLED=0。 - HAKMEM: 29.01M ops/s(segv/assert なし)。Phase80/82 以降の比較用新基準。
Phase80: mid/smallmid Pool v1 flatten(C6-heavy)
- 目的: mid/smallmid の pool v1 ホットパスを薄くし、C6-heavy ベンチで +5〜10% 程度の底上げを狙う。
- 実装:
core/hakmem_pool.cに v1 専用のフラット化経路(hak_pool_try_alloc_v1_flat/hak_pool_free_v1_flat)を追加し、TLS ring/lo hit 時は即 return・その他は従来の_v1_implへフォールバックする Box に分離。ENVHAKMEM_POOL_V1_FLATTEN_ENABLED(デフォルト0)とHAKMEM_POOL_V1_FLATTEN_STATSでオンオフと統計を制御。 - A/B(C6-heavy, ws=400, iters=1M,
HAKMEM_BENCH_MIN_SIZE=257/MAX_SIZE=768,POOL_V2_ENABLED=0, Tiny/Small v2/v3 は従来どおり):- flatten OFF (
POOL_V1_FLATTEN_ENABLED=0): Throughput ≈ 23.12M ops/s、[POOL_V1_FLAT] alloc_tls_hit=0 alloc_fb=0 free_tls_hit=0 free_fb=0。
- flatten OFF (
- flatten ON (
POOL_V1_FLATTEN_ENABLED=1): Throughput ≈ 25.50M ops/s(約 +10%)、alloc_tls_hit=499,870 alloc_fb=230 free_tls_hit=460,450 free_fb=39,649。 - 所感: 自スレッド TLS fast path を太らせるだけで目標どおり +10% 程度の改善が得られた。まだ free_fb がそこそこ残っているため、次に詰めるなら page_of / 自スレ判定の精度を上げて free_fb を削るフェーズ(Pool v1 flatten Phase2)を検討する。運用デフォルトは引き続き
POOL_V1_FLATTEN_ENABLED=0(安全側)とし、bench/実験時のみ opt-in。C7_SAFE プロファイル時は安全側で強制 OFF(クラッシュ回避のため)。
Phase81: Pool v1 flatten Phase2(free_fb 内訳の可視化)
- 変更: flatten stats に free fallback の理由別カウンタを追加(page_null / not_mine / other)。
hak_pool_free_v1_flatで mid_desc 取得失敗 → page_null、owner 不一致等 → not_mine、その他 → other として集計。 - ベンチ(C6-heavy, 1M/400, Release, Tiny/Pool v2 OFF, small v3 OFF,
POOL_V1_FLATTEN_ENABLED=1):- flatten OFF: 23.68M ops/s(stats 0)。
- flatten ON : 25.90M ops/s(約 +9.4%)、
alloc_tls_hit=499,870 alloc_fb=230 free_tls_hit=460,060 free_fb=40,039 page_null=40,039 not_mine=0 other=0。
- 所感: free fallback はほぼすべて mid_desc 取得失敗(page_null)によるもの。owner mismatch は 0。次は page_of/mid_desc 判定を精度アップさせ、free_fb をさらに削る余地がある。デフォルトは引き続き flatten OFF(安全側)。
Phase82: mid_desc マスク整合(free_fb 削減の第一歩)
- 変更:
mid_desc_register/lookup/adoptが扱うページアドレスをPOOL_PAGE_SIZEで正規化し、mmap の 64KiB 非アラインでも lookup が一致するように修正。flatten stats は page_null/not_mine/other もダンプするよう拡張済み。 - ベンチ(C6-heavy, 1M/400, Release, tiny/pool v2 OFF, LEGACY tiny, flatten ON):
- flatten OFF: 23.68M ops/s(参考)。
- flatten ON : 26.70M ops/s(約 +13% vs OFF)、
alloc_tls_hit=499,871 alloc_fb=229 free_tls_hit=489,147 free_fb=10,952 page_null=3,476 not_mine=7,476 other=0。
- 所感: page_null が大幅減少、not_mine が顕在化。owner 判定を少し緩め/精度アップする余地はあるが、デフォルトは引き続き flatten OFF(実験のみ ON)。
PhaseA/B (SmallObject HotBox v3 C7-only 通電)
- 追加:
HAKMEM_SMALL_HEAP_V3_ENABLED/CLASSESgate、routeTINY_ROUTE_SMALL_HEAP_V3、front の v3 経路(fallback 付き)。 - 型/IF:
core/box/smallobject_hotbox_v3_box.hに so_page/class/ctx+stats、TLS 初期化を実装。smallobject_cold_iface_v1.hで v1 Tiny への Cold IF ラッパ(C7 専用)を用意。 - Hot path:
core/smallobject_hotbox_v3.cで so_alloc/so_free を実装(current/partial freelist を持つ)。C7 で refill は Tiny v1 からページを借り、freelist を v3 で carve。retire 時に v1 へ返却。fail 時は v1 にフォールバック。 - デフォルト: ENV 未指定時は C7-only で v3 ON(
HAKMEM_SMALL_HEAP_V3_ENABLED未設定かつ CLASSES 未設定で class7 に v3 を適用)。HAKMEM_SMALL_HEAP_V3_ENABLED=0または CLASSES から bit7 を外せばいつでも v1 経路に戻せるようにしている。
Phase65-c7-v3-HEAP_STATS(C7-only v3 A/B 追加確認)
- 短尺 20k/ws=64:
- v3 OFF: 40.91M ops/s,
HEAP_STATS[7] fast=11015 slow=1。 - v3 ON (
CLASSES=0x80): 56.43M ops/s、SMALL_HEAP_V3_STATSでalloc_refill=49 fb_v1=0 page_of_fail=0(短尺ウォームアップ由来の refill)。segv/assert なし。
- v3 OFF: 40.91M ops/s,
- 長尺 1M/ws=400:
- v3 OFF: 38.29M ops/s,
HEAP_STATS[7] fast=550099 slow=1。 - v3 ON: 50.25M ops/s、
alloc_refill=5077 fb_v1=0 page_of_fail=0。slow は v1 と同等レンジ。
- v3 OFF: 38.29M ops/s,
- Mixed 16–1024B 1M/ws=400(参考):
- v3 OFF: 42.35M ops/s,
HEAP_STATS[7] fast=283169 slow=1。 - v3 ON: 49.60M ops/s,
alloc_refill=2446 fb_v1=0 page_of_fail=0。
- v3 OFF: 42.35M ops/s,
- 結論: HEAP_STATS 的にも slow≈1 を維持しつつ、v3 ON は C7-only/Mixed で大きくプラス。デフォルトでは C7-only v3 を ON(ENV 未指定で ENABLED=1, CLASSES=0x80 相当)としつつ、混乱や回帰時に備えて
SMALL_HEAP_V3_ENABLED=0/ クラスマスクでいつでも v1 に戻せるようにしている。***
Phase63: C6 v2 A/B(bench専用マスクでの初回計測)
- C6-heavy (min=257/max=768, ws=400, iters=1M, PROFILE=C7_SAFE, C7_HOT=1, v2 stats ON)
- v2 OFF (
HOTHEAP_V2=0): 42.15M ops/s, HEAP_STATS[7] fast=283169 slow=1。 - v2 ON (
HOTHEAP_V2=1, classes=0x40): 29.69M ops/s(大幅回帰)。HEAP_STATS[6] fast=266914 slow=16。v2 stats cls6 route_hits=0 / free_fb_v1=266930 で実質 v1 経路に落ちており、v2 専用処理が活きていない。 - 所感: C6 v2 を有効にすると現状大きく劣化。C6 マスクは研究用のまま(本線は C7 v1/v2 のみ)。
- v2 OFF (
- Mixed 16–1024B (ws=400, iters=1M, PROFILE=C7_SAFE, C7 v2 ON, v2 stats ON)
- C7 v2 only (
classes=0x80): 45.07M ops/s、HEAP_STATS[7] fast=283170 slow=2276、v2 alloc_lease/refill=2276。 - C6+C7 v2 (
classes=0xC0): 35.65M ops/s(大幅回帰)。HEAP_STATS[6] fast=137306 slow=1、cls7 slow=2276。v2 stats cls6 route_hits=0(C6 依然 v1)、cls7 refills=2276。 - 所感: C7 v2 は long-run で安定していたが、今回の 1M/400 では refill が 2,276 件まで増えスルーが低下。C6 を v2 に乗せる構成は混在でも回帰が大きく、当面研究箱のままに固定。
- C7 v2 only (
Phase64: C6 v2 route 修正 / C7 v2 refill 再トリアージ
- front の route switch を汎用化し、class6 でも
TINY_ROUTE_HOTHEAP_V2を直接呼ぶよう修正。v2 stats に route 値を追加。 - C6-heavy v2 ON (classes=0x40, ws=400, iters=100k): route_hits=26660, alloc_refill=1, fallback_v1=0、throughput 35.52M ops/s(v1よりは低めだが v2 パスが有効に)。
- C7-only 20k/ws=64 v2 ON: HEAP_STATS[7] slow=48、v2 alloc_refill=48(v2 OFF は slow=1)。Mixed 20k/ws=256 v2 ON でも alloc_refill=42。短尺では refill 多発が残っており原因再調査中。
- Next: C7-only 長尺でも slow/refill が増えているかを再確認し、refill_slow/partial ポリシーを見直す。C6 v2 は route/gate が通るようになったので、性能 A/B を改めて計測(未実施)。デフォルトは引き続き v2 OFF。
Phase71: PoolHotBox v2 初回 A/B(Cold IF=v1)→ 失敗
- C6-heavy (min=2048/max=8192, ws=400, iters=1M, PROFILE=C7_SAFE, Tiny v2 OFF)
- v2 OFF (
POOL_V2_ENABLED=0): 30.57M ops/s。 - v2 ON (
POOL_V2_ENABLED=1 POOL_V2_CLASSES=0x7F/0x1): 実行直後に SIGABRT(gdb でhak_pool_free_v2_impl→pool_hotbox_v2_page_ofの fail-fast で abort)。10k 短尺でも同様に abort し、POOL_V2_STATSは出力されず。
- v2 OFF (
- 所感: v2 alloc→v1 free の混線か page_of 範囲判定で落ちており、構造A/B がまだ通らない。デフォルトは v1 のまま維持。次ステップでは route/gate と page_of 整合を確認し、free_fb_v1 が跳ねない形に直してから再A/B する。
Phase65/66: v2 refill 可視化(C7短尺)と C6 v2 調査の前段
- C7-only (ws=64, iters=20k, v2 ON, stats ON): HEAP_STATS[7] fast=11016 slow=48。新設の refill stats で
refill_with_current=0 / refill_with_partial=0→ current/partial が空の状態で 48 回 refill 発生していることを確認(retire 0)。 - v2 OFF 同条件: slow=1(baseline)。短尺の refill 多発は依然再現するが、current/partial を失ってから refill しているパターンに絞れた。
- C6 v2 の性能トリアージは未着手(route は修正済み)。次ステップで C6-heavy / Mixed A/B を再取得し、route_hits>0 でのスループット/slow を確認する。
- Phase65 後半(長尺本命プロファイル)
- C7-only 1M/ws=400: v2 OFF 38.24M ops/s, v2 ON 38.68M ops/s(HEAP_STATS[7] fast=550099 slow=1、refill=1)。
- Mixed 16–1024B 1M/ws=400: v2 OFF 41.78M ops/s, v2 ON 41.94M ops/s(HEAP_STATS[7] fast=283169 slow=1)。refill は 1 件に収束し、fail/fallback なし。
- 結論: 短尺の refill≒50 はウォームアップ由来。本命プロファイルでは v2 ON/OFF で slow≈1 に張り付き、性能も ±5% 以内(むしろ微プラス)。
- 運用方針: デフォルト構成では
HAKMEM_TINY_HOTHEAP_V2=0を維持しつつ、C7-only の bench/pro プロファイルではHAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80を opt-in 推奨とする(Mixed/本番では明示しない限り OFF)。
Phase59: C7 HotHeap v2 Mixed A/B(C7-only 研究箱の現状)
- Mixed 16–1024B(ws=256, iters=20k,
PROFILE=C7_SAFE, v2 C7-only, v2 stats ON)で v2 ON/OFF を比較:- v2 OFF (
HAKMEM_TINY_HOTHEAP_V2=0): 45.11M ops/s, HEAP_STATS[7] fast=5691 slow=1。
- v2 OFF (
- v2 ON (
HAKMEM_TINY_HOTHEAP_V2=1, classes=0x80): 46.21M ops/s(約 +2.4%)、HEAP_STATS[7] fast=5692 slow=45。- HOTHEAP_V2_C7_STATS: route_hits=5692, alloc_fast=5692, alloc_lease/refill=45, cold_refill_fail=0, page_retired=4, fallback_v1=0。
- C7_PAGE_STATS: prepare_calls=45 → refill が多く current/partial を握り切れていない。
- 方針: v2 は Mixed でも微プラスだが slow_prepare が増えている。refill 後のページを温存する/partial を活用するポリシー調整で slow≈1 を目指す。デフォルトは引き続き v2 OFF(C7_SAFE v1 本線)。
Phase60: C7 v2 空ページ保持ポリシー導入(partial 温存+追加 stats)
- 変更:
tiny_hotheap_class_v2にmax_partial_pages(C7 デフォルト 2)とpartial_countを追加し、free でused==0のページは retire せず partial に温存。上限超のみ retire。partial push/pop/peak と retire_v2 を v2 stats に追加。 - ベンチ:
- C7-only (ws=64, iters=20k, PROFILE=C7_SAFE):
- v2 OFF: 41.94M ops/s, HEAP_STATS[7] fast=11015 slow=1。
- v2 ON: 50.43M ops/s, HEAP_STATS[7] fast=11016 slow=48。HOTHEAP_V2_C7_STATS: alloc_lease=48 (=refill), partial_push/pop/peak=0, retire_v2=0。
- Mixed 16–1024B (ws=256, iters=20k, PROFILE=C7_SAFE):
- v2 OFF: 42.82M ops/s, HEAP_STATS[7] fast=5691 slow=1。
- v2 ON: 47.71M ops/s, HEAP_STATS[7] fast=5692 slow=42。HOTHEAP_V2_C7_STATS: alloc_lease=42 (=refill), partial_push/pop/peak=0, retire_v2=0。
- C7-only (ws=64, iters=20k, PROFILE=C7_SAFE):
- 所感: slow_prepare は refill 回数と一致し、空ページがほぼ出ないため partial/retire はまだ発火していない。v2 は C7-only/Mixed ともプラスだが、refill=40〜50 が残る。ページ容量/lease 戦略や空ページを作る負荷での検証が次課題。デフォルトは引き続き v2 OFF(研究箱扱い)。
Phase61: C7 v2 長尺 Mixed (ws=400, iters=1M) 安定性チェック
- プロファイル: Mixed 16–1024B, ws=400, iters=1M, PROFILE=C7_SAFE, C7_HOT=1, LARSON_FIX=1, v2 classes=0x80, STATS_BOX ON, STATS_BATCH=0。
- ベンチ:
- v2 OFF: 41.58M ops/s, HEAP_STATS[7] fast=283169 slow=1。fail/fallback=0。
- v2 ON: 42.41M ops/s(約 +2%)、HEAP_STATS[7] fast=283169 slow=1。v2 statsは特記なし(fail/fallbackなし)。
- 所感: 長尺でも v2 ON で回帰なく微プラスを維持。slow=1 に張り付き、短尺で見えた refill 多発は再現せず。引き続きデフォルトは v2 OFF のまま研究箱扱い。
Phase61': C7 v2 短尺 Mixed 再確認(ws=256, iters=20k)
- プロファイル: Mixed 16–1024B, ws=256, iters=20k, PROFILE=C7_SAFE, C7_HOT=1, LARSON_FIX=1, v2 classes=0x80。
- ベンチ:
- v2 OFF: 43.27M ops/s, HEAP_STATS[7] fast=5691 slow=1。
- v2 ON: 44.57M ops/s(約 +3%)、HEAP_STATS[7] fast=5691 slow=1。
- 所感: 短尺でも slow_prepare は v2 OFF/ON ともに 1 件に収まり、fail/fallback も 0 で安定。Phase59 時点で見えていた「slow≈refill で 45 程度」という状態から改善され、C7 v2 は C7-only / Mixed / 短尺・長尺いずれでも v1 C7_SAFE を上回る構造になった。運用デフォルトは引き続き v2 OFF だが、bench/研究プロファイルでは C7 v2 を本命候補として扱える状態。
Phase68: mid/smallmid・pool 方面への次ターゲット整理
- 現状: mid/smallmid (257–768B メイン) のベースラインは HAKMEM ≈28–29M ops/s に対し mimalloc ≈54M / system ≈15M。Tiny 16–1024B は ~41–42M と比べ、mid/pool 側が大きく劣る。
- ホットスポット: perf では
hak_pool_try_alloc/free,memset,mid_desc_lookupが主因。pf/sys は小さく、CPU 側命令数削減がボトルネック。 - 目標: mid/smallmid で +5〜10%(28–29M → 30–32M)をまず達成すること。
- 方針: Tiny v2/C6 v2 は研究箱のまま固定し、pool/smallmid の Hot Box 化設計に着手(新規 POOL_V2_BOX_DESIGN を作成)。運用デフォルトは変えず、実装は段階的に A/B できるようゲート前提で進める。
Phase62: C6 v2 実験箱の足場を追加(コード実装のみ、デフォルト OFF)
- 変更:
- TinyHotHeap v2 を C6 でも動くように拡張(Hot Box ロジックを class_idx パラメータ化、stats をクラス配列化、TLS 初期化で C6 も partial 保持 2 枚に設定)。
- Route/Front は既存の 1 LUT + 1 switch をそのまま利用し、
HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x40で C6 v2 を opt-in。 - Cold IF は v1 TinyHeap をラップする既存実装を流用(refill/retire のみ触る)。fallback 記録/カウンタもクラス別に整備。
- 状態:
- デフォルトは v2 OFF(C7 SAFE v1 が本線)。C6 v2 は bench/研究専用の opt-in。ベンチ未実施(次フェーズで C6-heavy / Mixed A/B を取得予定)。
- C7 v2 の安定性・性能は維持(C6 追加による挙動変化はなし)。
Phase 36: TinyHotHeap v2 を「Hot Box」として再定義(設計ドキュメント整備)
- 状況: HotHeap v2 は Phase35 まで「v1 TinyHeap/C7 SAFE の上に乗るラッパ」で、Mixed では構造的に勝てない状態だったため、いったん棚上げ の扱いになっていた。
- 方針転換:
docs/analysis/TINY_HEAP_V2_DESIGN.mdに Phase36 セクションを追加し、TinyHeap v2 自体を per-thread Hot Box(TinyHotHeapBox v2)として再定義。Superslab/Tier/Remote/Stats/Learning はすべて外側の Cold Box に落とし、境界を- alloc 側:
tiny_heap_refill_slow(th, ci) - free 側:
tiny_heap_page_retire_slow(th, page)の 1 箇所に集約する設計に切り替えた。
- alloc 側:
- 設計内容:
TinyHeapCtx/TinyClassHeap/TinyPageMetaによる per-thread TinyHotHeap(C5〜C7)を Hot Box とし、C7-only → C6/C5 へ段階的に拡張する A 案を第一候補として整理。C7 超ホットレーン(B 案)、mimalloc 風 Segment+Page+Block へのフル寄せ(C 案)は将来の選択肢として文書化。 - ENV/A/B:
HAKMEM_TINY_HOTHEAP_V2/HAKMEM_TINY_HOTHEAP_CLASSESで v2 ON/OFF と対象クラスを切り替える方針を維持(デフォルトは依然 v2 OFF, v1 C7_SAFE)。Route Snapshot (g_tiny_route_class[ci]) で v1/v2/legacy を 1 LUT + 1 分岐で選択するイメージを明示。 - 実装ステータス: 現時点では 設計とドキュメントのみ整備。まだコードに TinyHotHeap v2 の新しい Hot Box 構造は反映していない(既存 v2 ラッパ実装もそのまま)。
- 次のアクション窓口:
- 実装ガイド:
docs/design/TINY_HOTHEAP_V2_IMPLEMENTATION_GUIDE.md(本フェーズで骨子を追加、実装担当 AI/開発者向けの指示書)。 - 詳細設計:
docs/analysis/TINY_HEAP_V2_DESIGN.md(Phase36+ セクションに A/B/C 案と Box 構造を集約)。
- 実装ガイド:
Phase 36+ (ChatGPT Pro フィードバック統合 / TinyHeap v2 ロードマップ再定義)
- 状況整理:
- Mixed 16–1024B: HAKMEM ≈41M ops/s / mimalloc ≈113M / system ≈92M → HAKMEM は mimalloc の ~36%、system の ~45%。
- mid/smallmid: HAKMEM ≈28–29M / mimalloc ≈54M / system ≈15M → mid/pool は mimalloc の ~50%、system の ~2×。
- Superslab/OS: SS_OS_STATS では 1M ops あたり
alloc≈2 free≈3 madvise≈2程度で、OS 呼び出しは支配的ではない。WarmPool (C7) は hit≈99%。 - pf: ≈6.6k/1M ops はほぼ first-write 起因と推定され、HugePage/ヘッダ軽量化実験でも大きく減らせていない。
- ChatGPT Pro からの提案(要約):
- 次に大きく変えるべきは TinyHeap v2 の Hot 層であり、「v1 の上に乗るラッパ」ではなく v1 と并列の Hot Box として再設計する。
- Superslab/Tier/Guard/Stats/Learning は v1/v2 共通の Cold Box とし、Hot→Cold の境界は共通インタフェース(
TinyColdIface的なもの)に集約する。 - TinyHeap v2 は C5–C7 をカバーしつつ、rollout は C7-only → C6 → C5 の順に段階的に行う。v1 は常に fallback/safe path として残し、PolicySnapshot で
tiny_heap_version[class]を切り替える。 - mid/smallmid/pool v2 は第2波の最適化対象とし、pf/first-touch/HugePage は v3 以降(最後の 5〜10% を詰めるテーマ)に回すのが妥当。
- ドキュメント反映:
docs/analysis/TINY_HEAP_V2_DESIGN.mdに「ChatGPT Pro からのフィードバックと v2 ロードマップ」セクションを追加し、- v1/v2 并列 Hot Box 構造(Front/Gate → TinyHeapBox v1 or TinyHotHeapBox v2 → 共通の Cold Box)
- v1/v2 共通の Cold インタフェース(TinyColdIface)導入方針
- C7-only → C5–C7 への段階的 rollout 戦略
- v2 世代では Superslab/Segment/Tier/Guard/Remote の構造は変えず、v3 世代で SmallObjectHeap 全体を再構成する を明文化。
- 今後のロードマップ(v2 世代の位置づけ):
- v2 では Tiny front/route Box(済)+ TinyHotHeap v2 の Hot Box 再設計に集中し、Cold Box 側はほぼ据え置きとする。
- mid/smallmid/pool v2 は構造スケッチと A/B ゲートまでに留め、本線は pool v1 のまま。
- pf/first-touch/HugePage は研究用モード(Mode A/B)として設計・実装を持ちつつ、運用デフォルトには含めない。
Phase 37: TinyHotHeap v2 C7 current_page ポリシー修正(スローパス多発の是正)
- ベンチ結果(Release, PROFILE=C7_SAFE):
- C7-only (ws=64, iters=20k): v2 OFF 40.09M ops/s / v2 ON 25.57M ops/s(
HEAP_STATS[7] fast=97 slow=32758→ ほぼ slow_prepare)。 - Mixed 16–1024B (ws=256, iters=20k): v2 OFF 40.99M ops/s / v2 ON 32.07M ops/s(
fast=141 slow=16654)。
- C7-only (ws=64, iters=20k): v2 OFF 40.09M ops/s / v2 ON 25.57M ops/s(
- 所感: v2 ON 時に
current_pageがほぼ活きず、C7-only/Mixed とも毎回slow_prepareに落ちて大幅回帰している(current_page stats:prepare_calls=slow_prepareで current_null≒0)。現状では v2 を運用に使えないため、デフォルトは引き続き v2 OFF(C7_SAFE + HOTHEAP_V2=0)が安全。 - 対応方針:
docs/design/TINY_HOTHEAP_V2_IMPLEMENTATION_GUIDE.mdに Phase37 セクションを追加し、C7-only 向けに- v2 専用 current_page デバッグ統計の追加(prepare_calls / prepare_with_current_null など)
- refill_slow で必ず
current_pageをセットするようにする - free 側で current_page を維持・再利用するポリシーを導入
- empty page の retire 条件を見直し(即返却せず partial として保持する実験を許容)
- v1 C7 SAFE/TinyHeapBox の current_page ポリシーを v2 に移植 を実装タスクとして明示。
- 判定基準: Phase37 完了の目安として、
- C7-only で v2 OFF と v2 ON が ±5% 以内(できれば同等以上)
HEAP_STATS[7]でfast≈11015 slow≈1に戻る- v2 current_page stats で
prepare_with_current_nullがprepare_callsに対して ≪1% 程度 を満たすことを目標とする。満たせない場合は引き続き v2 は研究用箱(デフォルト OFF)のままとする。
Phase 33: C7 v2 HotHeap A/B(薄型化の足がかり)
- 条件: Release, HEAP_STATS=ON, C7 SAFE (
PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1), v2 は C7 のみ (HAKMEM_TINY_HOTHEAP_CLASSES=0x80)。 - C7-only (ws=64, iters=20k): v2 OFF 39.42M ops/s / v2 ON 43.55M ops/s (cls7 fast=11015 / slow=1 で一致、v2カウンタ増加)。→ v2 の current/freelist 自前化で C7-only はわずかにプラス。
- Mixed 16–1024B (ws=256, iters=20k): v2 OFF 40.44M ops/s / v2 ON 36.58M ops/s (cls7 fast=5691 / slow=1 で一致、v2カウンタ増加)。→ Mixed では v2 のラップ/lease がまだオーバーヘッド。
- 所感: C7-only では v2 を保ったまま次の薄型化に進めそう。Mixed での回帰は lease 判定や v1 呼び出し重複が疑わしいため、Phase34 で「余計な枝/ロード」の整理候補に入れる。
Phase 32: C7 HotHeap v2 で current_page を自前管理(ページ供給だけ v1 から lease)
- v1 側に
tiny_heap_c7_lease_page_for_v2()を追加し、C7 SAFE が保持するページ情報(meta/ss/base/capacity)を lease できる境界を用意。 - v2 TLS ctx に C7 用 storage_page を持たせ、current_page が空/枯渇したときに lease を巻き取り、pop/push は v1 の
tiny_heap_page_pop/free_localを直接叩く形に変更(meta/ss_active の整合は v1 に委譲)。 - Free も current_page(lease_page)が一致する場合は v2 側で処理し、範囲外/不一致のみ従来 C7 free へフォールバック。Superslab/Remote/Stats は依然 v1 に任せる(lease は返却せず 1 枚だけ保持)。
- 目的: C7 v2 で current_page/freelist を握れる状態を作り、今後の v2 専用 slow 境界や multi-page 対応を進めやすくする。
Phase 31: C7-only HotHeap v2 A/B 配線(v1 ラッパ)
- ENV:
HAKMEM_TINY_HOTHEAP_V2+HAKMEM_TINY_HOTHEAP_CLASSES(bit7) で C7 を v2 経路に差し替え可能に。 - Front:
malloc_tiny_fast/free_tiny_fastの C7 直線パスで v2→v1→legacy slow の順に試行(デフォルトは v1)。 - 実体: v2 alloc/free は現時点で v1 の薄ラッパ(挙動不変、性能も A/B で同等の想定)。他クラスは未接続のまま。
- 目的: 次フェーズで C7-only で v1/v2 を切り替えられるようにする前段階。
- A/B(Release, HEAP_STATS=ON)
- C7-only (ws=64, iters=20k): v2 OFF 43.28M, v2 ON 43.28M(fast=11015 / slow=1 で一致)
- Mixed 16–1024B (ws=256, iters=20k): LEGACY 42.18M / C7_SAFE v2 OFF 41.15M / C7_SAFE v2 ON 40.74M(cls7 fast=5691 / slow=1 で一致)
Phase 28: v1 の締め(標準プロファイルと次世代入口)
- 標準プロファイルを固定:
- LEGACY … TinyHeap 無効。
- C7_SAFE …
HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_STATS_BOX=1 HAKMEM_TINY_STATS_BATCH=0(C7 SAFE + Stats Box 即時)。C6 は OFF。 - Bench/実験専用 … C7_ULTRA_BENCH、C6 TinyHeap(mask=0x40/0xC0)、STATS_BATCH=1。
- mimalloc 対決用フラグ(v1 基準点):
- C7-only:
HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_STATS_BOX=1 HAKMEM_TINY_STATS_BATCH=0 HAKMEM_TINY_LARSON_FIX=1(ULTRA は bench 用)。 - Mixed 16–1024B:
HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_LARSON_FIX=1で PROFILE=LEGACY と PROFILE=C7_SAFE を並べて比較。
- C7-only:
- C6 の扱いを凍結: C6 TinyHeap/Hot は v1 では bench 専用に留め、v2 で C5–C7 をまとめて再設計する前提に移行。
Phase 27: STATS_BOX / STATS_BATCH A/B(C7 SAFE)
- C7-only(20k/ws=64, PROFILE=C7_SAFE, HOT=1, LARSON_FIX=1, HEAP_STATS=ON)
- STATS_BOX=0: 43.31M ops/s(cls7 fast=11015 / slow=1)
- STATS_BOX=1, BATCH=0: 43.06M ops/s(fast/slow 同一)
- STATS_BOX=1, BATCH=1: 35.10M ops/s(fast/slow 同一、性能大幅低下)
- STATS_BOX=1, BATCH=1, META_MODE=2(ULTRA bench): 48.55M ops/s(bench 専用)
- Mixed 16–1024B(20k/ws=256, HEAP_STATS=ON)
- LEGACY: 40.92M ops/s
- C7_SAFE + STATS_BOX=1, BATCH=0: 42.72M ops/s
- C7_SAFE + STATS_BOX=1, BATCH=1: 35.27M ops/s
- 結論: STATS_BOX 自体は安全で BATCH=0 なら性能も同等〜わずかプラス。BATCH=1 は C7-only/Mixed とも大きく劣化するため bench 専用に留め、標準は STATS_BOX=1 & BATCH=0(または STATS_BOX=0)のままとする。
Phase 26: Cold Stats Box をバッチ対応アグリゲータに拡張(C7 SAFE)
core/box/tiny_stats_box.hに pending(used/active)と ENVHAKMEM_TINY_STATS_BATCHを追加。tiny_stats_flush_for_page()は delta を受け取り、バッチ ON なら page pending へ貯め、threshold(capacity×16 相当)超え or empty でtiny_stats_maybe_flush_for_page()が meta/ss_active_* にまとめて反映。バッチ OFF なら従来通り即時更新。tiny_heap_page_tに pending フィールドを追加し、tiny_heap_meta_flush_page()は C7 SAFE の delta を Stats Box に渡すだけに変更(deltas は heap 側で zero)。C7 以外の挙動は不変。- ドキュメント:
docs/analysis/COLD_TINY_STATS_BOX_DESIGN.mdに遅延許容条件とバッチフロー、ENV (HAKMEM_TINY_STATS_BOX,HAKMEM_TINY_STATS_BATCH) を追記。 - A/B は Phase27 で実施済み(C7-only/Mixed いずれも BATCH=1 は大幅マイナス)。挙動変更は C7 SAFE + Stats Box 有効時のみ。
Phase 25: Cold Stats Box(C7 SAFE flush の箱分離)
- 新規ドキュメント:
docs/analysis/COLD_TINY_STATS_BOX_DESIGN.mdを追加し、meta/active 更新を Cold Stats Box に押し出す設計メモを作成(Hot 側は page->used だけ、統計は Box 経由で更新する方針)。 - コード:
core/box/tiny_stats_box.hを追加(HAKMEM_TINY_STATS_BOXで A/B)。C7 SAFE (class7 meta_mode=1) の delta flush はtiny_stats_flush_for_page()経由に分離し、現状は従来と同じ meta->used / ss_active_* 更新を行うだけ(挙動不変)。 - ビルド:
make -j4 bench_random_mixed_hakmemOK。 - ベンチ (C7-only 20k/ws=64, PROFILE=C7_SAFE, HOT=1, HEAP_STATS=ON):
- STATS_BOX=0: 42.99M ops/s(cls7 fast=11015 / slow=1)。
- STATS_BOX=1: 42.92M ops/s(cls7 fast=11015 / slow=1)。挙動・カウンタ一致 → A/B で差分なし。
Phase 24: C6 SAFE 性能チェック(bench 専用の結論固め)
- 条件: Release, ws=256, iters=20k,
HAKMEM_TINY_LARSON_FIX=1, すべて debug ENV OFF。HAKMEM_TINY_HEAP_STATS=1 HAKMEM_TINY_HEAP_STATS_DUMP=1で測定。 - C6-heavy (min=257/max=768):
- LEGACY (TinyHeap OFF): 41.74M ops/s(HEAP_STATS 0)。
- C6 TinyHeap mode0 (
HEAP_BOX=1 HEAP_CLASSES=0x40 C6_HOT=1 C6_META_MODE=0): 36.07M ops/s(cls6 fast=5381 / slow_prepare=1)。 - C6 TinyHeap mode1 (
HEAP_BOX=1 HEAP_CLASSES=0x40 C6_HOT=1 C6_META_MODE=1): 28.86M ops/s(cls6 fast=2692 / slow_prepare=2690)。
- Mixed 16–1024B:
- LEGACY: 40.90M ops/s。
- C7_SAFE (C6 OFF,
PROFILE=C7_SAFE): 40.96M ops/s(cls7 fast=5691 / slow=1)。 - C6+C7 SAFE (
HEAP_CLASSES=0xC0/ C6+7 HOT / meta_mode=1): 27.21M ops/s(cls6 fast=1388 / slow=1366、cls7 fast=5664 / slow=19)。
- 結論: C6 TinyHeap は mode0/1 いずれも C6-heavy/Mixed で大幅マイナス。C6 meta_mode=1 は slow_prepare が増え性能も悪化。C6 は引き続き bench/実験専用マスク(0x40/0xC0)とし、通常は LEGACY または C7_SAFE プロファイルを推奨。
- 現状の扱い: C6 v2/TinyHeap は構造レベルでは通電しているが perf 未達のため「研究箱」に固定し、
HAKMEM_TINY_HOTHEAP_CLASSES=0x40/0xC0は常に opt-in(実験時のみ ON)とする。本線の TinyHeap は C7 SAFE(v1/v2)のみ。
- 現状の扱い: C6 v2/TinyHeap は構造レベルでは通電しているが perf 未達のため「研究箱」に固定し、
Phase 20: C6 Hot front の箱追加(C7 対称の直線パス)
- 新規ドキュメント:
docs/analysis/C6_HOTBOX_DESIGN.mdを追加し、C6 を TinyHeap でホット化する箱の目的と境界を定義(SAFE のみ、ULTRA なし)。C6 TinyHeap は当面 bench/実験扱いと明記。 - ENV/Route:
HAKMEM_TINY_C6_HOTを追加。1 のとき class6 だけ Gate→Heap の直線パスを有効化。- Route snapshot は
tiny_heap_class_route_enabled(6)がHAKMEM_TINY_C6_HOT && class_maskを満たすときだけ HEAP に設定。 tiny_c6_front_uses_heap()を追加し、C7 と対称の front 判定を用意。
- Front:
- alloc: size が class6 範囲((256, 512])かつ
tiny_c6_front_uses_heap()のとき、LUT/route を飛ばしてtiny_heap_alloc_class_fast(6)に直行。miss は静かにtiny_cold_refill_and_alloc(6)へ。 - free: class_idx==6 かつ
tiny_c6_front_uses_heap()なら Larson self-thread 判定後に TinyHeap free へ直行(route LUT は 1 回だけ参照)。
- alloc: size が class6 範囲((256, 512])かつ
- ベンチ(Release, ws=256, iters=20k, LARSON_FIX=1):
- C6-heavy (min=257/max=768):
- LEGACY (PROFILE=LEGACY): ≈44.0M ops/s。
- C6 TinyHeap + Hot (
HEAP_BOX=1 HEAP_CLASSES=0x40 C6_HOT=1 META_MODE=1): ≈38.3M ops/s(HEAP_STATS cls6: fast=5381 slow_prepare=1)。
- Mixed 16–1024B:
- LEGACY: ≈42.0M ops/s。
- C7_SAFE (C6 OFF): ≈42.3M ops/s。
- C6+C7 TinyHeap + Hot (
HEAP_CLASSES=0xC0 C6_HOT=1 C7_HOT=1 META_MODE C6=1 C7=1): ≈37.3M ops/s(HEAP_STATS cls6: fast=2753 slow=1 / cls7: fast=5682 slow=1)。
- C6-heavy (min=257/max=768):
- 所感: フロントを薄くしても C6 TinyHeap は依然マイナスが大きい。C7 SAFE は Mixed でもほぼ誤差~わずかプラス。C6 は bench/実験専用マスク(0x40/0xC0)の位置づけを維持。
Phase 19: プロファイル固定と次の箱候補
- プロファイルまとめ:
- LEGACY: TinyHeap 全無効(基準)。Mixed 16–1024B は ≈44M ops/s 台。
- C7_SAFE: class7 だけ TinyHeap + meta_mode=1。C7-only 20k/ws64 ≈46.6M、Mixed 16–1024B は LEGACY 比 ±1M 以内(軽いマイナス〜誤差)。C7-heavy 向け推奨プロファイル。
- C7_ULTRA_BENCH: class7 + meta_mode=2(bench 専用、Superslab/Tier 整合は緩む)。C7-only 20k/ws64 ≈52M。
- C6 TinyHeap:
HAKMEM_TINY_HEAP_CLASSES=0x40/0xC0は bench/実験専用。C6-heavy/Mixed では明確にマイナス(例: LEGACY≈44.3M → C6 TinyHeap≈38.6M)。
- 当面の運用:
- 普段は PROFILE=LEGACY か PROFILE=C7_SAFE を手で選択。C6 TinyHeap は明示しない限り OFF。
- C7-only 比較:
HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1(ULTRA は研究用途のみ)。 - Mixed 16–1024B: PROFILE=LEGACY と PROFILE=C7_SAFE を並べて比較。C6 を触るときは HEAP_CLASSES を明示し、HEAP_STATS で fast/slow を記録。
- 次に伸ばす箱候補(検討メモのみ):
- C6 TinyHeap を C7 SAFE 流に本気で攻める(current 固定 + delta/flush の安全版)。Superslab/Tier の整合を再チェックしつつ命令削減。
- Tiny front をさらに薄くする(class6/7 用の直線 front を拡張し、Gate/UC/TLS SLL 経路の命令を減らす)。上記1と実質同じ箱の別側面。
Phase 18: C6 SAFE 計測・メタモード拡張(環境ゲートのみ実装、挙動は整合優先)
- ENV:
HAKMEM_TINY_C6_META_MODEを追加(0=OFF, 1=SAFE)。現状は整合性優先で C6 は meta/active を per-alloc 更新のまま(behavior mode=0扱い、delta/flush 未使用)。TinyHeap へ載せるかはHAKMEM_TINY_HEAP_CLASSESで指定(デフォルト 0x80=C7 のみ)。 - C6 偏重 (min=257/max=768, ws=256, iters=20k, LARSON_FIX=1):
- LEGACY (TinyHeap OFF): ≈44.28M ops/s(HEAP_STATS=0)。
- TinyHeap C6 only mask=0x40, META_MODE=0: ≈38.81M ops/s(cls6 fast=5372 / slow_prepare=1)。
- TinyHeap C6 only mask=0x40, META_MODE=1: ≈38.59M ops/s(同上:slow_prepare≒1 → 回帰は prepare 頻度由来ではない)。
- TinyHeap C6+C7 mask=0xC0, C6 META=1 / C7 META=1: ≈39.94M ops/s(cls6 fast=5372/slow=1, cls7 fast=5691/slow=1)。
- Mixed 16–1024B (ws=256, iters=20k, LARSON_FIX=1):
- LEGACY: ≈44.27M ops/s。
- PROFILE=C7_SAFE (mask=0x80, C7 META=1): ≈43.64M ops/s。
- TinyHeap C6 only mask=0x40, META_MODE=0: ≈38.48M ops/s(cls6 fast=2744/slow=1)。
- TinyHeap C6 only mask=0x40, META_MODE=1: ≈38.66M ops/s(cls6 fast=2744/slow=1)。
- TinyHeap C6+C7 mask=0xC0, C6 META=1 / C7 META=1: ≈39.49M ops/s(cls6 fast=2744/slow=1, cls7 fast=5691/slow=1)。
- 所感: C6 は slow_prepare がほぼ 0 でも回帰しており、meta/route 側コストが支配的。C6 SAFE はまだ「挙動は mode 0 と同等(安全寄せ)」で、meta-light は未適用。次は C6 専用の軽量化を安全に再導入するか、Front/Gate/Route 側の命令削減を優先するかを検討。
現在の状態(Tiny / Superslab / Warm Pool)
- Tiny Front / Superslab / Shared Pool は Box Theory 準拠で 3 層構造に整理済み(HOT/WARM/COLD)。
- Tiny Gatekeeper Box(alloc/free)と Tiny Route Box により、USER→BASE 変換と Tiny vs Pool のルーティングを入口 1 箇所に集約。
- Superslab Tier Box(HOT/DRAINING/FREE)+ Release Guard Box により、SuperSlab ライフサイクルと eager FREE の安全な境界を定義。
- Warm Pool 層:
tiny_warm_pool.h: per-thread の HOT SuperSlab プール。warm_pool_stats_box.h: hits/misses/prefilled の統計箱。warm_pool_prefill_box.h: registry スキャン時に Warm Pool を事前充填する cold-path helper。
- Prefault Box(
ss_prefault_box.h)は追加済みだが、4MB MAP_POPULATE 問題を避けるためデフォルト OFF(HAKMEM_SS_PREFAULT=0)に設定。
直近の成果
- TinyHeap クラスマスク(C6 A/B 試験)と C6 ベンチ速報
- ENV
HAKMEM_TINY_HEAP_CLASSESを追加し、bitmask で TinyHeap に載せるクラスを制御(デフォルト 0x80=C7 のみ)。Gate も per-class で TinyHeap/旧フロントを切替。 - SLL refill/prewarm は
tiny_heap_class_route_enabled(cls)で早期 return するため、C6 を TinyHeap に載せても TLS SLL を踏まない 2 層構造を維持。 - ベンチ (Release, iters=20k, ws=256, min=257 max=768): TinyHeap OFF ≈45.7M ops/s / C6 TinyHeap (
HEAP_CLASSES=0x40) ≈39.7M / C6+C7 TinyHeap (0xC0) ≈34.1M (Tiny lane failed 警告あり)。 - Mixed 16–1024B でも TinyHeap OFF ≈46.8M / C7 only (
0x80) ≈39.4M / C6+C7 (0xC0) ≈33.8M(Tiny lane failed 警告が出る。Gate 側判定の整理が今後の課題)。
- ENV
- C7 TinyHeap Phase 3(stride キャッシュ+meta-light 実装)
tiny_heap_class_tに stride キャッシュを追加し、ctx 初期化時に全クラスの stride を前計算。tiny_heap_page_pop()は hcls->stride を使うようにして C7 alloc の算術コストを削減。- free 側で class7 は「今 free した page を current_page に優先」するように変更し、alloc_slow_prepare の頻度を下げる方向に調整。
HAKMEM_TINY_C7_META_LIGHT=1で meta->used / ss_active_add/dec を per-alloc で触らないベンチ用モードを実装(デフォルト OFF、page->used は維持)。- ベンチ(Release, iters=20k ws=64, C7-only):
- legacy (
HEAP_BOX=0 HOT=1): ≈42.5M ops/s。 - TinyHeap front (
HEAP_BOX=1 HOT=1 LARSON_FIX=1 META_LIGHT=0): ≈43.2M ops/s、stats=alloc_fast_current=10052 / alloc_slow_prepare=7681 / free_fast_local=10053 / free_slow_fallback=0。 - TinyHeap front + meta-light (
META_LIGHT=1): ≈48.1M ops/s、stats=alloc_fast_current=5837 / alloc_slow_prepare=5179 / free_fast_local=8727 / free_slow_fallback=0(active/meta の緩和によるベンチ専用モード)。
- legacy (
- C7 TinyHeap Phase 2(可視化+警告抑止)
HAKMEM_TINY_C7_HEAP_STATSを追加し、C7 TinyHeap のステップ別カウンタ(alloc_fast_current/alloc_slow_prepare/free_fast_local/free_slow_fallback/alloc_prepare_fail/alloc_fail)を計測できるようにした(HAKMEM_TINY_C7_HEAP_STATS_DUMP=1で終了時にダンプ)。hak_alloc_atで size==1024 かつ TinyHeap front ON の場合、Tiny lane 失敗扱いにせずtiny_c7_alloc_fastへフォールバック → Tiny lane failed 警告を除去。- TinyHeapBox に meta-light フラグ(
HAKMEM_TINY_C7_META_LIGHT)の足場を追加(Phase3 でベンチ用実装に移行済み)。 - Front gate の C7 分岐を TinyHeap front 優先に整理(likelyヒント付き)、C7 ラッパを
always_inlineに。 - ベンチ: Legacy (
HEAP_BOX=0 HOT=1) ≈43.0M ops/s。TinyHeap front ON (HEAP_BOX=1 HOT=1 LARSON_FIX=1) は警告なしで完走し、直近の測定では ≈34.8〜38.8M ops/s(DEBUG/環境の揺れあり)。HAKMEM_TINY_C7_HEAP_STATS=1でのカウンタは alloc_fast_current=10052 / alloc_slow_prepare=7681 / free_fast_local=10053 / free_slow_fallback=0 / alloc_prepare_fail=0 / alloc_fail=0。
- C7 TinyHeap front の SLL 切り離し(再現 SEGV 対応):
tiny_c7_heap_mode_enabled()を追加し、HAKMEM_TINY_HEAP_BOX=1 HAKMEM_TINY_C7_HOT=1のときは C7 を完全に TinyHeapBox ルートへ固定。sll_refill_small_from_ss()/sll_refill_batch_from_ss()で C7 を即 return する早期ゲートを追加し、hak_tiny_prewarm_tls_cache()でも C7 の TLS SLL prewarm をスキップ。tls_sll_push_impl()に C7 + TinyHeap front の拒否ガードを入れ、万が一 push が来ても SLL を触らないようにした。- 旧 slow path (
hak_tiny_alloc_slow) で C7 + TinyHeap front の場合は TinyHeapBox に委譲し、レガシー slow 経路を通さないようにした。 - ベンチ:
HAKMEM_BENCH_C7_ONLY=1、HAKMEM_TINY_HEAP_BOX=1 HAKMEM_TINY_C7_HOT=1で 20k ループ完走 (≈42–46M ops/s)。HAKMEM_TINY_SLL_LOG_ANY=1を付けても C7 の TLS SLL ログはゼロ。レガシー (HEAP_BOX=0) も同条件で ≈41.8M ops/s で回帰なし。
- TinyHeapBox 導入 (C7 先行 A/B):
core/box/tiny_heap_box.hで mimalloc 風 TinyHeap(current/partial/full + page 内 freelist)を Box 化。TLSg_tiny_heap_ctxに全クラスのヒープを保持し、下層 Box との接続は slow 境界 1 箇所に限定。- C7HotBox は薄いラッパ (
tiny_c7_alloc_fast/tiny_c7_free_fast_with_meta/tiny_c7_page_ofなど) に縮退させ、ENVHAKMEM_TINY_HEAP_BOX=1かつHAKMEM_TINY_C7_HOT=1で Gate から class7 を TinyHeap front に切替。 - free 側は Larson 判定に関係なく、self-thread なら meta 渡しで即 TinyHeap free、owner mismatch は remote queue、lookup 失敗時は
tiny_c7_free_fast()にフォールバック。 - docs 追記:
docs/analysis/C7_HOTBOX_DESIGN.mdに TinyHeapBox 移行メモを追加、新規docs/analysis/TINY_HEAP_BOX_DESIGN.mdに構造/責務/ENV/今後の移行ステップを整理。 - ベンチ/テスト:
make -j4 bench_random_mixed_hakmemビルド成功。- C7-only (
HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_HEAP_BOX=0 HAKMEM_TINY_C7_HOT=1 ./bench_random_mixed_hakmem 20000 64 1) → ≈42.95M ops/s。 - TinyHeap front ON (
HAKMEM_TINY_HEAP_BOX=1 HAKMEM_TINY_C7_HOT=1): 2k/5k/8k までは完走 (≈34–44M ops/s) するが、9k 以上でtls_sll_push_implSEGV が再現。valgrind では 10k 完走するため、SLL 周りの防御/初期化順を後続フェーズで要調査。
- C7 HotBox Phase 1.1(lookup 削減):
- free ホットパスに
tiny_c7_free_fast_with_meta(ss, slab_idx, base)を追加し、Larson fix (HAKMEM_TINY_LARSON_FIX!=0) で owner==self と判定できた場合のみ Superslab lookup を再実行せずに即 free。cross-thread は従来どおり remote queue、Larson fix OFF か lookup 失敗時は UC 経路にフォールバック。 tiny_c7_page_of()を TLS fast-first 化し、self-thread の C7 slab ならhak_super_lookup/slab_index_forを呼ばずに attach するようにした。- C7-only ベンチ(Release,
HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_LARSON_FIX=1 ./bench_random_mixed_hakmem 20000 64 1)でHAKMEM_TINY_C7_HOT=0 → ≈42.4M ops/s,HOT=1 → ≈40.6M ops/s(まだ -4% なので次フェーズで平滑化を続行)。
- free ホットパスに
- C7 HotBox(C7 専用 TinyHeap)の骨格追加:
core/box/tiny_c7_hotbox.hに C7 ページ/ヒープ構造 (tiny_c7_page_t,tiny_c7_heap_t) とホットパス API (tiny_c7_heap_for_thread,tiny_c7_alloc_fast,tiny_c7_alloc_slow_from_heap,tiny_c7_free_fast,tiny_c7_page_becomes_empty) を実装。TLS ごとに current/partial/full を持つ箱に閉じ込めた。- Gate は
size==1024 && HAKMEM_TINY_C7_HOT=1のときのみ C7HotBox へ分岐。オフ時は従来経路へフルフォールバックできる。 - 設計メモ
docs/analysis/C7_HOTBOX_DESIGN.mdを追加し、目的/構造/フロー図/A/B ポリシーを整理。 - ベンチは未実施(C7-only/C7-hot=1/0 のスモークを後続で実行予定)。
- Gatekeeper inlining(Phase A-1)完了:
malloc/freeラッパの関数呼び出しを削減しつつ、Box 境界は維持。 - Unified Cache Refill の debug 検証を 1 箇所に集約し、リリースビルドの HOT パスを軽量化:
bench_random_mixed_hakmem 1000000 256 42が約 4.3M → 5.0M ops/s(~+17%)に改善。
- Tiny-only/Tiny Mixed / Non-Tiny の条件差分をドキュメント化・分離:
bench_random_mixed_hakmemにHAKMEM_BENCH_MIN_SIZE/HAKMEM_BENCH_MAX_SIZEを追加し、- 8–128B(Tiny-only)
- 129–1024B(Tiny C5–C7 専用) を個別に測定可能にした。
docs/PERF_ANALYSIS_TINY_MIXED.mdほかに、8–128B/200K/ws=400(旧 Tiny 専用)と現在の 16–1024B/1M/ws=256(Tiny+Non-Tiny 混在)の違いを明記。
- Unified Cache Refill 安全化(Step 1 完了):
core/front/tiny_unified_cache.cのunified_cache_refill()でmax_batch <= 256を保証し、out[256]と常に整合するよう修正。- C5〜C7 の Unified Cache 容量・バッチサイズを増やす実験を行ってもスタック破壊が起きない状態にした。
- Tiny Page Box(C7 Tiny-Plus 層)の導入(Step 2 第1段階完了):
core/box/tiny_page_box.h/core/box/tiny_page_box.cを追加し、HAKMEM_TINY_PAGE_BOX_CLASSESで有効クラスを制御できる Page Box を実装。tiny_tls_bind_slab()からtiny_page_box_on_new_slab()を呼び出し、TLS が bind した C7 slab を per-thread の page pool に登録。unified_cache_refill()の先頭に Page Box 経路を追加し、C7 では「TLS が掴んでいるページ内 freelist/carve」からバッチ供給を試みてから Warm Pool / Shared Pool に落ちるようにした(Box 境界はTiny Page Box → Warm Pool → Shared Poolの順序を維持)。
- TinyClassPolicy/Stats/Learner Box を追加し、Hot path は
tiny_policy_get(class_idx)で Page/Warm ポリシーを読むだけに統一。- FROZEN デフォルト(legacy プロファイル):Page Box は C5〜C7 のみ ON、Warm は C0〜C7 すべて ON(C0〜C4 cap=4、C5〜C7 cap=8)。
- ENV
HAKMEM_TINY_POLICY_PROFILE=legacy|c5_7_only|tinyplus_allで切替可能(未指定は legacy)。 - Stats は OBSERVE 用に積むだけ、Learner は空実装のまま。
- mimalloc/system との最新ベンチ (Release, prefault デフォルト, policy=legacy, mode=2) を README_PERF に追記。C7-only 48.8M vs mimalloc 95.3M / system 73.9M、129–1024B 50.0M vs 128.4M / 97.7M、full 50.9M vs 123.6M / 83.5M、Tiny-only 8–128B 93.2M vs 123.7M / 66.3M。
- TLS Bind Box の導入:
core/box/ss_tls_bind_box.hにss_tls_bind_one()を追加し、「Superslab + slab_idx → TLS」のバインド処理(superslab_init_slab/meta->class_idx設定 /tiny_tls_bind_slab)を 1 箇所に集約。superslab_refill()(Shared Pool 経路)および Warm Pool 実験経路から、この Box を経由して TLS に接続するよう統一。
- C7 Warm/TLS Bind 経路の実装と検証:
core/front/tiny_unified_cache.cに C7 専用の Warm/TLS Bind モード(0/1/2)を追加し、Debug ではHAKMEM_WARM_TLS_BIND_C7で切替可能にした。- mode 0: Legacy Warm(レガシー/デバッグ用、C7 では carve 0 が多く非推奨)
- mode 1: Bind-only(Warm から取得した Superslab を TLS Bind Box 経由でバインドする本番経路)
- mode 2: Bind+TLS carve(TLS から直接 carve する実験経路)
- Release ビルドでは常に mode=1 固定。Debug では
HAKMEM_WARM_TLS_BIND_C7=0/1/2で切替。
- Warm Pool / Unified Cache の詳細計測:
warm_pool_dbg_box.hと Unified Cache の計測フックを拡張し、C7 向けに- Warm pop 試行/ヒット/実 carve 回数
- TLS carve 試行/成功/失敗
- UC ミスを Warm/TLS/Shared 別に分類 を Debug ビルドで観測可能にした。
bench_random_mixed.cにHAKMEM_BENCH_C7_ONLY=1を追加し、C7 サイズ専用の micro-bench を追加。
- TinyClassPolicy / Stats / Learner Box の導入(初期フェーズ):
core/box/tiny_class_policy_box.{h,c}にクラス別ポリシー構造体TinyClassPolicyとtiny_policy_get(class_idx)を追加。- FROZEN デフォルト: Page Box = C5–C7, Warm = 全クラス(C0–C4 cap=4 / C5–C7 cap=8)。
HAKMEM_TINY_POLICY_PROFILE=legacy|c5_7_only|tinyplus_allでプロファイル切替可能(未知値は legacy にフォールバック)。
core/box/tiny_class_stats_box.{h,c}に OBSERVE 用の軽量カウンタ(UC miss / Warm hit / Shared Pool lock など)を追加。core/box/tiny_policy_learner_box.{h,c}に Learner の骨組みを追加(現状は FROZEN/OBSERVE モード向けの雛形)。core/front/tiny_unified_cache.c/ Page Box / Warm Pool 経路をtiny_policy_get(class_idx)ベースでゲートし、Hot path からは Policy Box を読む形に統一。
bench_random_mixedに RSS ダンプ(getrusage(RUSAGE_SELF).ru_maxrss)を追加し、各 allocator で ops/s と合わせて常駐メモリを記録できるようにした。- 新規比較表
PERF_COMPARISON_ALLOCATORS.mdを追加。C7-only / 129–1024B / 16–1024B で HAKMEM(full/larson_guard) は ~50M ops/s / ~29MB RSS、system は ~95–78M ops/s / ~1.6MB RSS、mimalloc は ~74–126M ops/s / ~1.8MB RSS。 - SS stats (HAKMEM_SS_STATS_DUMP=1, full profile, 16–1024B ws=256/1M): live Superslab は C2=1, C7=1(empty_events: C7=1)、RSS は ~29MB。予算を 2 に絞っても同じ配置で RSS 変化なし → RSS は Superslab 枚数より TLS/Warm/Page stack 等の常駐分が支配的。
性能の現状(Random Mixed, HEAD)
- 条件: Release,
HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2 HAKMEM_WARM_C7_MAX=8 HAKMEM_WARM_C7_PREFETCH=4, ws=256- C7-only (size=1024, iters=200K, ws=32)
- policy=legacy: 47.3M / 47.3M / 43.9M ops/s(平均 ≈ 46M)。C7 uc_miss=6660 / warm_hit=3329 / shared_lock=5 / tls_carve_success=3329。
- policy=auto(Learner: score=lock*4+miss): 45.6M / 44.6M / 39.7M ops/s(平均 ≈ 43–45M)、統計は legacy と同一(C7 固定 ON)。
- guard 比較: full 42.4M ops/s vs larson_guard 40.7M ops/s(-4%程度で安全側ガードを維持)。
- 129–1024B (iters=1M, ws=256)
- legacy: 51.5M ops/s。C5 uc_miss=1/warm_hit=0/shared_lock=1、C6 uc_miss=1/warm_hit=0/shared_lock=2、C7 uc_miss=17196/warm_hit=8597/shared_lock=5/tls_carve_success=8597。
- auto: 51.9M ops/s(Learner=lock 重視でも C7 のみ ON、統計ほぼ同じ)。
- guard 比較: full 49.0M ops/s vs larson_guard 48.4M ops/s(-1.2%)。
- full random_mixed 16–1024B (iters=1M, ws=256)
- legacy: 51.0M ops/s。C7 uc_miss=16702/warm_hit=8350/shared_lock=5/tls_carve_success=8350(C5/C6 は uc_miss=1〜2)。
- auto: 50.0M ops/s(C7 固定 ON のまま、他クラスはほぼ動かず)。
- C7-only (size=1024, iters=200K, ws=32)
- 補足:
- WarmPool-STATS と TinyClassStats を統合。
HAKMEM_WARM_POOL_STATS=1で C7-only 実行時に hits=3329 / misses=1 / prefilled=1 を確認(TinyClassStats の warm_hit=3329 と一致)。 TinyClassPolicyにtls_carve_enabledを追加し、デフォルトで C5–C7 を ON。TinyClassStatsに tls_carve_attempt/success を追加済み。- Learner のスコアを
score = shared_lock * 4 + uc_missに変更済み(auto プロファイル専用)。現状のワークロードでは C7 が圧倒的に優勢で、C5/C6 はまだほぼ選ばれない。
- WarmPool-STATS と TinyClassStats を統合。
サイズ→クラス対応(HAKMEM_TINY_HEADER_CLASSIDX=1 のため size+1 で判定)
hak_tiny_size_to_class(size)はneeded=size+1でg_size_to_class_lut_2kを引くため、512B 要求は 513B として class 7 判定になる(現状の挙動は仕様どおり)。- 代表サイズのマップ(データサイズ→class_idx / 総バイト数)
- 8B → C1(16B stride)
- 16B → C2(32B)
- 32B → C3(64B)
- 64B → C4(128B)
- 128B → C5(256B)
- 256B → C6(512B)
- 512B → C7(2048B stride / 32 blocks per slab)
- 1024B → C7(同上)
- 512B 固定ベンチで C7 経路が動くのはこのヘッダ加算による設計上の結果。現時点では「C7 支配」を前提に C5/C6 は拡張枠として観測を続ける。
C5/C6 専用ワークロードの速報(Release, ws=512, iters=1,000,000, size fixed)
- 条件:
HAKMEM_BENCH_MIN_SIZE=256 HAKMEM_BENCH_MAX_SIZE=256 (実質 C6)、HAKMEM_TINY_PROFILE=full、HAKMEM_WARM_TLS_BIND_C7=2、HAKMEM_TINY_STATS_DUMP=1- policy=legacy: Throughput ≈ 89.9M ops/s。C6: uc_miss=5, warm_hit=1, shared_lock=2, tls_carve_attempt=1, tls_carve_success=1。
- policy=auto: Throughput ≈ 87.5M ops/s。C6 の統計はほぼ同じ(uc_miss=5, warm_hit=1, tls_carve_attempt/success=1)。C5 ほぼ負荷なし。
- 補足: C5/C6 はワーキングセットを広げても Warm/TLS carve のヒットは少数(キャッシュヒット優位なため)。専用負荷を増やす場合はさらに ws を広げて観測予定。
- Larson ベンチ(Release, 10 runs,
./test_larson.sh)- profile=full: 1.15〜1.26M ops/s
- profile=larson_guard: 1.10〜1.27M ops/s(≈-3〜0%でほぼ同等)。
HAKMEM_SS_STATS_DUMP=1で Superslab live が 1 前後に収まり、SEGV/OOM なし。サンプルログはdocs/analysis/SUPERSLAB_STATS_SNAPSHOT.mdに記録。
新しいログ/ENV スイッチ
HAKMEM_TINY_POLICY_LOG=0/1: Policy 初期化/auto update のログ抑制(デフォルト ON)。HAKMEM_TINY_WARM_LOG=0/1: C7 prefill 関連ログ(PREFILL_META/skip 等)の抑制(デフォルト ON)。HAKMEM_TINY_PAGEBOX_LOG=0/1: Page Box の登録ログ抑制(Debug のみ、デフォルト ON)。- 長時間ラン時は上記を 0 にしてノイズを抑える運用を推奨。短時間デバッグ時のみ 1 にする。
次にやること(広い条件での安定化確認)
HAKMEM_BENCH_MIN_SIZE=129 HAKMEM_BENCH_MAX_SIZE=1024や通常のbench_random_mixed_hakmem 1000000 256 42で 空スラブ限定ガードが副作用なく動くかを継続確認(現状 Release で 29–30M ops/s を確認済み)。- ドキュメント更新:
- Release だけ C7 Warm が死んでいた根本原因 = 満杯 C7 slab を Shared Pool がリセットせず再供給していた。
- Acquire の空スラブ強制ガード+Stage3(LRU) 再利用時の Superslab 全スロットリセット+Warm/TLS carve 有効化で、 C7-only Release が ~20–25M ops/s クラスに回復し、Random Mixed 16–1024B Release も ~29–30M ops/s クラスまで改善した。
- 次フェーズ案:
- Superslab ガード(Stats/Reset/Stage3/Budget/larson_guard)まで完了。以降は mimalloc/system との比較最適化や、必要に応じた C5/C6 Tiny-Plus 拡張を検討。
次フェーズ(Tiny 全クラス向け Page Box / Warm / Policy 汎用化の検討)
- 方向性:
- 現在は C7 向け Tiny-Plus(Page Box + Warm Pool + TLS Bind)が安定したため、C1〜C7 まで「候補」として広げつつ、 実際にどのクラスで有効化するかは Policy Box(学習/ENV)側で制御する設計に進める。
- 設計方針(案):
TinyClassPolicyBoxを新設し、クラス別ポリシー構造体(TinyClassPolicy{ page_box_enabled, warm_enabled, warm_cap, ... })を配列で保持。- Hot path(Tiny Front / Unified Cache / Page Box / Warm Pool)は
tiny_policy_get(class_idx)でポリシーを読むだけにし、 学習/更新はTinyPolicyLearnerBox側で行う。 TinyClassStatsBoxを導入し、クラス別に UC miss / warm hit / shared_pool_lock などの軽量カウンタを記録(OBSERVE/LEARN モード用)。- モードは FROZEN / OBSERVE / LEARN を ENV で切替可能にし、デフォルトは FROZEN(C5–C7 のみ Page Box/Warm ON, 他クラス OFF)。
- 実装ステップ(案):
- C7 Page Box / Warm / TLS Bind の API を「class_idx を引数に取る汎用形」に整理し、内部で
if (!policy->page_box_enabled) fallbackする形にリファクタ。 TinyClassPolicystruct とtiny_policy_get(class_idx)を導入し、Hot path から直接HAKMEM_*ENV を参照しないようにする(Policy Box 経由に統一)。TinyClassStatsBoxを追加し、FROZEN/OBSERVE モードで C1〜C7 の stats を集計(policy はまだ固定)。TinyPolicyLearnerBoxを追加し、LEARN モードで stats をもとにpage_box_enabled[]/warm_cap[]を更新(ただし「同時に ON にできるクラス数」に上限を設ける)。
- C7 Page Box / Warm / TLS Bind の API を「class_idx を引数に取る汎用形」に整理し、内部で
- 進捗メモ(実装済み):
TinyClassPolicyBox/TinyClassStatsBox/TinyPolicyLearnerBoxを追加し、デフォルトで C5〜C7 に Page Box + Warm を許可(Warm cap=8)。- unified_cache_refill の Page/Warm 経路は
tiny_policy_get()の返り値でゲートし、Warm push は per-class cap を尊重。 - Page Box 初期化もデフォルトで C5〜C7 を有効化。OBSERVE 用の軽量 stats increment を UC miss / Warm hit に接続済み。
- 次ステップの設計メモ:
- TinyPageBoxContext を class 汎用構造に広げ、C5/C6 も「TLS Bind で page 登録 → UC refill で page 内 freelist からバッチ供給」を C7 と共有できるようにする(実装は未着手、設計メモのみ)。
メモ
- ページフォルト問題は Prefault Box + ウォームアップで一定水準まで解消済みで、現在の主ボトルネックはユーザー空間の箱(Unified Cache / free / Pool)側に移っている。
- 以降の最適化は「箱を削る」ではなく、「HOT 層で踏む箱を減らし、Tiny 的なシンプル経路と Tiny-Plus 経路(Page Box + Warm)をクラス別ポリシーでどう使い分けるか」にフォーカスする。
今回の変更(C7 meta-light をページ境界バッチ flush 化)
tiny_heap_page_tに C7 用の delta (c7_active_delta/c7_used_delta) を追加し、meta-light ON 時は per-alloc で meta/active を触らず delta のみ更新。- ページが empty になる/ノード解放時に
tiny_c7_meta_flush_page()で delta をまとめて meta->used / total_active_blocks に反映。負側はss_active_dec_oneを繰り返す素朴実装(ベンチ頻度は低い前提)。 HAKMEM_TINY_C7_META_LIGHTは依然 bench/研究用。デフォルト OFF。本番統計は OFF 時と同じ挙動を維持。- C7-only 20k/ws64 ベンチ: legacy (HEAP_BOX=0 HOT=1) ≈41.2M ops/s、TinyHeap front META_LIGHT=0 ≈41.9M ops/s、META_LIGHT=1(バッチ) ≈53.5M ops/s。stats: META_LIGHT=1 で alloc_fast_current=11013 / alloc_slow_prepare=3 / free_fast_local=9294。
今後のフォーカス(C7 支配を前提に一旦整理)
- 設計明記: 257–512→C6, 513–2048→C7(size+1 判定)。実負荷は C7 が受ける設計として確定。C5/C6 は拡張枠・観測対象。
- 優先度: C5-only ≈91M ops/s、512B 固定も C7 経路で ≈47M ops/s → C5/C6 最適化は auto/実験用に留め、本命は C7 Tiny-Plus+Policy。
- プロファイル運用: legacy=本番、auto=C7固定+上位2クラス観測用のまま据え置き。学習拡張は新ワークロードで C5/C6 がホットになった際に検討。
- 次の大きな箱候補: (1) mimalloc/system とのフルベンチ整理(論文/README 更新)、(2) hakorune 側 PHI/JoinIR の開発にリソースを戻す。
巨大 BSS グローバルの棚卸しと今後
nm -S --size-sort bench_random_mixed_hakmemと SS_STATS のサンプルから、RSS を支配しているのは Tiny 層ではなく巨大 BSS 配列であることを確認。- 代表例:
g_super_reg≈24MB,g_shared_pool≈2.3MB,g_super_reg_by_class≈1MB,g_rem_side≈1MB など。 - SS_STATS(ws=64, iters=10k)では live Superslab は C2=1, C7=1 程度で、巨大レジストリの大半は未使用キャパシティになっている。
- Tiny 用メモリ会計 Box(
tiny_mem_stats_box)では UC/Warm/Page/TLS/Policy-Stats 合計でも ≈40KB 程度と判明し、RSS≈29MB の主因ではないことを確認。
- 代表例:
- docs/analysis/LARGE_GLOBALS_OVERVIEW.md に各大型シンボルのサイズ/役割と SS_STATS とのギャップを一覧化済み。
次フェーズ候補:
- Superslab Registry / Shared Pool / Remote Queue を Box 化し、プロファイル別に「必要なだけ動的確保」できる SuperRegBox / SharedPoolBox / RemoteSideBox への移行を検討。
HAKMEM_PROFILEや ENV から「bench 向け縮小設定」と「本番向けフル設定」を切り替えられるようにし、RSS を抑えつつ Box 構造は維持する。
進捗(巨大BSS Box化フェーズ)
- docs/analysis/LARGE_GLOBALS_OVERVIEW.md に大型シンボルの定義元・役割・縮小目安を追記(SuperReg/SharedPool/Remote など)。
- 設計スタブを追加:
core/box/super_reg_box.h… レジストリ容量をプロファイルで切替するための API メモ。core/box/shared_pool_box.h… Shared Pool の容量/ガードをプロファイルに紐づけるための API メモ。core/box/remote_side_box.h… Remote Queue テーブルをプロファイルで縮小するための API メモ。
HAKMEM_PROFILE=benchを追加し、SuperReg/SharedPool/Remote の「論理有効スロット」を 1/8〜1/16 に制限するラッパを実装(配列は現状サイズのまま)。bench_random_mixed_hakmemは full/bench ともビルド・完走済み。C7-only/129–1024B/16–1024B で ops/s は ±数% 以内、RSS は ~32.6MB でほぼ不変(論理制限のみのため)。- SuperReg/Remote を Box 内で動的確保に置き換え、
HAKMEM_PROFILE=benchでは実容量も縮小(SuperReg: 1/8〜1/16、Remote: log2 を 12〜)。C7-only 200k/ws32 では full=29.6MB → bench=7.2MB (ops ≈44.4M 同レンジ) まで RSS を削減できた。 - bench 実容量版での広いワークロード検証: 129–1024B ws=256/1M は full=48.9M ops/s & 29.6MB → bench=49.2M & 7.2MB。16–1024B ws=256/1M は full=48.3M & 29.7MB → bench=48.8M & 7.2MB。SS_STATS(bench)でも live Superslab は C2=1, C7=1 に収まり、Tiny 層メモリは ~41KB のまま。
- 次ステップ: SharedPool 側も必要なら動的化/縮小を検討しつつ、RSS をさらに攻めるか、CPU パス最適化に戻るか判断。***
フェーズ整理と次の方針
- SharedPool は現状サイズを維持し、
HAKMEM_PROFILE=fullを本番、HAKMEM_PROFILE=benchを対 mimalloc/system の軽量プロファイルとして運用(bench は SuperReg/Remote 縮小済み、RSS≈7.2MB)。 - 巨大BSS Box化フェーズは「bench で RSS≈7.2MB / ops≈同等」まで完了。今後は perf(CPUサイクル)最適化にフォーカス。
Phase 5: C7 delta debug フック(meta-light バッチ版)
core/box/tiny_heap_box.hにHAKMEM_TINY_C7_DELTA_DEBUGゲートとtiny_c7_heap_debug_dump_deltas()を追加。meta-light ON 時に page ごとのc7_used_delta/c7_active_deltaを stderr へダンプできるようにした。core/hakmem_tiny.cに destructor フックを追加し、HAKMEM_TINY_C7_META_LIGHT=1 HAKMEM_TINY_C7_DELTA_DEBUG=1でベンチ終了時に自動チェック(1 スレッド前提で TLS TinyHeap ctx を走査)。- ベンチ (C7-only, ws=64, Release):
- 20k: legacy (HEAP_BOX=0 HOT=1) ≈39.7M ops/s、TinyHeap META_LIGHT=0 ≈39.9M、META_LIGHT=1 ≈54.0M。
- 100k: TinyHeap META_LIGHT=0 ≈39.9M、META_LIGHT=1+DELTA_DEBUG ≈51.3M(delta 残: idx0 used_delta=7669 active_delta=7669 used=6)。
- 200k: TinyHeap META_LIGHT=1+DELTA_DEBUG ≈48.1M(delta 残: idx0 used_delta=14727 active_delta=14727 used=6)。
- delta debug から、長時間ランでも live page に delta が積み上がる(empty/release でのみ flush する設計のため)ことを確認。次フェーズで閾値 flush や partial→current の切替タイミング改善を検討する。
Phase 6: C7 delta 閾値 flush + clamp
tiny_c7_delta_should_flush()を追加し、C7 meta-light ON かつ|delta| >= max(256, capacity*16)でホットパスからtiny_c7_meta_flush_page()を実行。per-alloc atomic なしで delta を capacity の数倍にバウンド。tiny_heap_attach_page()で C7 meta-light 時にusedをcapacityへ clamp(c7_delta も 0 クリア)し、過去ラン由来の巨大 meta->used でも TLS ノードを安全に再利用。- ベンチ (C7-only ws=64, Release):
- Legacy HEAP_BOX=0 HOT=1: ≈42.5M ops/s
- TinyHeap HEAP_BOX=1 HOT=1 LARSON_FIX=1 META_LIGHT=0: ≈43.1M ops/s
- TinyHeap META_LIGHT=1 (閾値 flush/clamp): ≈42.6M ops/s
- 長時間 delta debug(META_LIGHT=1 DELTA_DEBUG=1):
- 100k/200k:
[C7_DELTA_SUMMARY] nonzero_pages=0 used_delta_sum=0 active_delta_sum=0(delta 残なし)
- 100k/200k:
Phase 7: TinyHeap クラス選択(C6 載せ替えの土台)
- ENV
HAKMEM_TINY_HEAP_CLASSES(bitmask、デフォルト 0x80=C7 のみ)を追加。tiny_heap_class_route_enabled(cls)で TinyHeap front を使うクラスを切替。 - Front gate:
malloc_tiny_fast/free_tiny_fastでクラスごとに TinyHeap ルートを選択。C7 は従来通りtiny_c7_heap_mode_enabled()(HAKMEM_TINY_C7_HOT 連動)でガードし、それ以外のクラスはtiny_heap_alloc/free_class_fast()を呼ぶ経路を追加。 - TLS SLL との分離をクラス単位に拡張:
sll_refill_small_from_ss/sll_refill_batch_from_ss/hak_tiny_prewarm_tls_cacheはtiny_heap_class_route_enabled(cls)のとき即 return/skip(C6 も TinyHeap に載せたら SLL を経由しない)。 - ドキュメント: TinyHeapBox/C7HotBox 設計にクラス bitmask と multi-class 対応の方針を追記。ベンチは今後 C6/C7 切替パターンで再計測予定。
Phase 9: Tiny lane 判定を TinyHeap と整合
hak_alloc_atで Tiny route の class_idx / TinyHeap route ON/OFF を保持し、Tiny front NULL 時に TinyHeap を直接試行。TinyHeap が有効なクラスでの NULL は静かなフォールバック扱いにし、Tiny lane failed警告は legacy Tiny route が本当に失敗した場合のみ出す。- Gate から TinyHeap 経路で成功した alloc/free は Tiny lane 成功として扱うよう統一(C6/C7 の mixed で出ていた警告を抑止)。
- ベンチ (Release, iters=20k, ws=256):
- C6 偏重 (min=257 max=768): OFF≈47.8M / C6-only TinyHeap≈39.2M / C6+C7 TinyHeap≈31.3M(警告なし)。
- Mixed 16–1024B: OFF≈47.6M / C7-only TinyHeap≈36.9M / C6+C7 TinyHeap≈30.3M(警告なし)。
- ドキュメント更新: Tiny lane 判定と TinyHeap 整合のメモを
docs/analysis/TINY_HEAP_BOX_DESIGN.md/docs/analysis/C7_HOTBOX_DESIGN.mdに追記。
Phase ULTRA: C7 meta モードを 0/1/2 の 3 段階に
- 新 ENV
HAKMEM_TINY_C7_META_MODEを導入(0:OFF, 1:SAFE meta-light=従来の delta+閾値 flush/clamp, 2:ULTRA=bench 専用で meta/active を per-alloc では触らない)。HAKMEM_TINY_C7_META_LIGHTは未指定時の後方互換ゲートとして残し、mode 未指定なら SAFE=1 相当。 - ULTRA(mode=2) は per-alloc で meta->used / ss_active_* を更新せず、delta/flush もスキップ。Box 境界は維持するが Superslab/Tier 統計は崩れる前提で C7-only bench 専用。
- SAFE(mode=1) は従来のページ境界 flush + 閾値 flush + attach clamp を維持。本番は mode=0/1 のみを推奨。
- ベンチ (C7-only 20k/ws=64, Release, HEAP_BOX=1 HEAP_CLASSES=0x80 HOT=1 LARSON_FIX=1):
- mode=0: ≈35.0M ops/s
- mode=1: ≈37.1M ops/s
- mode=2 (ULTRA): ≈41.4M ops/s
- ドキュメント更新: meta モードの三段化と ULTRA は bench 専用である旨を
docs/analysis/TINY_HEAP_BOX_DESIGN.md/docs/analysis/C7_HOTBOX_DESIGN.mdに追記。
Phase 10: C7 ULTRA の軽量化&fast/slow 計測(20k/ws=64, Release)
- 変更: ULTRA(mode=2) の pop/push で meta->freelist/carved への atomic store をスキップ(per-alloc の余分な write を削減、Box 境界は維持)。
- C7-only stats(HEAP_BOX=1 HEAP_CLASSES=0x80 HOT=1 LARSON_FIX=1 C7_HEAP_STATS=1):
- mode=0: ops≈38.7M / alloc_fast_current=10052 / alloc_slow_prepare=7681 / free_fast_local=10053
- mode=1: ops≈34.1M / alloc_fast_current=5837 / alloc_slow_prepare=5179 / free_fast_local=8727
- mode=2(ULTRA): ops≈41.6M / alloc_fast_current=5948 / alloc_slow_prepare=5068 / free_fast_local=7190
- 所感: slow_prepare 割合が依然高く、ULTRA でも legacy(≈42.5M) をわずかに下回る。次ステップは current_page の持続や prepare 回数削減に集中する。
Phase 11: C7 current_page の可視化と ULTRA 固定化トライ(20k/ws=64, Release)
- 追加カウンタ(C7_HEAP_STATS=1 連動):
g_c7_page_statsを導入し、prepare_calls / prepare_with_current_null / prepare_from_partial / current_set_from_free / current_dropped_to_partial を記録。destructor で[C7_PAGE_STATS]をダンプ。 - C7 ULTRA の free パスを強化: free で used>0 のページは必ず current_page に据え直し、meta 触らず早期 return。page stats もこの経路でカウント。
- ベンチ (mode=2 ULTRA, HEAP_BOX=1 HEAP_CLASSES=0x80 HOT=1 LARSON_FIX=1 C7_HEAP_STATS=1 stats dump ON):
- ops≈40.9M
- C7_HEAP_STATS: alloc_fast_current=5948 / alloc_slow_prepare=5068 / free_fast_local=7190
- C7_PAGE_STATS: prepare_calls=5068 / prepare_with_current_null=5068 / prepare_from_partial=0 / current_set_from_free=0 / current_dropped_to_partial=0 → prepare のたびに current_page が NULL になっており、free 側で current を維持できていないことが判明。次は current_page ポリシー/attach パスの軽量化を追加で検討。
- ULTRA の current_page 固定化(unlink/empty を抑止、prepare で current を優先)を追加。
- C7-only 20k/ws=64, mode=2: ops≈52.0M、C7_HEAP_STATS: fast=11015 / slow_prepare=1 / free_fast_local=7137、C7_PAGE_STATS: prepare_calls=1 (current null=1)。
- 現状 C7 ULTRA は legacy (~42.5M) を上回り、slow_prepare をほぼ 0 に抑制できている。SAFE への逆輸入余地は今後検討。
Phase 12: SAFE (META_MODE=1) に current_page ポリシーを逆輸入
- C7 SAFE で current_page を極力保持するように変更(empty 時も delta flush のみで detach せず current 維持、mark_full で current を追い出さない、prepare は current に空きがあれば即 return)。
- ベンチ (HEAP_BOX=1 HEAP_CLASSES=0x80 HOT=1 LARSON_FIX=1, ws=64):
- SAFE mode=1, 20k: ops≈46.6M(C7_HEAP_STATS fast=11015 / slow_prepare=1 / free_fast_local=8726、C7_PAGE_STATS: prepare_calls=1)。
- SAFE 長時間: 100k≈46.7M / 200k≈44.99M。
HAKMEM_TINY_C7_DELTA_DEBUG=1でも[C7_DELTA_SUMMARY] nonzero_pages=0 used_delta_sum=0 active_delta_sum=0。
- SAFE 長時間: 100k≈46.7M / 200k≈44.99M。
- ULTRA (mode=2) は bench 専用のまま。本番寄りは mode=0/1 を使用する方針。
Phase 13: TinyHeap stats 汎用化と C6/C7 混在ベンチ
- 変更:
TinyC7HeapStatsをTinyHeapClassStats g_tiny_heap_stats[TINY_NUM_CLASSES]に拡張し、HAKMEM_TINY_HEAP_STATS/_DUMP(従来の_C7_も互換)で全クラスの fast/slow/fallback を取得可能にした。C7 page stats は従来通り。 - Mixed 16–1024B (iters=20k, ws=256, LARSON_FIX=1):
- TinyHeap OFF: ≈43.7M ops/s。
- C7 SAFE のみ TinyHeap (
HEAP_BOX=1 HEAP_CLASSES=0x80 META_MODE=1 HOT=1): ≈44.9M ops/s(HEAP_STATS[7] fast=5691 slow_prepare=1)。 - C6+C7 TinyHeap (
HEAP_CLASSES=0xC0同条件): ≈39.3M ops/s(HEAP_STATS[6] fast=2744 slow=1,HEAP_STATS[7] fast=5691 slow=1)。
- C6 偏重 (min=257 max=768, iters=20k, ws=256):
- TinyHeap OFF: ≈43.8M ops/s。
- C6 TinyHeap のみ (
HEAP_CLASSES=0x40, C7 legacy): ≈38.5M ops/s(HEAP_STATS[6] fast=5372 slow=1)。 - C6+C7 TinyHeap (
HEAP_CLASSES=0xC0, C7 SAFE): ≈40.6M ops/s(HEAP_STATS[6] fast=5372 slow=1,HEAP_STATS[7] fast=5691 slow=1)。
- 方針メモ: C7 SAFE は mixed でも悪化せずプラスが見えるのでデフォルト TinyHeap 候補。C6 は slow_prepare は少ないが経路オーバーヘッドで throughput 低下が大きいので、当面は bench/実験用 (HEAP_CLASSES=0x40/0xC0) に留める。推奨例: 本番寄り C7 は
HEAP_BOX=1 HEAP_CLASSES=0x80 META_MODE=1、C7-only bench はMETA_MODE=2。
Phase 21–22 (C6 meta_mode=1 クラッシュ切り分け: 実験専用)
- C6 meta_mode=1 は bench/実験専用として明記(通常ベンチは meta_mode=0 or C6 TinyHeap OFF 推奨)。
- C6 delta/flush トレース:
HAKMEM_TINY_C6_DELTA_TRACEで last_delta_site を記録、HAKMEM_TINY_C6_DELTA_DEBUGと合わせて class6 の delta を dump 可能。 - C6 pop Fail-Fast:
HAKMEM_TINY_C6_DEBUG_POP=1でtiny_heap_page_popが page 範囲/容量/空き無し/ss mismatch/クラス不整合/容量 0/フリーリスト OOB を検知すると[C6_POP_FAIL]を吐いて abort。pop/free のデバッグログもこの ENV でのみ出力(上限512行)。 - 防御強化:
- attach 時に meta->freelist を範囲チェックし、OOB は
meta->freelist=NULLに潰す(debug 時のみ 1 行ログ)。 - empty→release 時に C6 SAFE は meta->freelist を NULL にし、debug 時は page->free_list を poison して再利用時の壊れを検知。
- pop で freelist OOB を Fail-Fast 追加。
- delta site にタグ付け(ALLOC/FREE/ATTACH/EMPTY/THRESHOLD)、flush 前に記録して壊れたページの直前イベントを把握できるようにした。
- attach 時に meta->freelist を範囲チェックし、OOB は
- 再現状況(C6-heavy min=257/max=768, ws=256, HOT=1, meta_mode=1, DEBUG_POP/DELTA_TRACE/DELTA_DEBUG=1):
- iters=1000/1500/2000: すべて完走、
C6_DELTA_SUMMARYは 0/0/0、Fail-Fast ログなし。 - iters=20000 でも完走(同じく delta_sum=0)。ネイティブでの以前の SIGSEGV は再現せず。
- ログ末尾は同一ページ内で free_list が範囲内に収まり、last_delta_site は ATTACH/ALLOC を往復。
→ クラッシュ原因は meta->freelist の OOB 読み込みが濃厚。Fail-Fast/Poison で暫定的に封じ込め。
- iters=1000/1500/2000: すべて完走、
Phase 14: TinyHeap Profile Box 追加とプロファイル別 A/B
- ENV を整理:
HAKMEM_TINY_HEAP_PROFILEを追加(LEGACY/C7_SAFE/C7_ULTRA_BENCH/CUSTOM)。ENV 未指定時のデフォルト mask/meta_mode をプロファイルで決定、HAKMEM_TINY_HEAP_BOXも LEGACY 以外なら自動 ON。HAKMEM_TINY_HEAP_CLASSES/HAKMEM_TINY_C7_META_MODEがあればそちらを最優先。- C7_SAFE → class mask=0x80, C7 meta_mode=1(SAFE)、C7_HOT は別途 1。
- C7_ULTRA_BENCH → class mask=0x80, C7 meta_mode=2(bench 専用)。
- LEGACY → TinyHeap 無効。
- ベンチ(20k/ws=64, Release, LARSON_FIX=1):
- C7-only: LEGACY (HEAP_BOX=0, PROFILE=LEGACY, HOT=0) ≈39.4M / PROFILE=C7_SAFE+HOT=1 ≈42.1M / PROFILE=C7_ULTRA_BENCH+HOT=1 ≈48.8M。
- Mixed 16–1024B: PROFILE=LEGACY ≈44.2M / PROFILE=C7_SAFE+HOT=1 ≈42.8M。
- 推奨プロファイル例(現状案):
- 本番寄せ C7:
HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1。 - C7-only bench/mimalloc 比較:
HAKMEM_TINY_HEAP_PROFILE=C7_ULTRA_BENCH HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1。
- 本番寄せ C7:
- 次フェーズの判断メモ: C7_SAFE プリセットは固まったので、次は (A) C6 TinyHeap を SAFE 流に軽量化するか、(B) front/gate の命令数削減を perf で詰めるかの二択で進める。
Phase 16: Front/Gate Flatten(Route Snapshot + Front class stats)
- Route Snapshot Box (
core/box/tiny_route_env_box.h) を追加し、起動時にクラスごとの経路(TinyHeap/Legacy)を LUT に固定。tiny_route_for_class(ci)で hot path の分岐を 1 回に縮約(tiny_route_snapshot_init()は init 時+未初期化時に lazy 呼び出し)。 - Front class 分布カウンタを追加(
HAKMEM_TINY_FRONT_CLASS_STATS[_DUMP]=1)。Mixed 16–1024B/LEGACY では cls2=147/147, cls3=341/341, cls4=720/720, cls5=1420/1420, cls6=2745/2745, cls7 alloc=5692 free=0。C7_SAFE では同配分で cls7 free=4573。 - Gate 再配線:
malloc_tiny_fastは「size→class→route」を 1 回だけ評価し、route=HEAP は TinyHeap 直行、NULL 時のみ Legacy slow へ静かにフォールバック。free_tiny_fastも route LUT ベースで TinyHeap/Legacy を振り分け(Larson fix + TinyHeap free with meta)。 - ベンチ (Release, LARSON_FIX=1, iters=20k):
- C7-only ws=64: LEGACY ≈39.7M / C7_SAFE profile+HOT=1 ≈41.1M / C7_ULTRA_BENCH+HOT=1 ≈46.1M。
- Mixed 16–1024B ws=256: LEGACY ≈42.1M / C7_SAFE profile+HOT=1 ≈39.8M(差を ~-5% まで圧縮)。
- 次フェーズ候補メモ: gate/UC の命令削減を続けるか、C6 TinyHeap を SAFE 流(current 固定+軽量化)に寄せるかを選ぶ段階。
Phase 17: C7 フロント超直線化 (size==1024 専用パイプ)
- Route Snapshot の上に C7 判定ヘルパ
tiny_c7_front_uses_heap()を追加し、Gate から class7 の経路を 1 LUT で取得。 malloc_tiny_fast冒頭に C7 専用パス:size==1024 && tiny_c7_front_uses_heap()のとき class/LUT/route を飛ばしてtiny_c7_alloc_fastに直行、miss 時のみtiny_cold_refill_and_alloc(7)へ静かにフォールバック。他クラスは従来の route LUT 経由。free_tiny_fastも class7 が Heap route なら先に判定し、Larson owner 一致後にtiny_c7_free_fast_with_metaへ直行(route はスナップショットから 1 回だけ読む)。- ベンチ (Release, iters=20k, LARSON_FIX=1, HOT=1):
- C7-only ws=64: PROFILE=LEGACY ≈37.1M / C7_SAFE ≈38.2M / C7_ULTRA_BENCH ≈45.3M ops/s。
- Mixed 16–1024B ws=256: PROFILE=LEGACY ≈40.3M / C7_SAFE ≈40.7M ops/s(回帰を ~-1M まで圧縮)。
- 次ステップ案: (A) C6 TinyHeap を C7 SAFE 流(current 固定+meta-light SAFE)に寄せて再評価するか、(B) Tiny front/gate/UC の命令数削減を perf で詰めるかを選ぶフェーズ。
ホットパス perf フェーズの TODO(案)
- tiny_alloc_fast / tiny_free_fast_v2 の再プロファイル:残存分岐・間接呼び出し・重い箱を特定。
- Unified Cache ヒットパスを最短化:ヒット時を 1–2 load + 軽分岐に近づける(必要なら C7 専用インライン版検討)。
- free パス Gatekeeper/Box の再配線:C7 ホットケースだけ分岐極小のストレートラインにする。
目標: シングルスレッド小オブジェクトで ~50M ops/s → 70M〜80M 帯を狙う(mimalloc との差を半減イメージ)。***
補足(CPU ホットパス観測メモ)
HAKMEM_PROFILE=bench HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2で perf を試行したが、perf_event_paranoid制約でcyclesが取れず page-fault サンプルのみ(__memset_avx2_unaligned_ermsが warmup を支配)。perf.dataは即削除済み。集計結果と次の測定案はdocs/analysis/CPU_HOTPATH_OVERVIEW.mdに記載。- C7 alloc/free flattening と UC ヒット簡略化の設計メモを追加:
docs/analysis/C7_HOTPATH_FLATTENING.md,docs/analysis/C7_FREE_HOTPATH.md。実装はこれから。 - C7 HotBox を追加(
core/box/tiny_c7_hotbox.h+HAKMEM_TINY_C7_HOT)。size==1024 のときだけ C7 専用 TinyHeap に直結し、per-thread ヒープ内の current_page→free_list pop で完結させる経路を用意。ベンチ/IPC 計測は後続。
C7 ホットパス平坦化(第1段階)の結果メモ
HAKMEM_PROFILE=bench HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2、129–1024B ws=256/1M(Release)で:HAKMEM_TINY_C7_HOT=0: ≈49.7M ops/sHAKMEM_TINY_C7_HOT=1: ≈46.7M ops/s(分岐ミスは僅かに改善するがスループットはノイズ〜微減)
- 16–1024B ws=256/1M では:
- hot=0: ops≈47.4M, IPC≈2.13, br-miss≈2.90%
- hot=1: ops≈47.4–47.6M, IPC≈2.16, br-miss≈2.75%
- 現状の C7 ホットパス実装は「ヒット専用 UC + TLS→UC→cold 直線化」の初期版で、大幅な伸びはまだ無い。回帰はなく、分岐ミス率はわずかに改善。今後さらに UC ヒット専用関数の最短化や free 側の直線化を詰める余地あり。
- 方針:
HAKMEM_TINY_C7_HOTは実験用スイッチとして残し、デフォルト OFF。perf フェーズは bench プロファイルで ≈50M ops/s / RSS ≈7MB を維持できる現行経路を基準に一旦完了とする。***
ChatGPT Pro 設計レビュー要約(mimalloc にさらに迫るための方向性)
- 現状:
- bench プロファイル(
HAKMEM_PROFILE=bench)で 16–1024B は ~50M ops/s / RSS≈7MB。mimalloc は ~100–120M ops/s / RSS≈2MB 前後で、性能は 0.4×〜0.5× 程度。 - IPC≈2.1 前後とパイプラインはそれなりに埋まっているが、命令数と多層経路(Gate/Route/TinyFront/UC/Page/Warm/Shared)が支配的。
- bench プロファイル(
- 評価:
- 「今の箱構造のまま小手先だけで 2× 持ち上げるのはほぼ無理」で、Tiny front を mimalloc 風 TinyHeap に寄せる小さめの再設計が必要。
- Superslab/Tier/Guard/Budget/Stats/Remote といった COLD/Safety 層は Box として残し、HOT 側をより薄い TinyHeapBox に集約するのが筋が良い。
- 推奨パターン(案):
- パターン1: Hot TinyHeap vs Cold SafetyBox
- per-thread TinyHeap(heap→page→block)で C0〜C7 の小オブジェクトを mimalloc 風に処理し、Superslab/Shared/Tier/Guard/Budget/Stats/Remote はレアイベント専用の外側の Box として扱う。
- パターン2: Policy Snapshot Box の徹底
_Atomic TinyPolicySnapshotを使い、Hot path はpolicy[cls]を読むだけにし、Learner/ENV 読み・更新は完全に外側の Box に隔離する(現行実装をさらに徹底)。
- パターン3: C7HotBox(C7専用 TinyHeap Box)の本格分離
- size==1024 のみ
C7HotBoxに直行させ、UC/Page/Warm/TLS を C7HotBox 内部で self-contained に扱う。Superslab/Tier/Guard とは「page が尽きる/全 free になる」ときだけ話す。
- size==1024 のみ
- パターン1: Hot TinyHeap vs Cold SafetyBox
- ロードマップ案:
- Phase 1: C7HotBox を本格化し、C7-only ベンチで 50M→70M 付近を狙う(他クラスは従来 TinyFront のまま)。
- Phase 2: UC + Page + Warm を統合した TinyHeapBox を導入し、C5〜C7 を TinyHeap 経由に寄せる(129–1024B/16–1024B で 60–80M を目標)。
- Phase 3: 必要に応じて C0〜C4 も段階的に TinyHeap 側へ移植し、TinyFront は薄いラッパ層に縮退させる。
- 方針メモ:
- Box Theory は維持しつつ、「Hot TinyHeap(シンプル・高速)」と「Cold Superslab/SafetyBox(複雑・安全)」の二層構造に整理することで、mimalloc に近い性能と HAKMEM 固有の安全性・観測性・学習レイヤを両立させる方向性と認識。
Phase33–34: C7 v2 A/B と運用方針固定
- C7 v2 HotHeap(current/freelist を v2、自前 lease は v1)A/B:
- C7-only ws=64 iters=20k PROFILE=C7_SAFE HOT=1 LARSON_FIX=1 HEAP_STATS=ON: v2 OFF 39.42M / v2 ON 43.55M(cls7 fast=11015 slow=1)。
- Mixed 16–1024B ws=256 iters=20k 同条件: v2 OFF 40.44M / v2 ON 36.58M(cls7 fast=5691 slow=1)。混在では回帰。
- 運用方針: v2 は当面 C7-only ベンチ専用(Mixed では v2 OFF 推奨)。C7 SAFE v1 を標準とし、v2 は A/B 実験用。
- v2 stats 追加(ENV
HAKMEM_TINY_HOTHEAP_V2_STATS=1):alloc_calls/alloc_fast/alloc_lease/alloc_fb_v1free_calls/free_fast/free_fb_v1- destructor で
[HOTHEAP_V2_C7_STATS] ...を 1 行 dump。
- Mixed 回帰の切り分け: 上記 stats で「v2 fast/fallback の比率」を取り、枝コストか fallback 多発かを次フェーズで判断する。
Phase35: v2 を封印し、標準を v1+C7_SAFE に固定
- 観測: v2 ON で C7-only/Mixed とも大幅劣化(alloc_fast がほぼ当たらず lease→v1 fallback が支配、HEAP_STATS slow_prepare も爆増)。
- 方針:
- 標準設定は
HAKMEM_TINY_HOTHEAP_V2=0。Mixed では必ず OFF。C7-only でも v2 は明示 ON の研究モード扱い。 - コード上の v2 分岐は
__builtin_expect(..., 0)に寄せ、コメントで「現状は負けている実験箱」だと明示。性能比較や mimalloc 対決では v1+C7_SAFE に集中する。
- 標準設定は
- 次の焦点: v1+C7_SAFE のホットパス薄型化や mid-size 側の改善を優先し、v2 を触るのは「それでも足りない」ときの次善策に回す。
Phase36: C7-only HotHeap v2 を Hot Box 化(lease は v1、Hot 部は自前)
- 変更:
tiny_hotheap_v2_tls_get()で全クラスの storage_page を reset+stride 初期化し、TLS ctx を明示確保。v2 ページ node 取得ヘルパを追加(storage 再利用+不足時は calloc)。- C7 専用の Hot パスを実装:
tiny_hotheap_v2_alloc/freeで current_page→partial→refill の順に処理し、pop/push は lease した v1 page を更新して meta/ss を維持。used==0 は retire_slow 経由でリセット。 - Cold 境界を明示:
tiny_hotheap_v2_refill_slow(tiny_heap_c7_lease_page_for_v2()から 1 枚借りて wrap)とtiny_hotheap_v2_page_retire_slow(lease 情報を返却し reset)が Hot→Cold 唯一の接点。 - Route/Front: route LUT をそのまま使い、C7 直線パスでも route==
TINY_ROUTE_HOTHEAP_V2のときだけ v2 を試すよう整理(free 側も同様)。v2 を外したときの branch コストを最小化。 - v2 stats は現状維持(alloc/free fast/lease/fallback を ENV
HAKMEM_TINY_HOTHEAP_V2_STATSで計測)。
- 状態: v2 は依然 C7-only 実験箱。デフォルト/推奨は
HOTHEAP_V2=0(v1+C7_SAFE)。A/B 計測は未実施(make -j4 成功のみ)。
Phase53: mid/smallmid シングルスレッド基線(v2 OFF, C7_SAFE)
- 条件: threads=1 / cycles=1,000,000 / ws=400 / reps=1。
- スループット: HAKMEM 28.43M ops/s(perf run 29.02M)、mimalloc 54.22M、system 15.29M。
- perf stat (HAKMEM): cycles=211,394,722、instructions=513,342,673 (IPC≈2.43)、task-clock=57.48ms(user 33.29 / sys 25.22)、page-faults=7,374。
- 所感: mid/smallmid では mimalloc が約1.9×。pf は ~7.3k で Tiny よりやや多めだが CPU 命令量と sys 比率が主因。次のターゲット選定用に数字を確定。
Phase54: mid/smallmid CPU ホットパス分析(perf record, userland)
- 条件:
perf record -g -e cycles:u -o perf.data.mid_u ./bench_mid_large_mt_hakmem 1 1000000 400 1(C7_SAFE, v2 OFF)。 - ホットシンボル(self%): hak_pool_try_alloc.part.0=14.7%、worker_run=9.2%、free/hak_free_at≈9–10%、__memset_avx2_unaligned_erms≈9%、mid_desc_lookup=3.8%、hak_super_lookup=1.4%、hak_pool_free≈0.7%。
- 所感: pool allocator と free/memset が支配的。mid_desc_lookup / hak_super_lookup も目立つ。Phase55 ターゲットは pool 系を筆頭候補に。
- ドキュメント: docs/analysis/MID_LARGE_CPU_HOTPATH_ANALYSIS.md に詳細。
Phase55: pool allocator ホットパス軽量化(着手予定)
- スコープ: core/hakmem_pool.c / core/hakmem_smallmid.c / box/pool_* の fast path。
- 方針: hak_pool_try_alloc を「TLS/local freelist 即 return」直線化、debug/stat/slow を unlikely 側に寄せる。self-thread free では pool push を最優先にし、cross-thread/debug は後段に分離。mid_desc_lookup を入口で 1 回だけ決めて TLS にキャッシュする案を検討。
- 成功ライン (bench_mid_large_mt_hakmem 1 1000000 400 1, Release, v2 OFF, C7_SAFE): ops/s を +5〜10%(28–29M→30–32M)改善し、perf self% で hak_pool_try_alloc+free/hak_free_at の合計が数ポイント低下していれば〆とする。
Phase56: pool ホットパス実装の初期薄型化(結果)
- 変更: PoolBlock→user 変換を
hak_pool_block_to_user()にまとめ、TLS fast path/pop と self-thread free の最優先 push を直線化。owner 判定を mid_desc 1 回の lookup に寄せ、同一スレッド free は ring/lo push で即 return。 - ベンチ (C6-heavy: min=257/max=768, ws=256, iters=20k, C7_SAFE, v2 OFF): 25.93M ops/s(従来 28–29M から悪化)。perf stat (1M, ws=400): cycles=225,766,496 / instructions=528,335,613 / task-clock=57.88ms、ops/s=25.71M。
- 所感: fast path整理だけでは効果が出ず回帰。pool self%/memset などが依然重い可能性が高い。次の一手は pool fast pathのさらなる枝削減や memset/desc cache の見直しが必要。
Phase57: pool v2 回帰トリアージ(実装)
HAKMEM_POOL_V2_ENABLEDで旧/新 pool を A/B できる gate を追加(デフォルト 0 = 旧挙動)。細分スイッチとしてHAKMEM_POOL_V2_BLOCK_TO_USER/HAKMEM_POOL_V2_TLS_FAST_PATHを用意(v2時のみ有効)。- v1/v2 の両実装を同居させ、公開 API はラッパでルート切替。mid_lookup も同様に gate。
- ベンチ (C6-heavy, 1M/400, Release):
- v2 OFF (v1): 27.40M ops/s
- v2 ON: 24.73M ops/s
- 所感: 回帰を避けるため標準は v1 を維持しつつ、どの変更が悪かったかをスイッチ単位でA/Bできるようにした。次は各スイッチON/OFFでの差分取り、必要なら v2 を研究箱のまま凍結。
Phase69: PoolHotBox v2 初回 A/B(Cold IF まだダミー)
- 状況: HotBox v2 を posix_memalign/free ベースの Cold IF で通電。Pool v2 は研究箱のまま(デフォルト OFF)。
- ベンチ (Release, min=2048/max=8192, ws=400, iters=100k, C7_SAFE, Tiny v2 OFF):
- v2 OFF: 28.70M ops/s
- v2 ON (classes=0x7F, Cold IF=posix_memalign): 2.15M ops/s
- Stats:
alloc_refill=1630(cls0),alloc_refill_fail=0,free_fb_v1=50437→ page_of/class 判定が合わず v1 free に大量フォールバック。
- 次の一手: Cold IF を v1 pool/Superslab 経路に差し替え、free_fb_v1 の主因(page_of or class 判定)を潰した上で再A/B。研究箱のまま進め、標準は v1 を維持。
Phase70: PoolHotBox v2 Cold IF 切替(進行中)
- 変更: Cold IF を posix_memalign から v1 ベースの mmap/POOL_PAGE_SIZE + mid_desc_register に切り替え、retire も munmap に統一。page_of で class/base 範囲を厳密チェックし、ミスマッチ時は Fail-Fast(v2 内で v1 fallback しない)に変更。free_fb_v1 は front 側のみでカウントする前提に整理。
- ビルド:
make bench_random_mixed_hakmem -j4成功(警告のみ)。 - 次アクション: C6-heavy で v2 OFF/ON を再A/B(POOL_V2_ENABLED=1, CLASSES=C6ビット, POOL_V2_STATS=1)。free_fb_v1 が 0 近傍か、refill/fail が妥当かを確認して Phase69 の回帰を再評価する。
Phase72: PoolHotBox v2 page_of O(1) 化と凍結判断
- 実装・挙動整理:
- PoolHotBox v2 の page_of を 64KiB アラインマスク+ページ先頭ヘッダに埋めた self ポインタで O(1) 化し、retire/初期化時にヘッダを必ずセット/クリアするように変更。ヘッダ領域を除いた容量から freelist を carve するよう capacity 計算も揃えた。
- Cold IF は v1 pool/Superslab ベースの mmap + mid_desc_register / munmap に統一し、HotBox v2 からは geometry/token だけを受け取る構造に整理。
- C6-heavy 短〜中尺(10k〜100k/ws=400, v2 ON, POOL_V2_STATS=1)では page_of_fail_x=0 / free_fb_v1=0 / alloc_refill 十数〜数十回で完走し、構造バグや大量 fallback は解消された。
- 1M 長尺 C6-heavy での結果:
- v2 OFF: ≈27〜30M ops/s で安定完走。
- v2 ON: 120s タイムアウトで完走せず(ハング/極端な遅さ)。page_of_fail は短尺では 0 だが、長尺では v1 比で極端な回帰となる。
- 結論と方針:
- PoolHotBox v2 の箱構造と Cold IF は一通り通電し、研究用には十分な観測性が得られたものの、C6-heavy 長尺での性能回帰が大きく、現フェーズ(Tiny v2 + mid/pool v2)のスコープでは本線候補に持ち上げるのは難しい。
- 本フェーズでは PoolHotBox v2 を 研究箱として凍結 し、標準構成は引き続き
HAKMEM_POOL_V2_ENABLED=0(v1 pool)とする。 - 将来の v3 テーマとして mid/smallmid/pool の Hot/Cold 再設計を行う際に、本フェーズの実装・perf/abort ログを出発点とする。***
Phase Final: 現行デフォルトと研究箱の位置づけ
- 標準構成:
HAKMEM_TINY_HEAP_PROFILE=C7_SAFE,HAKMEM_TINY_HOTHEAP_V2=0,HAKMEM_TINY_STATS_BOX=1,HAKMEM_TINY_STATS_BATCH=0, Pool はHAKMEM_POOL_V2_ENABLED=0。HugePage/ヘッダ light/off はすべて OFF。 - 研究箱:
- TinyHotHeap v2(C7-only): 明示的に
HAKMEM_TINY_HOTHEAP_V2=1のときだけ使用。Mixed では推奨 OFF。 - Pool v2:
HAKMEM_POOL_V2_ENABLED=1を立てたときのみ。標準は v1 で回帰なしを優先。 - HugePage/ヘッダ light/off: first-touch/bench 専用。デフォルトはすべて OFF。
- TinyHotHeap v2(C7-only): 明示的に
- 次フェーズの方向性(v3 テーマの入口):
- TinyHeap v2 を C5–C7 統合 HotHeap として再設計(現行 v2 とは別ライン)。
- first-touch/page-fault 系の本格対応(HugePage/ヘッダ light の昇格可否検証)。
- mid/smallmid の pool/フロント最適化、または mid/large route のさらなるフラット化。
Phase65-c7-v3 short/long A/B(C7-only, Tiny v2/pool v2 OFF)
- 短尺 (20k, ws=64): v3 OFF
41.26Mops/s → v3 ON57.55Mops/s、alloc_refill=49, fb_v1=0, page_of_fail=0(HEAP_STATS slow 未取得だがクラッシュなし)。 - 長尺 (1M, ws=400): v3 OFF
38.26Mops/s → v3 ON50.24Mops/s、alloc_refill=5077, fb_v1=0、クラッシュ/アサートなし。
Phase65-c7-v3 mixed sanity(16–1024B, ws=400, iters=1M, Tiny v2/pool v2 OFF)
- v3 OFF
41.56Mops/s → v3 ON49.40Mops/s、alloc_refill=2446, fb_v1=0、異常なし。 - v3 は依然デフォルト OFF(HAKMEM_SMALL_HEAP_V3_ENABLED=0)。C7-only の研究/bench では
ENABLED=1, CLASSES=0x80で opt-in 可能。
Phase73: Tiny front v3 スナップショット化(Mixed 16–1024B, C7 v3 ON)
- 追加:
HAKMEM_TINY_FRONT_V3_ENABLED(デフォルトOFF)とHAKMEM_TINY_FRONT_V3_STATSENV を追加し、front v3 有効時に- unified_cache_on
- tiny_guard_on
- header_mode
を 1 回だけキャッシュする
TinyFrontV3Snapshotを導入。ホットパスでは snapshot を読むだけにして guard/UC 判定の呼び出しを整理。
- コード影響: malloc/free 両方が snapshot を読んで UC/guard 判定をキャッシュ経由で処理(front v3 OFF のときは従来通り)。
- Mixed 16–1024B (ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF) で A/B: HEAP_STATS slow=1 のまま挙動変化なし(perf は後続フラット化で狙う)。
Phase74: Tiny front v3 size→class LUT 化(挙動維持のまま前段を軽量化)
- ENV:
HAKMEM_TINY_FRONT_V3_LUT_ENABLED(デフォルト OFF、front v3 ON 時だけ有効)。ON 時は Tiny 前段が size→class→route を LUT 1 ルックアップで取得し、従来のhak_tiny_size_to_class+ route 読みを置き換える。 - LUT は起動時に既存の size→class 変換と route スナップショットを写経して構築するため挙動は不変。LUT/Front v3 が無効なときは自動で旧経路にフォールバック。
- A/B (Mixed 16–1024B, 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 相当)で 5〜10% を狙う。
Phase75: Tiny front v3 route fast path(LUT→1 switch)
- ENV:
HAKMEM_TINY_FRONT_V3_ROUTE_FAST_ENABLED(デフォルト OFF)。front v3 + LUT が ON のときだけ、LUT に写した route_kind を直接使いtiny_route_for_class呼び出しを省略する。 - 実装: malloc_tiny_fast の Tiny 前段で size→class→route を LUT 2 バイト load だけで決定し、直後の 1 switch で v3/v2/v1/legacy に分岐。route_fast=0 では Phase74 と同じ経路に自動フォールバック。
- 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 判定の整理など、別軸のフラット化を検討。
Phase76: Tiny front v3 Header v3 (C7-only軽量ヘッダ)
- ENV:
HAKMEM_TINY_HEADER_V3_ENABLED(デフォルト0),HAKMEM_TINY_HEADER_V3_SKIP_C7(デフォルト0)。有効時は C7 v3 alloc だけ tiny_region_id_write_header を通さず 1byte を軽く書いて返す。 - snapshot に header_v3_enabled/skip_c7 を追加(他クラスや v1/v2/pool には無影響、いつでも ENV で OFF)。
- A/B (Mixed 16–1024B, ws=400, iters=1M, C7 v3 ON, 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_v1/page_of_fail=0
- 所感: ヘッダ簡略だけでは perf 改善せず。free 側のヘッダ依存を下げる / header_light 再設計を別フェーズで検討。デフォルトは HEADER_V3=0 のまま。
Phase58: TinyColdIface 導入と C7 v2 Cold 境界接続(WIP / v2 は引き続き研究箱)
- 変更内容(コード側の状態メモ):
core/box/tiny_cold_iface_v1.hにTinyColdIfaceを追加し、v1 TinyHeap のtiny_heap_prepare_page()/tiny_heap_page_becomes_empty()をrefill_page(cold_ctx, class_idx)retire_page(cold_ctx, class_idx, page)の 2 関数にラップ。Hot Box(v2 など)はこの IF 経由でのみ Superslab/Tier/Stats に触れる方針を具体化した。
core/hakmem_tiny.cの C7 v2 実装を更新し、tiny_hotheap_v2_refill_slow()/tiny_hotheap_v2_page_retire_slow()がTinyColdIface経由で v1 TinyHeap に ページ借用・返却を行うよう変更。refill では:cold.refill_page(tiny_heap_ctx_for_thread(), 7)でtiny_heap_page_tを 1 枚取得- v2 側の
tiny_hotheap_page_v2ノードを確保し、base/capacity/slab_idx/metaなどをコピー - v1 ページに freelist が無い場合でも、v2 が
used=0にリセットしてtiny_hotheap_v2_build_freelist()で自前 freelist を構築する - freelist がある場合は
lease_page->meta->freelistを v2 側 freelist で更新 current_pageに必ず freelist/capacity を持つページが入るように Fail-Fast チェックを追加
- TLS 初期化 (
tiny_hotheap_v2_tls_get()) を整理し、クラスごとにstorage_pageをtiny_hotheap_v2_page_reset()でゼロ化しつつstride=tiny_stride_for_class(i)を事前設定。 v2 側の page 構造は常に Hot Box 内で初期化される。 - v2 統計を強化し、
cold_refill_fail/cold_retire_callsなど Cold IF 周辺のカウンタをHAKMEM_TINY_HOTHEAP_V2_STATS=1でダンプ。
- 現状の挙動 / ベンチ:
- C7-only (ws=64, iters=20k,
PROFILE=C7_SAFE, v2 OFF) は依然として ≈42M ops/s,HEAP_STATS[7] fast=11015 slow=1を維持(v1 C7_SAFE は安定)。 - v2 ON では、Cold IF 経由の refill/carve までは進むものの、ウォームアップ直後の
tiny_hotheap_v2_try_pop()付近で SIGSEGV が再現し、ベンチ完走前に落ちる。- 既存ログでは
route_hits/alloc_callsは増えるが、cold_refill_failは 0 近傍まで減少しており、「refill が常に失敗する」状態は解消。 - SEGV は v2
current_page/lease_pageと v1 TinyHeap のtiny_heap_page_pop()/mark_fullの相互作用に起因している可能性が高い。
- 既存ログでは
- C7-only (ws=64, iters=20k,
- 問題の整理(Box Theory 観点):
tiny_hotheap_v2_try_pop()はまだ v1 TinyHeap のtiny_heap_page_pop()/tiny_heap_page_mark_full()を直接呼び出し、v2page->lease_pageのfree_list/usedを v1 関数で更新しつつ- v2 側の
candidate->freelist/usedにもコピーする という二重管理になっている。
- 本来の設計では「Hot Box (v2) は自分の
tiny_hotheap_page_v2.freelistだけを pop/push し、Cold Box とはTinyColdIfaceの refill/retire 境界でのみ接続する」べきであり、 v1 TinyHeap の page/pop ロジックに依存している現状は箱の境界が曖昧になっている。 - その結果として、v1 側の meta/used/freelist と v2 側の freelist/capacity がずれた状態で deref され、SEGV や不整合の温床になっていると考えられる。
- 次の一手(実装担当 AI 向け指示書の要点 / 詳細は
docs/design/TINY_HOTHEAP_V2_IMPLEMENTATION_GUIDE.mdに追記済み想定):tiny_hotheap_v2_try_pop()から v1 TinyHeap 依存を排除し、v2 の freelist だけで pop する直線パスに書き換える。- refill 時に
TinyColdIface.refill_page()から得たtiny_heap_page_tのbase/capacityだけを信頼し、tiny_hotheap_page_v2内で freelist を完全に自前構築する。 - Hot path では
lease_pageを「Cold に返すための token」として保持するだけにし、tiny_heap_page_pop()/mark_full()など v1 の API は呼ばない。
- refill 時に
tiny_hotheap_v2_page_retire_slow()では、page が空になったタイミングでのみTinyColdIface.retire_page(cold_ctx, class_idx, lease_page)を呼ぶようにし、 v2 内部のリスト (current_page/partial_pages/full_pages) から unlink したら Hot 側の state を全て破棄する。TinyColdIfaceを **「refill/retire だけの境界」**として明確化し、Hot Box から Cold Box への侵入(meta/used/freelist の直接操作)をこれ以上増やさない。- C7-only で v2 ON/OFF を A/B しつつ、
cold_refill_failが 0 に張り付いていること、alloc_fast≈ v1 のfast件数に近づいていることを確認する(性能よりもまず安定性・境界の分離を優先)。
Phase ML1: Pool v1 Zero コスト削減(memset 89.73% 軽量化)
背景: C6-heavy(mid/smallmid, Pool v1/flatten 系)ベンチで __memset_avx2_unaligned_erms が self 89.73% を占有(perf 実測)。
実装: ChatGPT により修正完了
core/box/pool_zero_mode_box.h新設(ENV キャッシュ経由で ZERO_MODE を統一管理)core/bench_profile.h: glibc setenv 呼び出しをセグフォから守るため、RTLD_NEXT 経由の malloc+putenv に切り替えcore/hakmem_pool.c: zero mode に応じた memset 制御(FULL/header/off)
A/B テスト結果(C6-heavy, PROFILE=C6_HEAVY_LEGACY_POOLV1, flatten OFF):
| Iterations | ZERO_MODE=full | ZERO_MODE=header | 改善 |
|---|---|---|---|
| 10K | 3.06 M ops/s | 3.17 M ops/s | +3.65% |
| 1M | 23.71 M ops/s | 27.34 M ops/s | +15.34% 🚀 |
所感: イテレーション数が増えると改善率も大きくなる(memset overhead の割合が増加)。header mode で期待値 +3-5% を大幅に超える +15% の改善を実現。デフォルトは ZERO_MODE=full(安全側)のまま、bench/micro-opt 時のみ export HAKMEM_POOL_ZERO_MODE=header で opt-in。
環境変数:
# ベースライン(フル zero)
export HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1
./bench_mid_large_mt_hakmem 1 1000000 400 1
# → 23.71 M ops/s
# 軽量 zero(header + guard のみ)
export HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1
export HAKMEM_POOL_ZERO_MODE=header
./bench_mid_large_mt_hakmem 1 1000000 400 1
# → 27.34 M ops/s (+15.34%)
Phase 82: mid_desc initialization race fix(本線安定化)
課題と分析:
- Phase 82 の full flatten が C7_SAFE モードでクラッシュしていた根本原因:
mid_desc_adopt()が未初期化ミューテックスにアクセス- Race condition: C7_SAFE では TinyHeap ルーティングが限定的なため、Pool が早期に呼ばれる
mid_desc_adopt()の前にmid_desc_init_once()が保証されない
- 修正:
hak_pool_init_impl()冒頭でmid_desc_init_once()を強制実行 → 初期化順序を確定化
ベンチ結果 (C6_HEAVY_LEGACY_POOLV1, Release):
| フェーズ | 10K | 100K | 1M | 備考 |
|---|---|---|---|---|
| Phase 1 (ベースライン) | 3.03M | 14.86M | 26.67M | 最適化なし |
| Phase 2 (Zero Mode) | +5.0% | -2.7% | -0.2% | ML1: 小規模で効果 |
| Phase 3 (Flatten) | +3.7% | +6.1% | -5.0% | 中規模で最適 |
| Phase 4 (Combined) | -5.1% | +8.8% | +2.0% | 最高: 100K で +8.8% |
| Phase 5 (C7_SAFE) | NO CRASH ✅ | NO CRASH ✅ | NO CRASH ✅ | 安全性確保 |
構成別デフォルト (本線):
- C7_SAFE:
POOL_V1_FLATTEN_ENABLED=0,POOL_ZERO_MODE=full(安全側、ベンチ opt-in で切替) - LEGACY: flatten/zero はベンチ専用オプション、デフォルトはいずれも OFF
- mid_desc_init_once(): すべてのモードで初期化保証(クラッシュ防止)
所感: mid_desc 初期化順序の修正は本線として常に有効。Flatten と Zero Mode は箱として組み込まれているが、デフォルト構成ではいずれも OFF。中規模 (100K) ワークロードで Combined が +8.8% 到達、1M 長尺で +2% 程度と、性能ではなく安全性が主要成果。
Phase MD1: mid_desc_lookup TLS キャッシュ(mid/smallmid ベンチ専用)
- 目的: C6-heavy / mid/smallmid で目立つ
mid_desc_lookupself% を TLS キャッシュで 1 回に抑える(サイズ変化で miss → 従来 path)。 - ENV:
HAKMEM_MID_DESC_CACHE_ENABLED=1で opt-in(デフォルト OFF、標準プロファイルは挙動不変)。 - A/B:
HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1, 1M/400, flatten OFF/zero full → OFF: 28.90M ops/s / ON: 29.83M ops/s(約 +3.2%)。C7_SAFE/Mixed は未確認(±数%以内を期待)。- Mixed 16–1024B (
HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE, 1M/400): OFF 44.83M → ON 44.94M(+0.3% 以内、挙動変化なし)。標準 Mixed では推奨は据え置き(mid専用オプション扱い)。
- Mixed 16–1024B (
Phase TG2: tiny_alloc_gate_box 再構成(回帰で廃止)
- 内容: tiny_alloc_gate_box を LUT/route 先頭分岐に寄せる再構成+ malloc_tiny_fast_dispatch の分離を試験。
- 結果: Mixed 16–1024B (MIXED_TINYV3_C7_SAFE, Release) で 約 -14% (44.8M → 38.6M ops/s) の回帰。segv/assert は無し。
- 対応: Phase TG2 変更は破棄済み(tiny_alloc_gate_box / malloc_tiny_fast を元の直線ロジックへ戻した)。今後は gate 全体を触らず、header / classify / ptr fast path など局所削減で攻める方針。