Files
hakmem/CURRENT_TASK.md
2025-12-10 17:58:42 +09:00

1064 lines
119 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## HAKMEM 状況メモ (2025-12-10 更新 / Mixed 基準ライン再固定)
### Phase S-FINAL: Mixed 161024B 現行ベースライン固定C7-only v3 / front v3+LUT+fast classify ON
- ベンチ: `./bench_random_mixed_hakmem 1000000 400 1`1 thread, ws=400, iters=1M, seed=1
- ENV:
- プリセット: `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE`
- bench_profile により自動注入される値:
- `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`C7-only SmallObject v3
- `HAKMEM_POOL_V2_ENABLED=0`
- `HAKMEM_TINY_FRONT_V3_ENABLED=1`
- `HAKMEM_TINY_FRONT_V3_LUT_ENABLED=1`
- `HAKMEM_TINY_PTR_FAST_CLASSIFY_ENABLED=1`
- サイズ範囲: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024`Mixed 161024B 前提。未設定時は既定値を使用)
- その他: `HAKMEM_FREE_POLICY` / `HAKMEM_THP` / stats 系 ENV は未設定(デフォルトのまま)。
- 結果(現 HEAD, Release, ユーザ環境での実測):
- HAKMEM baselineC7 header dedup OFF: **44,384,651 ops/s**
- HAKMEM + `HAKMEM_TINY_C7_HEADER_DEDUP_ENABLED=1`: **44,303,895 ops/s**(約 -0.2%、誤差レンジ内)
- メモ:
- 一時的に同プロファイルで ~36M ops/s まで落ち込んでいたが、Tiny front v3 snapshot の遅延・LUT 判定の整理・C7 ヘッダまわりの配置見直しにより、Mixed 161024B のスループットは **約 44M ops/s レベル** に戻っている。
- C7 ヘッダ再書き込み抑制dedupは ON/OFF いずれもほぼ同等で、現状は安全な実験箱として ENV ゲート付きのまま維持(デフォルトは OFF
- 以降の最適化はこの Phase S-FINAL を基準ラインとして扱い、A/B は必ず `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE` 前提で比較する(過去の別プロファイル・別ビルドの数値とは直接比較しない)。
- Mixed の「健康診断 run」として、少なくとも `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE ./bench_random_mixed_hakmem 1000000 400 1` を 1 本通し、segv/assert なし・スループットが 40〜45M ops/s 程度のレンジに入っていることを確認する(マシン差は許容)。
### Phase FP1: Mixed 161024B madvise A/BC7-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-FastENV `HAKMEM_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`、ENV `HAKMEM_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 v3research / 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 stats `route_hits=266,930 alloc_refill=5 fb_v1=0 page_of_fail=0`C7 は v1 ルート)。
- Mixed 161024B 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/BC6-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 161024B 追加 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-onlymask 0x80のまま。C6 v3 は `HAKMEM_SMALL_HEAP_V3_CLASSES` bit6 で明示 opt-in研究箱。ベンチ時は `HAKMEM_TINY_C6_HOT=1` を併用して tiny front を確実に通す。C6 v3 は現状 C6-heavy/Mixed とも性能マイナスのため、研究箱据え置き。
- 確定: 標準プロファイルは `HAKMEM_SMALL_HEAP_V3_CLASSES=0x80`C7-only v3 固定。bit6C6は研究専用で本線に乗せない。
- 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 161024B 新基準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 flattenC6-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 に分離。ENV `HAKMEM_POOL_V1_FLATTEN_ENABLED`デフォルト0と `HAKMEM_POOL_V1_FLATTEN_STATS` でオンオフと統計を制御。
- A/BC6-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 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 Phase2free_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/CLASSES` gate、route `TINY_ROUTE_SMALL_HEAP_V3`、front の v3 経路fallback 付き)。
- 型/IF: `core/box/smallobject_hotbox_v3_box.h` に so_page/class/ctxstats、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_STATSC7-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 なし。
- 長尺 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 と同等レンジ。
- Mixed 161024B 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`。
- 結論: HEAP_STATS 的にも slow≈1 を維持しつつ、v3 ON は C7-only/Mixed で大きくプラス。デフォルトでは C7-only v3 を ONENV 未指定で ENABLED=1, CLASSES=0x80 相当)としつつ、混乱や回帰時に備えて `SMALL_HEAP_V3_ENABLED=0` / クラスマスクでいつでも v1 に戻せるようにしている。***
### Phase63: C6 v2 A/Bbench専用マスクでの初回計測
- 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 のみ)。
- Mixed 161024B (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=0C6 依然 v1、cls7 refills=2276。
- 所感: C7 v2 は long-run で安定していたが、今回の 1M/400 では refill が 2,276 件まで増えスルーが低下。C6 を v2 に乗せる構成は混在でも回帰が大きく、当面研究箱のままに固定。
### 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=48v2 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/BCold 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 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=1baseline。短尺の 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 161024B 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/BC7-only 研究箱の現状)
- Mixed 161024Bws=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 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 OFFC7_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 161024B (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。
- 所感: slow_prepare は refill 回数と一致し、空ページがほぼ出ないため partial/retire はまだ発火していない。v2 は C7-only/Mixed ともプラスだが、refill=40〜50 が残る。ページ容量/lease 戦略や空ページを作る負荷での検証が次課題。デフォルトは引き続き v2 OFF研究箱扱い
### Phase61: C7 v2 長尺 Mixed (ws=400, iters=1M) 安定性チェック
- プロファイル: Mixed 161024B, 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 161024B, 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 (257768B メイン) のベースラインは **HAKMEM ≈2829M ops/s** に対し mimalloc ≈54M / system ≈15M。Tiny 161024B は ~4142M と比べ、mid/pool 側が大きく劣る。
- ホットスポット: perf では `hak_pool_try_alloc/free`, `memset`, `mid_desc_lookup` が主因。pf/sys は小さく、CPU 側命令数削減がボトルネック。
- 目標: mid/smallmid で +5〜10%2829M → 3032Mをまず達成すること。
- 方針: 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 OFFC7 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 BoxTinyHotHeapBox v2として再定義。Superslab/Tier/Remote/Stats/Learning はすべて外側の Cold Box に落とし、境界を
- alloc 側: `tiny_heap_refill_slow(th, ci)`
- free 側: `tiny_heap_page_retire_slow(th, page)`
の 1 箇所に集約する設計に切り替えた。
- 設計内容: `TinyHeapCtx` / `TinyClassHeap` / `TinyPageMeta` による per-thread TinyHotHeapC5〜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 161024B: HAKMEM ≈41M ops/s / mimalloc ≈113M / system ≈92M → HAKMEM は mimalloc の ~36%、system の ~45%。
- mid/smallmid: HAKMEM ≈2829M / 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 は C5C7 をカバーしつつ、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 → C5C7 への段階的 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 161024B (ws=256, iters=20k): v2 OFF **40.99M ops/s** / v2 ON **32.07M ops/s**`fast=141 slow=16654`)。
- 所感: v2 ON 時に `current_page` がほぼ活きず、C7-only/Mixed とも毎回 `slow_prepare` に落ちて大幅回帰しているcurrent_page stats: `prepare_calls=slow_prepare` で current_null≒0。現状では v2 を運用に使えないため、デフォルトは引き続き v2 OFFC7_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 161024B (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_pagelease_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/BRelease, HEAP_STATS=ON
- C7-only (ws=64, iters=20k): v2 OFF **43.28M**, v2 ON **43.28M**fast=11015 / slow=1 で一致)
- Mixed 161024B (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 TinyHeapmask=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 161024B: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_LARSON_FIX=1` で PROFILE=LEGACY と PROFILE=C7_SAFE を並べて比較。
- C6 の扱いを凍結: C6 TinyHeap/Hot は v1 では bench 専用に留め、v2 で C5C7 をまとめて再設計する前提に移行。
### Phase 27: STATS_BOX / STATS_BATCH A/BC7 SAFE
- C7-only20k/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=2ULTRA bench: **48.55M ops/s**bench 専用)
- Mixed 161024B20k/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` に pendingused/activeと ENV `HAKMEM_TINY_STATS_BATCH` を追加。`tiny_stats_flush_for_page()` は delta を受け取り、バッチ ON なら page pending へ貯め、thresholdcapacity×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 BoxC7 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_hakmem` OK。
- ベンチ (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 161024B:
- 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 SAFEv1/v2のみ。
### 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 回だけ参照)。
- ベンチ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/sHEAP_STATS cls6: fast=5381 slow_prepare=1
- Mixed 161024B:
- 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/sHEAP_STATS cls6: fast=2753 slow=1 / cls7: fast=5682 slow=1
- 所感: フロントを薄くしても C6 TinyHeap は依然マイナスが大きい。C7 SAFE は Mixed でもほぼ誤差わずかプラス。C6 は bench/実験専用マスク0x40/0xC0の位置づけを維持。
### Phase 19: プロファイル固定と次の箱候補
- プロファイルまとめ:
- LEGACY: TinyHeap 全無効基準。Mixed 161024B は ≈44M ops/s 台。
- C7_SAFE: class7 だけ TinyHeap + meta_mode=1。C7-only 20k/ws64 ≈46.6M、Mixed 161024B は LEGACY 比 ±1M 以内軽いマイナス〜誤差。C7-heavy 向け推奨プロファイル。
- C7_ULTRA_BENCH: class7 + meta_mode=2bench 専用、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 161024B: PROFILE=LEGACY と PROFILE=C7_SAFE を並べて比較。C6 を触るときは HEAP_CLASSES を明示し、HEAP_STATS で fast/slow を記録。
- 次に伸ばす箱候補(検討メモのみ):
1. C6 TinyHeap を C7 SAFE 流に本気で攻めるcurrent 固定 + delta/flush の安全版。Superslab/Tier の整合を再チェックしつつ命令削減。
2. 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/sHEAP_STATS=0
- TinyHeap C6 only mask=0x40, META_MODE=0: ≈38.81M ops/scls6 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/scls6 fast=5372/slow=1, cls7 fast=5691/slow=1
- Mixed 161024B (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/scls6 fast=2744/slow=1
- TinyHeap C6 only mask=0x40, META_MODE=1: ≈38.66M ops/scls6 fast=2744/slow=1
- TinyHeap C6+C7 mask=0xC0, C6 META=1 / C7 META=1: ≈39.49M ops/scls6 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 Boxalloc/freeと Tiny Route Box により、USER→BASE 変換と Tiny vs Pool のルーティングを入口 1 箇所に集約。
- Superslab Tier BoxHOT/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 161024B でも TinyHeap OFF ≈46.8M / C7 only (`0x80`) ≈39.4M / C6+C7 (`0xC0`) ≈33.8MTiny lane failed 警告が出る。Gate 側判定の整理が今後の課題)。
- C7 TinyHeap Phase 3stride キャッシュ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=0active/meta の緩和によるベンチ専用モード)。
- 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/sDEBUG/環境の揺れあり)。`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 ループ完走 (≈4246M 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 風 TinyHeapcurrent/partial/full + page 内 freelistを Box 化。TLS `g_tiny_heap_ctx` に全クラスのヒープを保持し、下層 Box との接続は slow 境界 1 箇所に限定。
- C7HotBox は薄いラッパ (`tiny_c7_alloc_fast` / `tiny_c7_free_fast_with_meta` / `tiny_c7_page_of` など) に縮退させ、ENV `HAKMEM_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 までは完走 (≈3444M ops/s) するが、9k 以上で `tls_sll_push_impl` SEGV が再現。valgrind では 10k 完走するため、SLL 周りの防御/初期化順を後続フェーズで要調査。
- C7 HotBox Phase 1.1lookup 削減):
- 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% なので次フェーズで平滑化を続行)。
- C7 HotBoxC7 専用 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 inliningPhase 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` を追加し、
- 8128BTiny-only
- 1291024BTiny C5C7 専用)
を個別に測定可能にした。
- `docs/PERF_ANALYSIS_TINY_MIXED.md` ほかに、8128B/200K/ws=400旧 Tiny 専用)と現在の 161024B/1M/ws=256Tiny+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 BoxC7 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 すべて ONC0〜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、1291024B 50.0M vs 128.4M / 97.7M、full 50.9M vs 123.6M / 83.5M、Tiny-only 8128B 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-onlyWarm から取得した Superslab を TLS Bind Box 経由でバインドする本番経路)
- mode 2: Bind+TLS carveTLS から直接 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 = C5C7, Warm = 全クラスC0C4 cap=4 / C5C7 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 / 1291024B / 161024B で HAKMEM(full/larson_guard) は ~50M ops/s / ~29MB RSS、system は ~9578M ops/s / ~1.6MB RSS、mimalloc は ~74126M ops/s / ~1.8MB RSS。
- SS stats (HAKMEM_SS_STATS_DUMP=1, full profile, 161024B ws=256/1M): live Superslab は C2=1, C7=1empty_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=autoLearner: score=lock*4+miss: 45.6M / 44.6M / 39.7M ops/s平均 ≈ **4345M**)、統計は legacy と同一C7 固定 ON
- guard 比較: full **42.4M ops/s** vs larson_guard **40.7M ops/s**-4%程度で安全側ガードを維持)。
- **1291024B (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 161024B (iters=1M, ws=256)**
- legacy: **51.0M ops/s**。C7 uc_miss=16702/warm_hit=8350/shared_lock=5/tls_carve_success=8350C5/C6 は uc_miss=1〜2
- auto: **50.0M ops/s**C7 固定 ON のまま、他クラスはほぼ動かず)。
- 補足:
- WarmPool-STATS と TinyClassStats を統合。`HAKMEM_WARM_POOL_STATS=1` で C7-only 実行時に hits=3329 / misses=1 / prefilled=1 を確認TinyClassStats の warm_hit=3329 と一致)。
- `TinyClassPolicy` に `tls_carve_enabled` を追加し、デフォルトで C5C7 を ON。`TinyClassStats` に tls_carve_attempt/success を追加済み。
- Learner のスコアを `score = shared_lock * 4 + uc_miss` に変更済みauto プロファイル専用)。現状のワークロードでは C7 が圧倒的に優勢で、C5/C6 はまだほぼ選ばれない。
### サイズ→クラス対応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 → C116B stride
- 16B → C232B
- 32B → C364B
- 64B → C4128B
- 128B → C5256B
- 256B → C6512B
- 512B → C72048B 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 にする。
### 次にやること(広い条件での安定化確認)
1. `HAKMEM_BENCH_MIN_SIZE=129 HAKMEM_BENCH_MAX_SIZE=1024` や通常の `bench_random_mixed_hakmem 1000000 256 42` で
空スラブ限定ガードが副作用なく動くかを継続確認(現状 Release で 2930M ops/s を確認済み)。
2. ドキュメント更新:
- Release だけ C7 Warm が死んでいた根本原因 = 満杯 C7 slab を Shared Pool がリセットせず再供給していた。
- Acquire の空スラブ強制ガードStage3(LRU) 再利用時の Superslab 全スロットリセットWarm/TLS carve 有効化で、
C7-only Release が ~2025M ops/s クラスに回復し、Random Mixed 161024B Release も ~2930M ops/s クラスまで改善した。
3. 次フェーズ案:
- Superslab ガードStats/Reset/Stage3/Budget/larson_guardまで完了。以降は mimalloc/system との比較最適化や、必要に応じた C5/C6 Tiny-Plus 拡張を検討。
### 次フェーズTiny 全クラス向け Page Box / Warm / Policy 汎用化の検討)
- 方向性:
- 現在は C7 向け Tiny-PlusPage Box + Warm Pool + TLS Bindが安定したため、C1〜C7 まで「候補」として広げつつ、
実際にどのクラスで有効化するかは Policy Box学習/ENV側で制御する設計に進める。
- 設計方針(案):
- `TinyClassPolicyBox` を新設し、クラス別ポリシー構造体(`TinyClassPolicy{ page_box_enabled, warm_enabled, warm_cap, ... }`)を配列で保持。
- Hot pathTiny 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 で切替可能にし、デフォルトは FROZENC5C7 のみ Page Box/Warm ON, 他クラス OFF
- 実装ステップ(案):
1. C7 Page Box / Warm / TLS Bind の API を「class_idx を引数に取る汎用形」に整理し、内部で `if (!policy->page_box_enabled) fallback` する形にリファクタ。
2. `TinyClassPolicy` struct と `tiny_policy_get(class_idx)` を導入し、Hot path から直接 `HAKMEM_*` ENV を参照しないようにするPolicy Box 経由に統一)。
3. `TinyClassStatsBox` を追加し、FROZEN/OBSERVE モードで C1〜C7 の stats を集計policy はまだ固定)。
4. `TinyPolicyLearnerBox` を追加し、LEARN モードで stats をもとに `page_box_enabled[]` / `warm_cap[]` を更新(ただし「同時に ON にできるクラス数」に上限を設ける)。
- 進捗メモ(実装済み):
- `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 支配を前提に一旦整理)
- 設計明記: 257512→C6, 5132048→C7size+1 判定)。実負荷は C7 が受ける設計として確定。C5/C6 は拡張枠・観測対象。
- 優先度: C5-only ≈91M ops/s、512B 固定も C7 経路で ≈47M ops/s → C5/C6 最適化は auto/実験用に留め、本命は C7 Tiny-PlusPolicy。
- プロファイル運用: 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_STATSws=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/1291024B/161024B で 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 実容量版での広いワークロード検証: 1291024B ws=256/1M は full=48.9M ops/s & 29.6MB → bench=49.2M & 7.2MB。161024B ws=256/1M は full=48.3M & 29.7MB → bench=48.8M & 7.2MB。SS_STATSbenchでも 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≈同等」まで完了。今後は perfCPUサイクル最適化にフォーカス。
### 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.3Mdelta 残: idx0 used_delta=7669 active_delta=7669 used=6
- 200k: TinyHeap META_LIGHT=1+DELTA_DEBUG ≈48.1Mdelta 残: 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` へ clampc7_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 debugMETA_LIGHT=1 DELTA_DEBUG=1:
- 100k/200k: `[C7_DELTA_SUMMARY] nonzero_pages=0 used_delta_sum=0 active_delta_sum=0`delta 残なし)
### 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/skipC6 も 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 161024B: 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 statsHEAP_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.6MC7_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`。
- 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 161024B (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 2122 (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 前に記録して壊れたページの直前イベントを把握できるようにした。
- 再現状況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 で暫定的に封じ込め。
### 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=1SAFE、C7_HOT は別途 1。
- C7_ULTRA_BENCH → class mask=0x80, C7 meta_mode=2bench 専用)。
- 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 161024B: 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_SAFE プリセットは固まったので、次は (A) C6 TinyHeap を SAFE 流に軽量化するか、(B) front/gate の命令数削減を perf で詰めるかの二択で進める。
### Phase 16: Front/Gate FlattenRoute 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 161024B/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 161024B 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 161024B 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
1. tiny_alloc_fast / tiny_free_fast_v2 の再プロファイル:残存分岐・間接呼び出し・重い箱を特定。
2. Unified Cache ヒットパスを最短化:ヒット時を 12 load + 軽分岐に近づける(必要なら C7 専用インライン版検討)。
3. 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`、1291024B ws=256/1MReleaseで:
- `HAKMEM_TINY_C7_HOT=0`: ≈49.7M ops/s
- `HAKMEM_TINY_C7_HOT=1`: ≈46.7M ops/s分岐ミスは僅かに改善するがスループットはイズ〜微減
- 161024B ws=256/1M では:
- hot=0: ops≈47.4M, IPC≈2.13, br-miss≈2.90%
- hot=1: ops≈47.447.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`)で 161024B は ~50M ops/s / RSS≈7MB。mimalloc は ~100120M ops/s / RSS≈2MB 前後で、性能は 0.4×〜0.5× 程度。
- IPC≈2.1 前後とパイプラインはそれなりに埋まっているが、命令数と多層経路Gate/Route/TinyFront/UC/Page/Warm/Sharedが支配的。
- 評価:
- 「今の箱構造のまま小手先だけで 2× 持ち上げるのはほぼ無理」で、Tiny front を mimalloc 風 TinyHeap に寄せる**小さめの再設計**が必要。
- Superslab/Tier/Guard/Budget/Stats/Remote といった COLD/Safety 層は Box として残し、HOT 側をより薄い TinyHeapBox に集約するのが筋が良い。
- 推奨パターン(案):
- パターン1: **Hot TinyHeap vs Cold SafetyBox**
- per-thread TinyHeapheap→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: **C7HotBoxC7専用 TinyHeap Boxの本格分離**
- size==1024 のみ `C7HotBox` に直行させ、UC/Page/Warm/TLS を C7HotBox 内部で self-contained に扱う。Superslab/Tier/Guard とは「page が尽きる/全 free になる」ときだけ話す。
- ロードマップ案:
1. Phase 1: C7HotBox を本格化し、C7-only ベンチで 50M→70M 付近を狙う(他クラスは従来 TinyFront のまま)。
2. Phase 2: UC + Page + Warm を統合した TinyHeapBox を導入し、C5〜C7 を TinyHeap 経由に寄せる1291024B/161024B で 6080M を目標)。
3. Phase 3: 必要に応じて C0〜C4 も段階的に TinyHeap 側へ移植し、TinyFront は薄いラッパ層に縮退させる。
- 方針メモ:
- Box Theory は維持しつつ、「Hot TinyHeapシンプル・高速」と「Cold Superslab/SafetyBox複雑・安全」の二層構造に整理することで、mimalloc に近い性能と HAKMEM 固有の安全性・観測性・学習レイヤを両立させる方向性と認識。
### Phase3334: C7 v2 A/B と運用方針固定
- C7 v2 HotHeapcurrent/freelist を v2、自前 lease は v1A/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 161024B 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_v1`
- `free_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 を resetstride 初期化し、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.48msuser 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≈910%、__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%2829M→3032M改善し、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**(従来 2829M から悪化。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/BCold 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-Fastv2 内で v1 fallback しないに変更。free_fb_v1 は front 側のみでカウントする前提に整理。
- ビルド: `make bench_random_mixed_hakmem -j4` 成功(警告のみ)。
- 次アクション: C6-heavy で v2 OFF/ON を再A/BPOOL_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 v2C7-only: 明示的に `HAKMEM_TINY_HOTHEAP_V2=1` のときだけ使用。Mixed では推奨 OFF。
- Pool v2: `HAKMEM_POOL_V2_ENABLED=1` を立てたときのみ。標準は v1 で回帰なしを優先。
- HugePage/ヘッダ light/off: first-touch/bench 専用。デフォルトはすべて OFF。
- 次フェーズの方向性v3 テーマの入口):
- TinyHeap v2 を C5C7 統合 HotHeap として再設計(現行 v2 とは別ライン)。
- first-touch/page-fault 系の本格対応HugePage/ヘッダ light の昇格可否検証)。
- mid/smallmid の pool/フロント最適化、または mid/large route のさらなるフラット化。
### Phase65-c7-v3 short/long A/BC7-only, Tiny v2/pool v2 OFF
- 短尺 (20k, ws=64): v3 OFF `41.26M` ops/s → v3 ON `57.55M` ops/s、`alloc_refill=49, fb_v1=0, page_of_fail=0`HEAP_STATS slow 未取得だがクラッシュなし)。
- 長尺 (1M, ws=400): v3 OFF `38.26M` ops/s → v3 ON `50.24M` ops/s、`alloc_refill=5077, fb_v1=0`、クラッシュ/アサートなし。
### Phase65-c7-v3 mixed sanity161024B, ws=400, iters=1M, Tiny v2/pool v2 OFF
- v3 OFF `41.56M` ops/s → v3 ON `49.40M` ops/s、`alloc_refill=2446, fb_v1=0`、異常なし。
- v3 は依然デフォルト OFFHAKMEM_SMALL_HEAP_V3_ENABLED=0。C7-only の研究/bench では `ENABLED=1, CLASSES=0x80` で opt-in 可能。
### Phase73: Tiny front v3 スナップショット化Mixed 161024B, C7 v3 ON
- 追加: `HAKMEM_TINY_FRONT_V3_ENABLED`デフォルトOFFと `HAKMEM_TINY_FRONT_V3_STATS` ENV を追加し、front v3 有効時に
- unified_cache_on
- tiny_guard_on
- header_mode
を 1 回だけキャッシュする `TinyFrontV3Snapshot` を導入。ホットパスでは snapshot を読むだけにして guard/UC 判定の呼び出しを整理。
- コード影響: malloc/free 両方が snapshot を読んで UC/guard 判定をキャッシュ経由で処理front v3 OFF のときは従来通り)。
- Mixed 161024B (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 161024B, 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=2446HEAP_STATS は TinyHeap v1 経路外のため未出力)
- 次: size→class→route 前段のさらなるフラット化Phase2-B 相当)で 5〜10% を狙う。
### Phase75: Tiny front v3 route fast pathLUT→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 161024B, 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 161024B, 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 Boxv2 など)はこの 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` の相互作用に起因している可能性が高い。
- 問題の整理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` に追記済み想定):
1. `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 は呼ばない。
2. `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 を全て破棄する。
3. `TinyColdIface` を **「refill/retire だけの境界」**として明確化し、Hot Box から Cold Box への侵入meta/used/freelist の直接操作)をこれ以上増やさない。
4. C7-only で v2 ON/OFF を A/B しつつ、`cold_refill_fail` が 0 に張り付いていること、`alloc_fast` ≈ v1 の `fast` 件数に近づいていることを確認する(性能よりもまず安定性・境界の分離を優先)。
### Phase ML1: Pool v1 Zero コスト削減memset 89.73% 軽量化)
**背景**: C6-heavymid/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。
**環境変数**:
```bash
# ベースライン(フル zero
export HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1
./bench_mid_large_mt_hakmem 1 1000000 400 1
# → 23.71 M ops/s
# 軽量 zeroheader + 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_lookup` self% を 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 161024B (`HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE`, 1M/400): OFF 44.83M → ON 44.94M+0.3% 以内、挙動変化なし)。標準 Mixed では推奨は据え置きmid専用オプション扱い
### Phase TG2: tiny_alloc_gate_box 再構成(回帰で廃止)
- 内容: tiny_alloc_gate_box を LUT/route 先頭分岐に寄せる再構成+ malloc_tiny_fast_dispatch の分離を試験。
- 結果: Mixed 161024B (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 など局所削減で攻める方針。
### Header Light v3.1C7 header 再書き込み抑制・ベンチ専用)
- ENV: `HAKMEM_TINY_C7_HEADER_DEDUP_ENABLED`(デフォルト 0, C7 v3 ON 時のみ効く)。直前と同一のヘッダなら store をスキップ、free 側の検証は不変。
- A/B (Mixed 161024B, ws=400, iters=1M, MIXED_TINYV3_C7_SAFE): OFF 44.38M ops/s, ON 44.30M ops/s±イズ, 回帰なし)。安全な実験箱として残す(デフォルト OFF
### Phase v4-1: SmallObjectHotBox v4 設計相談ChatGPT Proと次フェーズ方針
- 背景: C7-only SmallObject v3 + Tiny front v3LUT + fast classifyまで積んだ状態でも、Mixed 161024B で mimalloc の 30〜40% 程度。Tiny v2 / Pool v2 / C6 v3 など v2 世代の実験箱は perf 的に NG が多く、small-object heap 全体をもう一段構造から見直す必要が見えてきた。
- 設計相談ChatGPT Proからの提案要約:
- small-object heap v416〜1024B〜2KiBの箱構造:
- HotBox_v4per-thread SmallHeapCtx / SmallClassHeap / SmallPageMeta: current/partial/full を持つ page-based freelist を全 small-object クラスで統一。
- ColdIface_v4: `refill_page` / `retire_page` / `remote_push` / `remote_drain` など少数の境界 API に集約し、内部で Superslab/Warm/Remote を呼ぶ薄いラッパ。
- SuperslabBox/RemoteBox: 既存の Superslab/WarmPool/Remote を Cold 側の Box として再利用Hot から直接は触らない)。
- PolicyBox/LearningBox: small-object 用の `SmallPolicySnapshot` を作り、route_kind/classごとの block_size などを A/B できるようにするHot は snapshot を読むだけ)。
- mimalloc に近づくための「大きい一手」:
1. per-thread small-object heap v4 をきちんと作るC7-only v3 の成功パターンを generalize
2. Segment/Page/Block レイアウトと pf 削減page 配置と WarmPool を v4 用に再チューニング)。
3. front/gate を small-object 用に一段直線化Tiny/front v3 は残しつつ small-object 用 route を V4 vs legacy/pool に収束)。
- v3 の扱い:
- C7-only SmallObject v3 / front v3 は「v4 の prototype」として構造だけ再利用し、HotBox_v4 は基本的に新規設計にする。
- v2 ラッパ系TinyHotHeap v2 など)はインターフェースアイデアだけ残し、実装は archive 的扱いに寄せる。
- 次の実装フェーズv4-1の方針:
- まずは HotBox_v4 / ColdIface_v4 の「型と入口」だけを追加する(挙動は変えない):
- `core/box/smallobject_hotbox_v4_box.h` に `SmallPageMeta` / `SmallClassHeap` / `SmallHeapCtx` の struct 定義と TLS 取得 API 宣言だけ追加。
- `core/box/smallobject_cold_iface_v4.h` に `SmallColdIface` と `refill_page/retire_page` 等のインターフェース宣言だけ用意(中身は後続フェーズ)。
- route 種類として `TINY_ROUTE_SMALLHEAP_V4` を enum に追加し、front v3 の switch に case を足すが、現時点では即 legacy/v3 へフォールバックする stub に留める。
- docs:
- `docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md` を新規追加し、上記の箱構造と Phase v4-1〜v4-4 のロードマップをまとめる。
- 挙動確認:
- コード追加後も `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE` / `C6_HEAVY_LEGACY_POOLV1` の健康診断ランが segv/assert なし・スループットほぼ不変で通ることを確認するv4 はまだ stub のため perf には影響しない前提)。
- 実装メモ (2025-12-10):
- 追加: `core/box/smallobject_hotbox_v4_box.h`, `core/box/smallobject_cold_iface_v4.h`, `docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md`。`tiny_route_env_box.h` に `TINY_ROUTE_SMALLHEAP_V4` を追加し、`malloc_tiny_fast.h` の alloc/free switch に stub case を追加C7 は v3 経由、それ以外は v1 へフォールバック)。
- 健康診断ラン: Mixed 37.16M ops/sMIXED_TINYV3_C7_SAFE, ws=400, iters=1M、C6-heavy 27.62M ops/sC6_HEAVY_LEGACY_POOLV1, ws=400, iters=1M。segv/assert なし。今後の perf 伸びしろは別途追う。
### Phase v4-2: C7-only v4 route (v3 互換挙動、ENV で A/B)
- ENV:
- `HAKMEM_SMALL_HEAP_V4_ENABLED`(デフォルト 0, 研究箱)
- `HAKMEM_SMALL_HEAP_V4_CLASSES`bit7=0x80 を C7 用に使用。v4 と v3 を両方指定した場合は v4 を優先。
- v4 OFF従来 v3: `SMALL_HEAP_V3_ENABLED=1, V3_CLASSES=0x80, V4_ENABLED=0`
- v4 ONC7-only v4: `SMALL_HEAP_V3_ENABLED=0, V3_CLASSES=0, V4_ENABLED=1, V4_CLASSES=0x80`
- 変更点:
- `smallobject_hotbox_v4_env_box.h` を追加(デフォルト OFF
- `smallobject_hotbox_v4.c` を追加し、C7 ルートは v4 → いまは v3 実装に委譲する stub後続フェーズで独立実装予定。TLS ctx (`small_heap_ctx_v4_get`) は stub を返す。
- `tiny_route_env_box.h` で v4 を優先する route snapshot に更新。`malloc_tiny_fast.h` の alloc/free で `TINY_ROUTE_SMALLHEAP_V4` case を追加C7 以外は v1/v3 へフォールバック)。
- 健康診断ランv4 OFF のまま): Mixed 37.16M ops/s、C6-heavy 27.62M ops/ssegv/assert なし)。
### Phase v4-3: C7-only v4 freelist 実装Cold は Tiny v1 経由)
- 変更:
- `smallobject_hotbox_v4.c` に C7 専用の current/partial/full + freelist を実装。page_of はクラス内リスト検索。ColdIface v4 の refill/retire は Tiny v1 (`tiny_heap_prepare_page` / `tiny_heap_page_becomes_empty`) に接続。
- `smallobject_cold_iface_v4.h` を retire(class_idx 付き) に更新。
- `smallobject_hotbox_v4_box.h` に block_size/base を追加。
- route/LUT は v4 を優先するが、v4 が無効なら従来どおり v3/v1。
- A/B (Mixed 161024B, ws=400, iters=1M):
- v3: `V3_ENABLED=1 V3_CLASSES=0x80 V4_ENABLED=0` → 39.23M ops/s
- v4: `V3_ENABLED=0 V3_CLASSES=0 V4_ENABLED=1 V4_CLASSES=0x80` → 38.01M ops/s
- segv/assert なし。v4 は自前実装になったがまだ v3 よりわずかに遅い。次は C7 ページ管理の最適化/pf 改善を検討。
### Phase v4-3.1: C7 v4 の prepare 多発を抑制current/partial 再利用強化)
- 変更:
- `smallobject_hotbox_v4.c` で current/partial を捨てず保持する設計に変更。freelist が空でも current を NULL にせず、slow パスが partial を拾う / 本当に空のときだけ refill。free 側で current が無ければ戻ってきた page を掴み直し、partial_count を持って上限 2 に抑制。
- C7 alloc で `tiny_region_id_write_header` を呼ぶようにして v3 と整合を取った。
- `smallobject_hotbox_v4_box.h` に partial_count を追加。
- A/Bws=400, iters=1M, size=1024 固定, stats ON:
- v3: prepare_calls=5,077, Throughput=41,673,129 ops/s
- v4: prepare_calls=4,701以前 17,191 → 4.7k に減少), Throughput=42,130,607 ops/sv3 比 +1%
- Mixed 161024B (MIXED_TINYV3_C7_SAFE):
- v3 route: 40,661,560 ops/s
- v4 route: 40,010,302 ops/s-1.6% 以内、回帰なし)
- 所感: C7-only では v4 が逆転し、prepare 増加の問題は解消。Mixed も健康レンジに収まった。次は C7 v4 の pf/partial 再利用 or C6/C5 拡張を検討。