Guard madvise ENOMEM and stabilize pool/tiny front v3
This commit is contained in:
@ -73,3 +73,6 @@
|
||||
- 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 が大幅減(≈40k→≈3.4k)。not_mine が顕在化したため、次は owner 判定/自スレ判定の精度を軽く見直す余地がある。デフォルトは引き続き flatten OFF(安全側)で、bench/実験時のみ ON。
|
||||
|
||||
### 安全側の運用メモ
|
||||
- C7_SAFE / C7_ULTRA_BENCH プロファイルと pool v1 flatten の組み合わせではクラッシュ報告があるため、`HAKMEM_TINY_HEAP_PROFILE` がこれらのときは flatten を強制 OFF(ENV を立てても無効化)としている。LEGACY や研究用途でのみ flatten を opt-in する方針。
|
||||
|
||||
@ -27,3 +27,9 @@
|
||||
- 次の選択肢:
|
||||
- mid/smallmid パス(Tiny 以外)のホットパスを狙う箱
|
||||
- もしくは Tiny 側での残り課題と比較して優先度を決める材料に。
|
||||
|
||||
## 2025-12-XX 追記: madvise(ENOMEM) を握りつぶすガードを追加
|
||||
- Superslab OS Box に `ss_os_madvise_guarded()` を導入し、madvise(DONTNEED/POPULATE) が ENOMEM(vm.max_map_count)を返したら
|
||||
`g_ss_madvise_disabled` を立てて以降の madvise をスキップ。EINVAL だけは STRICT=1 で Fail-Fast のまま。
|
||||
- `[SS_OS_STATS]` に `madvise_enomem/madvise_other/madvise_disabled` を追加(`HAKMEM_SS_OS_STATS=1`)。
|
||||
- 目的: ENOMEM 多発で VMA を増やし続けないようにしつつ、アロケータ本体は継続させる。
|
||||
|
||||
@ -17,6 +17,23 @@
|
||||
- 結果: `Throughput = 65979164 ops/s`
|
||||
- 備考: FRONT_CLASS alloc counts(cls2:147, cls3:341, cls4:720, cls5:9857)。HEAP_STATS ダンプは出ず。
|
||||
|
||||
# Phase65 後半: 長尺 v2 ON/OFF A/B(ws=400, iters=1M, PROFILE=C7_SAFE)
|
||||
- 共通 ENV: `HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1 HAKMEM_TINY_HEAP_STATS=1 HAKMEM_TINY_HEAP_STATS_DUMP=1 HAKMEM_TINY_HOTHEAP_V2_STATS=1`
|
||||
## C7-only
|
||||
- v2 OFF (`HOTHEAP_V2=0`): **38.24M ops/s**, HEAP_STATS[7] fast=550099 slow=1。
|
||||
- v2 ON (`HOTHEAP_V2=1`, classes=0x80): **38.68M ops/s**, HEAP_STATS[7] fast=550099 slow=1。v2 stats: refill=1、fail/fallback=0。
|
||||
## Mixed 16–1024B
|
||||
- v2 OFF: **41.78M ops/s**, HEAP_STATS[7] fast=283169 slow=1。
|
||||
- v2 ON: **41.94M ops/s**, HEAP_STATS[7] fast=283169 slow=1。v2 stats: refill=1、fail/fallback=0。
|
||||
- 所感: 長尺では v2 ON/OFF とも slow≈1 に収束し、性能も ±5% 以内(むしろ微プラス)。短尺で見える refill≈50 はウォームアップ由来と判断。
|
||||
|
||||
### Phase65/66 サマリ表(1M / ws=400, PROFILE=C7_SAFE)
|
||||
|
||||
| プロファイル | v2 OFF ops/s | v2 ON ops/s | HEAP_STATS[7] slow | 備考 |
|
||||
|-----------------------|-------------:|------------:|--------------------:|-------------------------|
|
||||
| C7-only (C7-only ベンチ) | 38.24M | 38.68M | 1 | v2 は微プラス・refill=1 |
|
||||
| Mixed 16–1024B | 41.78M | 41.94M | 1 | v2 は微プラス・refill=1 |
|
||||
|
||||
---
|
||||
|
||||
# Phase43 (HEAP_STATS 再有効化の再計測) ※v2 OFF
|
||||
@ -43,6 +60,16 @@
|
||||
### メモ
|
||||
- C7-only では HEAP_STATS/PAGE_STATS が出ることを確認。Mixed/Tiny-only では cls7 以外の HEAP_STATS が落ちておらず、環境/計測対象の条件を再確認する余地あり。
|
||||
|
||||
# Phase63: C6 v2 A/B(C6-heavy / Mixed, C7 SAFE)
|
||||
- 共通 ENV: `HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_HOTHEAP_V2_STATS=1 HAKMEM_TINY_HEAP_STATS=1 HAKMEM_TINY_HEAP_STATS_DUMP=1`
|
||||
## C6-heavy (min=257/max=768, ws=400, iters=1M)
|
||||
- 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。HOTHEAP_V2_STATS cls6 route_hits=0 / free_fb_v1=266930(実質 v1 経路)、fail=0。
|
||||
## Mixed 16–1024B (ws=400, iters=1M)
|
||||
- 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。HOTHEAP_V2_STATS cls6 route_hits=0、cls7 refills=2276。
|
||||
- 所感: C6 v2 は初回 A/B で大幅マイナスかつ v2 ルートが当たっていない。C7 v2 もこのプロファイルでは refill が 2,276 件と多く throughput 低下。v2 は研究箱のまま、デフォルトは v2 OFF。
|
||||
|
||||
# Phase43'': 計測専用で C6/C7 を TinyHeap に載せた場合(v2 OFF)
|
||||
|
||||
## Mixed 16–1024B (ws=256, iters=20000, class mask=0xC0, C6+C7)
|
||||
@ -203,3 +230,45 @@
|
||||
- そのため HugePage ON/OFF で throughput / cycles / page-fault はほぼ同一となり、初期実装の段階では効果は「ゼロに近い」。
|
||||
- 2MB Superslab 専用クラスを設計するか、サイズ条件を緩めて HugePage を実際に使うかを決めないと、Mode A の効果は評価できない。
|
||||
- 一方で pf はすでに ≈6.6k と小さく、たとえ HugePage でさらに削っても全体への寄与は限定的なため、現時点では **CPU ホットパス側の最適化を優先し、HugePage 実験は research-only の位置付けに留める** のが妥当と見える。
|
||||
|
||||
## Phase59: C7 HotHeap v2 Mixed A/B(C7-only route ON/OFF)
|
||||
- プロファイル: `HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1 HAKMEM_TINY_HEAP_STATS=1 HAKMEM_TINY_HEAP_STATS_DUMP=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80`
|
||||
- v2 OFF (`HAKMEM_TINY_HOTHEAP_V2=0`):
|
||||
- Throughput: **45,113,732 ops/s**
|
||||
- HEAP_STATS[7]: fast=5691 slow=1
|
||||
- C7_PAGE_STATS: prepare_calls=1(current を握り続けている)
|
||||
- v2 ON (`HAKMEM_TINY_HOTHEAP_V2=1`, `HAKMEM_TINY_HOTHEAP_V2_STATS=1`):
|
||||
- Throughput: **46,209,226 ops/s**(約 +2.4%)
|
||||
- HEAP_STATS[7]: fast=5692 slow=45
|
||||
- HOTHEAP_V2_C7_STATS: route_hits=5692, alloc_fast=5692, alloc_lease=45 (=refill=45), cold_refill_fail=0, free_fast=4376, page_retired=4, fallback_v1=0
|
||||
- 所感:
|
||||
- Mixed でも v2 ON で微増(+2〜3%)だが、slow_prepare/alloc_lease が 45 と多く、current/partial を使い切る前に refill が走っている可能性がある。
|
||||
- cold_refill_fail/fallback は 0 のため、境界は安定。次は v2 内で空ページを握る/refill の発生頻度を下げる調整が必要。
|
||||
|
||||
## Phase60: C7 HotHeap v2 空ページ保持ポリシー(partial 温存)初期ベンチ
|
||||
- 変更点: `max_partial_pages` を C7 用に 2 へ設定し、free で `used==0` のページは retire せず partial へ温存。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。
|
||||
- メモ: workload が常時多数の live ブロックを持つため page が空にならず、partial_push/retire はまだ発火していない。slow≈refill となっており、ページ容量/同時 live 数が原因と推定。
|
||||
- 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。
|
||||
- 所感:
|
||||
- slow_prepare は「refill したページ数」と一致しており、空ページ保持ポリシーはまだ効く場面に遭遇していない(ページが一度も空にならないワークロード)。
|
||||
- v2 は C7-only/Mixed ともプラスを維持(+20% 近い向上)だが、refill=slow が 40〜50 回発生。partial を効かせるには「空になるページ」が出るプロファイルで検証するか、ページ容量/lease 戦略の見直しが必要。
|
||||
- 備考(容量と live 数):
|
||||
- C7 の page capacity は 32 blocks(約 32KiB)で、ws=64/256/400 の Mixed では常時多数の live ブロックが存在するため、空 page がほぼ発生しない。partial/retire は保険として温存しつつ、現行ベンチでは出番がない前提で扱う。
|
||||
|
||||
## Phase61: C7 v2 長尺 Mixed (ws=400, iters=1M) 安定性確認
|
||||
- プロファイル: Mixed 16–1024B, ws=400, iters=1M, PROFILE=C7_SAFE, C7_HOT=1, v2 classes=0x80, LARSON_FIX=1, STATS_BOX=on, STATS_BATCH=0。
|
||||
- v2 OFF: **41.58M ops/s**。HEAP_STATS[7] fast=283169 slow=1。cold_refill_fail=0, fallback_v1=0。
|
||||
- v2 ON: **42.41M ops/s**(約 +2%)。HEAP_STATS[7] fast=283169 slow=1。v2 stats dumpはなし(fail/fallbackなし)。
|
||||
- 所感:
|
||||
- 長尺でも v2 ON で安定稼働し、+2% 程度の改善を維持。slow_prepare は 1 に張り付き、短尺で見えていた refill 多発は長尺では再現せず。
|
||||
- 引き続き v2 は C7-only の研究箱(デフォルト OFF)のまま、Mixed でも回帰しないことを確認。
|
||||
|
||||
### Phase61’(短尺再確認): Mixed 16–1024B (ws=256, iters=20k)
|
||||
- v2 OFF: **43.27M ops/s**, HEAP_STATS[7] fast=5691 slow=1。
|
||||
- v2 ON (C7-only v2, classes=0x80, v2 stats ON): **44.57M ops/s**(約 +3%)、HEAP_STATS[7] fast=5691 slow=1、cold_refill_fail/fallback=0。C7_PAGE_STATS: prepare_calls=1 で安定。
|
||||
- 所感: 20k/256 でも slow_prepare は 1 に収まり、v2 ON で軽いプラスを維持。長尺と同様に安定。partial/retire ポリシーは依然発火せず(ページが空にならない負荷のため)、本線 Mixed では v2 を研究箱として継続しつつ、さらなる薄型化/slow圧縮を検討。
|
||||
|
||||
89
docs/analysis/POOL_V2_BOX_DESIGN.md
Normal file
89
docs/analysis/POOL_V2_BOX_DESIGN.md
Normal file
@ -0,0 +1,89 @@
|
||||
# POOL_V2_BOX_DESIGN (Phase68)
|
||||
|
||||
目的
|
||||
----
|
||||
- mid/smallmid (257–768B を主軸) のホットパスで pool allocator が支配的なため、TinyHotHeap v2 と同様の「Hot/Cold 分離」を pool にも導入する設計を整理する。
|
||||
- まずは箱構造と境界だけを決め、実装は後続フェーズでゲート付き A/B できるようにする(デフォルトは現行 v1 のまま)。
|
||||
|
||||
箱と境界(方針)
|
||||
-----------------
|
||||
- Hot Box: PoolHotBox v2(per-thread / per-class pool)
|
||||
- 構造: pool_page に `freelist / used / capacity / base`、pool_class に `current_page / partial_pages / full_pages / stride`。
|
||||
- 責務: alloc/free では page 内 freelist pop/push だけを扱う。Stats/学習/OS には触れない。
|
||||
- Cold Box: Superslab/Segment/Tier/Guard/Remote + pool 専用統計
|
||||
- 責務: pool_page の供給・返却、Tier/Guard 判定、OS との境界。
|
||||
- 境界は 2 箇所に集約
|
||||
- alloc 側: `pool_refill_page(class_idx)` … Hot が page を 1 枚借りる
|
||||
- free 側: `pool_page_retire(class_idx, page)` … Hot が empty page を返す
|
||||
|
||||
現行 v1/v2 の棚卸し(箱視点)
|
||||
-----------------------------
|
||||
- v1: 安定線。pool TLS freelist + shared pool を直接操作。perf 上は hak_pool_try_alloc/free, memset が支配的。
|
||||
- v2: Phase55–57 で導入した軽量化パス(TLS fast path 直線化など)だが perf 未達。`HAKMEM_POOL_V2_ENABLED` で研究箱としてゲート。
|
||||
- 共通課題: freelist pop/push と mid_desc_lookup/owner 判定がホットパスに残りすぎている。Cold/OS と混在している。
|
||||
|
||||
設計メモ(次フェーズ実装タスクの種)
|
||||
-----------------------------------
|
||||
- Hot 型
|
||||
- `pool_page_v2`, `pool_class_v2`, `pool_ctx_v2` を TinyHotHeap v2 のミニ版として定義。
|
||||
- TLS で per-thread ctx を保持し、stride/block_size を class 初期化時にセット。
|
||||
- Hot パス
|
||||
- `pool_v2_alloc(class_idx)` / `pool_v2_free(class_idx, ptr)` は current→partial→refill、freelist pop/push だけで完結させる。
|
||||
- Debug/統計/slow パスは unlikely 側に寄せる。
|
||||
- Cold IF
|
||||
- `PoolColdIface` に `refill_page` / `retire_page` を定義。初期実装は既存 pool/superslab の API を薄くラップして流用。
|
||||
- Gate/ENV
|
||||
- `HAKMEM_POOL_V2_ENABLED` / `HAKMEM_POOL_V2_CLASSES`(mask)で v1/v2 を切替。C6-heavy プロファイルから段階的に A/B する前提。
|
||||
|
||||
狙いと目標値
|
||||
------------
|
||||
- スループット目標: mid/smallmid 単体で +5〜10%(28–29M → 30–32M ops/s)をまず狙う。
|
||||
- 命令数削減: hak_pool_try_alloc/free, memset, mid_desc_lookup の self% を数ポイント下げる。
|
||||
- pf/sys は既に小さいため、CPU パスの直線化とキャッシュで効果を出す。
|
||||
|
||||
ガード
|
||||
------
|
||||
- 本ドキュメントは設計のみ。実装はすべて ENV ゲート付きで、デフォルトは v1 挙動を維持すること。
|
||||
- Superslab/OS/Stats/Learning のロジックを変えない(Cold IF で接続するだけ)。***
|
||||
|
||||
Phase69 メモ(初回 A/B と Cold IF 状況)
|
||||
----------------------------------------
|
||||
- HotBox v2 の初実装を通電(freelist/current/partial を v2 内で管理)。Cold IF はまだ posix_memalign/free を使うダミーのまま。
|
||||
- A/B(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、`alloc_refill=1630`, `free_fb_v1` 多数 → page_of 失敗で v1 free に大量フォールバック。
|
||||
- 次の一手:
|
||||
- Cold IF を v1 pool / Superslab 経路に差し替える(posix_memalign ダミーを撤去)。
|
||||
- free_fb_v1 の主因を解消する(page_of か class 判定の欠落)。必要ならヘッダに page token を持たせるなど Hot 側のトラッキングを強化。
|
||||
- A/B は C6-heavy プロファイル(pool が効くサイズ帯)で実施し、性能と stats を CURRENT_TASK.md に積む。
|
||||
|
||||
Phase70 メモ(Cold IF 差し替え・Fail-Fast 強化)
|
||||
----------------------------------------------
|
||||
- Cold IF を v1 ベースの mmap + mid_desc_register に変更し、retire は munmap に統一。HotBox v2 からは geometry/token だけを受け取り、pop/push は v2 freelist だけで完結させる方針に近づけた。
|
||||
- page_of は class/base/offset を厳密チェックし、ミスマッチ時は Fail-Fast(v2 内では v1 fallback しない)。free_fb_v1 は front 側の route ミスマッチ検知専用に狭める前提。
|
||||
- 次ステップ: C6-heavy で v2 OFF/ON を再A/Bし、`alloc_refill_fail==0`, `free_fb_v1≈0` を確認。研究箱のまま、標準は v1 を維持。
|
||||
|
||||
Phase71 メモ(v2 ON で abort, A/B 取れず)
|
||||
----------------------------------------
|
||||
- C6-heavy (min=2048/max=8192, ws=400, iters=1M, PROFILE=C7_SAFE, Tiny v2 OFF, classes=0x7F/0x1, POOL_V2_STATS=1) で v2 ON が起動直後に `hak_pool_free_v2_impl → pool_hotbox_v2_page_of` の Fail-Fast で SIGABRT。短尺 10k でも同様で stats は出ず。
|
||||
- v2 OFF では **30.57M ops/s** を確認。v2 ON はクラッシュのため比較値なし。
|
||||
- 状態: v2 alloc→v1 free 混線 or page_of 範囲判定が未整合。free_fb_v1 は front 側のみでカウントする方針のため、ページ追跡を直さないと A/B が進まない。
|
||||
- 対応方針: route/gate と page_of の整合を再確認し、v2 alloc が NULL を返さないようにするか、front で v1 fallback に落とす。安定するまでは v2 を研究箱(デフォルト OFF)のまま維持。
|
||||
|
||||
Phase72 メモ(page_of O(1) 化と長尺挙動 / 凍結判断)
|
||||
----------------------------------------------------
|
||||
- 実装の進展:
|
||||
- HotBox v2 ページ先頭に self ポインタを埋め、`POOL_PAGE_SIZE` アラインのマスク+ヘッダ読み出しで `pool_hotbox_v2_page_of()` を O(1) 化。
|
||||
- capacity はヘッダ分を差し引いた領域から算出し、freelist はヘッダ直後から carve。retire/初期化時にヘッダを必ずセット/クリア。
|
||||
- Cold IF の mmap を 64KiB アライン取得に揃え、2ページ分の OS 統計だけ積む構造に整理(Superslab 相当の geometry を模倣)。
|
||||
- 短〜中尺の挙動(C6-heavy, v2 ON, POOL_V2_STATS=1):
|
||||
- 10k〜100k/ws=400 では page_of_fail_x=0 / free_fb_v1=0 / alloc_refill 十数〜数十回で完走。構造バグ(page_of/route 混線)は解消。
|
||||
- Throughput は v1 基準より低く、短尺で ~20–25M ops/s 程度(v1≈30M)。オーダーは正しいがオーバーヘッドはまだ大きい。
|
||||
- 長尺 1M/ws=400 の挙動:
|
||||
- v2 OFF: ≈27–30M ops/s で安定完走。
|
||||
- v2 ON: 120s タイムアウトで完走せず(ハング/極端な遅さ)。page_of_fail は短尺では 0 だが、1M 長尺では perf 観点で許容できないレベルの回帰。
|
||||
- 現フェーズの結論:
|
||||
- PoolHotBox v2 の箱構造(page_of O(1)、Cold IF=v1 pool/Superslab)と Fail-Fast/統計まわりは通電し、研究用としては十分な観測性を得られた。
|
||||
- 一方で C6-heavy 長尺での極端な遅さを解消するには、page geometry / current/partial ポリシーや mid/pool 全体の設計をさらに大きく見直す必要があり、現フェーズ(Tiny v2 + mid/pool v2)での対応範囲を超える。
|
||||
- そのため、PoolHotBox v2 は **現行フェーズでは研究箱として凍結** し、運用デフォルトは引き続き `HAKMEM_POOL_V2_ENABLED=0`(v1 pool)のままとする。
|
||||
- mid/smallmid のさらなる最適化(mimalloc 7〜8割到達)を狙う場合は、将来の v3 テーマとして pool/mid の Hot/Cold 再設計を検討する(本ドキュメントはその出発点とする)。***
|
||||
268
docs/analysis/SMALLOBJECT_HOTBOX_V3_DESIGN.md
Normal file
268
docs/analysis/SMALLOBJECT_HOTBOX_V3_DESIGN.md
Normal file
@ -0,0 +1,268 @@
|
||||
SmallObject HotBox v3 Design (Tiny + mid/smallmid 統合案)
|
||||
========================================================
|
||||
|
||||
目的と背景
|
||||
----------
|
||||
- 現状の性能スナップショット:
|
||||
- Mixed 16–1024B (1t, ws=400, iters=1M, PROFILE=C7_SAFE, Tiny v2 OFF):
|
||||
- HAKMEM ≈ 40–50M ops/s
|
||||
- mimalloc ≈ 110–120M ops/s
|
||||
- system ≈ 90M ops/s
|
||||
- mid/smallmid (bench_mid_large_mt, 1t, ws=400, iters=1M):
|
||||
- HAKMEM ≈ 28–29M ops/s
|
||||
- mimalloc ≈ 54M ops/s
|
||||
- system ≈ 15M ops/s
|
||||
- これまでの Tiny/Pool v2 の試行から見えたこと:
|
||||
- C7 v2 (TinyHotHeap v2) は C7-only / Mixed 長尺では v1 C7_SAFE と同等以上まで到達したが、C6/C5 への水平展開や pool v2 は現フェーズでは perf 未達で凍結。
|
||||
- pool v2 は page_of O(1) 化+Cold IF=v1 pool/Superslab まで実装したが、C6-heavy 長尺で極端な遅さが発生し、現行設計のまま押し上げるのは難しい。
|
||||
- 結論:
|
||||
- mimalloc に 7〜8割で迫るには、「Tiny (16〜1KiB) と mid/smallmid の両方」を一体の SmallObject HotBox として設計し直す必要がある。
|
||||
- Superslab/Segment/Tier/Guard/Remote といった Cold/Safety 層は Box として残しつつ、SmallObject 側の Hot Box を 1 枚に集約する方向で v3 を設計する。
|
||||
|
||||
進捗サマリ (Phase A/B 通電)
|
||||
---------------------------
|
||||
- ENV: `HAKMEM_SMALL_HEAP_V3_ENABLED` / `HAKMEM_SMALL_HEAP_V3_CLASSES` を追加(デフォルトは C7-only ON: ENABLED=1, CLASSES=0x80 相当)。
|
||||
- 型/IF: `core/box/smallobject_hotbox_v3_box.h` に so_page/class/ctx と stats を定義。TLS 初期化でクラス別 stride/max_partial をセット。
|
||||
- Cold IF: `smallobject_cold_iface_v1.h` で C7 専用の v1 Tiny ラッパを実装。refill で tiny_heap_prepare_page(7) を借り、retire で tiny_heap_page_becomes_empty に返す。
|
||||
- Hot: `core/smallobject_hotbox_v3.c` で so_alloc/so_free を実装(current/partial freelist を v3 で管理、refill 失敗は v1 fallback)。ページ内 freelist carve は v3 側で実施。
|
||||
- Route: `tiny_route_env_box.h` に `TINY_ROUTE_SMALL_HEAP_V3` を追加。クラスビットが立っているときだけ route snapshot で v3 に振り分け。
|
||||
- Front: malloc/free で v3 route を試し、失敗時は v2/v1/legacy に落とす直線パス。デフォルトは OFF なので挙動は従来通り。
|
||||
|
||||
設計ゴール (SmallObjectHotBox v3)
|
||||
---------------------------------
|
||||
- 対象サイズ帯:
|
||||
- 16〜約 2KiB 程度の「SmallObject」領域(既存 Tiny C0〜C7 + mid/smallmid の一部)。
|
||||
- それより大きいサイズは現行 mid/large ルート(pool v1 / direct mmap)を継続使用。
|
||||
- Box 構造:
|
||||
- Hot Box: `SmallObjectHotBox` (per-thread)
|
||||
- 責務: size→class→page→block のみを扱う。ページ内 freelist pop/push、current/partial 管理。
|
||||
- Tiny v2 / pool v2 で学んだ「page_of O(1)、current/partial/retire ポリシー」を統合。
|
||||
- Cold Box: Superslab/Segment/Tier/Guard/Remote
|
||||
- 責務: Superslab/Segment の割当て・解放、Tier/HOT/DRAINING/FREE 管理、Remote Queue、Guard/Budget。
|
||||
- Hot からは refill/retire の 2 箇所でのみ触れる。
|
||||
- Policy Box: `SmallObjectPolicySnapshot`
|
||||
- 責務: クラスごとの有効/無効、max_partial_pages、warm_cap などのポリシーを `_Atomic` スナップショットで保持。
|
||||
- Hot は snapshot を読むだけ。Learner/ENV は snapshot の更新のみ。
|
||||
- Stats Box / Learning Box:
|
||||
- 責務: page/event 単位の delta を受け取り、Cold 側で集計・観測・学習を行う。
|
||||
- Hot は「page refill/retire 時」「alloc/free のカウンタ更新」以外では触らない。
|
||||
- 境界:
|
||||
- Hot → Cold は 2 箇所に集約:
|
||||
- `so_refill_page(cold_ctx, class_idx)` … SmallObjectHotBox が page を 1 枚借りる。
|
||||
- `so_page_retire(cold_ctx, class_idx, page)` … empty page を Cold 側に返却。
|
||||
- 現行 TinyColdIface / PoolColdIface の経験を活かし、SmallObject 用 Cold IF を 1 枚設計する。
|
||||
|
||||
データ構造案
|
||||
------------
|
||||
|
||||
### Page メタ (`so_page_t`)
|
||||
|
||||
```c
|
||||
typedef struct so_page_t {
|
||||
void* freelist; // ページ内 block 単位の LIFO freelist
|
||||
uint32_t used; // 使用中 block 数
|
||||
uint32_t capacity; // ページ内 block 総数
|
||||
uint16_t class_idx; // SmallObject クラス ID
|
||||
uint16_t flags; // HOT/PARTIAL/FULL などの軽量フラグ
|
||||
uint32_t block_size; // 1 block のバイト数
|
||||
void* base; // ページ base アドレス
|
||||
void* slab_ref; // Superslab/Segment 側 token (Cold Box 用)
|
||||
struct so_page_t* next;
|
||||
} so_page_t;
|
||||
```
|
||||
|
||||
ポイント:
|
||||
- Tiny v2 / pool v2 のページ構造を統一し、「SmallObject 全体で同じ page 型」を使う。
|
||||
- page_of は `POOL_PAGE_SIZE` や Superslab サイズに合わせた mask + header で O(1) を前提とする(pool v2 で得た知見)。
|
||||
|
||||
### クラス状態 (`so_class_t`)
|
||||
|
||||
```c
|
||||
typedef struct so_class_t {
|
||||
so_page_t* current; // ホットページ
|
||||
so_page_t* partial; // 空きありページのリスト
|
||||
uint16_t max_partial; // partial に保持する上限枚数
|
||||
uint16_t partial_count; // 現在の partial 枚数
|
||||
uint32_t block_size; // クラスの block サイズ
|
||||
} so_class_t;
|
||||
```
|
||||
|
||||
- Tiny C7 Safe / TinyHotHeap v2 / pool v2 の current/partial/retire ポリシーを統合。
|
||||
- full リストは v3 初期段階では不要(必要になったら追加)。
|
||||
|
||||
### TLS コンテキスト (`so_ctx_t`)
|
||||
|
||||
```c
|
||||
typedef struct so_ctx_t {
|
||||
so_class_t cls[SMALLOBJECT_NUM_CLASSES];
|
||||
} so_ctx_t;
|
||||
```
|
||||
|
||||
- TLS (`__thread`) で per-thread の SmallObject コンテキストを保持。
|
||||
- 初期化時にクラスごとの `block_size` / `max_partial` / ポリシー値をセットする。
|
||||
|
||||
Cold IF (SmallObjectColdIface) のイメージ
|
||||
----------------------------------------
|
||||
|
||||
```c
|
||||
typedef struct SmallObjectColdIface {
|
||||
so_page_t* (*refill_page)(void* cold_ctx, uint32_t class_idx);
|
||||
void (*retire_page)(void* cold_ctx, uint32_t class_idx, so_page_t* page);
|
||||
} SmallObjectColdIface;
|
||||
```
|
||||
|
||||
- `refill_page`:
|
||||
- Cold Box が Superslab/Segment から SmallObject 用ページを 1 枚切り出し、
|
||||
- `base` / `block_size` / `capacity` / `slab_ref` を設定した `so_page_t` を返す。
|
||||
- v3 では `so_page_t` 自体を Cold 側で確保する案と、Hot 側 node を再利用する案のどちらかを選べるようにしておく。
|
||||
- `retire_page`:
|
||||
- `used==0` のページを Cold Box に返却し、Tier/Guard/Remote の扱いは Cold 側に委譲。
|
||||
- 現行の TinyColdIface / pool Cold IF をラップする形で、SmallObject 用 Cold IF を段階的に導入する。
|
||||
|
||||
Hot パス設計(alloc/free)
|
||||
-------------------------
|
||||
|
||||
### alloc (Hot パス)
|
||||
|
||||
```c
|
||||
void* so_alloc_fast(so_ctx_t* ctx, uint32_t ci) {
|
||||
so_class_t* hc = &ctx->cls[ci];
|
||||
so_page_t* p = hc->current;
|
||||
|
||||
if (likely(p && p->freelist && p->used < p->capacity)) {
|
||||
void* blk = p->freelist;
|
||||
p->freelist = *(void**)blk;
|
||||
p->used++;
|
||||
return blk;
|
||||
}
|
||||
|
||||
if (hc->partial) {
|
||||
p = hc->partial;
|
||||
hc->partial = p->next;
|
||||
p->next = NULL;
|
||||
hc->current = p;
|
||||
if (p->freelist && p->used < p->capacity) {
|
||||
void* blk = p->freelist;
|
||||
p->freelist = *(void**)blk;
|
||||
p->used++;
|
||||
return blk;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // slow_refill へ
|
||||
}
|
||||
```
|
||||
|
||||
- Slow パス (`so_alloc_refill_slow`) では:
|
||||
- `SmallObjectColdIface.refill_page()` で Cold Box からページを 1 枚借りる。
|
||||
- `so_page_t` に geometry を設定し、ページ内 freelist を Hot Box 側で carve。
|
||||
- `hc->current` にセットしてから `so_alloc_fast` で pop。
|
||||
|
||||
### free (Hot パス)
|
||||
|
||||
```c
|
||||
void so_free_fast(so_ctx_t* ctx, uint32_t ci, void* ptr) {
|
||||
so_class_t* hc = &ctx->cls[ci];
|
||||
so_page_t* p = so_page_of(ptr); // O(1) page_of
|
||||
|
||||
*(void**)ptr = p->freelist;
|
||||
p->freelist = ptr;
|
||||
p->used--;
|
||||
|
||||
if (p->used == 0) {
|
||||
if (hc->partial_count < hc->max_partial) {
|
||||
p->next = hc->partial;
|
||||
hc->partial = p;
|
||||
hc->partial_count++;
|
||||
} else {
|
||||
so_page_retire_slow(ctx, ci, p); // Cold IF 経由
|
||||
}
|
||||
if (hc->current == p) hc->current = NULL;
|
||||
} else {
|
||||
if (!hc->current) hc->current = p;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Tiny v2 / pool v2 で使った「空ページ温存 or retire」のポリシーを、クラス別 `max_partial` で制御する。
|
||||
- page_of は pool v2 と同様に O(1) で実装し、Fail-Fast ではなく統計+前段 fallback で診断できるようにする。
|
||||
|
||||
Front/Gate/Route の統合方針
|
||||
--------------------------
|
||||
|
||||
- size→class→route の LUT は既存 TinyRoute Box を流用しつつ、「SmallObjectHotBox v3 対応 route」を追加する。
|
||||
- 例:
|
||||
- `ROUTE_SMALL_HEAP_V3` … SmallObjectHotBox v3。
|
||||
- `ROUTE_TINY_V1` / `ROUTE_POOL_V1` / `ROUTE_LEGACY` … 現行のまま。
|
||||
- PolicySnapshot で:
|
||||
|
||||
```c
|
||||
enum SmallObjectHeapVersion {
|
||||
SO_HEAP_V1 = 0,
|
||||
SO_HEAP_V3 = 1,
|
||||
};
|
||||
|
||||
typedef struct SmallObjectPolicySnapshot {
|
||||
uint8_t heap_version[SMALLOBJECT_NUM_CLASSES]; // V1/V3
|
||||
uint8_t enabled_mask[SMALLOBJECT_NUM_CLASSES]; // クラスごとの ON/OFF
|
||||
uint16_t max_partial[SMALLOBJECT_NUM_CLASSES];
|
||||
} SmallObjectPolicySnapshot;
|
||||
```
|
||||
|
||||
- Front からは:
|
||||
- `class_idx = size_to_smallobject_class(size);`
|
||||
- `route = g_smallobject_route[class_idx];`
|
||||
- `switch (route) { SMALL_HEAP_V3 / TINY_V1 / POOL_V1 / LEGACY }`
|
||||
という 1 LUT + 1 switch で決定。C7 v2 / Tiny v1 / pool v1 など既存経路もここで選べるようにする。
|
||||
|
||||
段階的 rollout 戦略
|
||||
-------------------
|
||||
|
||||
1. Phase A: 設計・骨格導入(bench/実験専用)
|
||||
- `SmallObjectHotBox` 型・SmallObjectColdIface・PolicySnapshot を導入。
|
||||
- まずは Tiny C7-only を SmallObjectHotBox v3 経由に差し替え(現行 C7 v2 を v3 枠に移すイメージ)。
|
||||
- ENV (`HAKMEM_SMALL_HEAP_V3_ENABLED`, `HAKMEM_SMALL_HEAP_V3_CLASSES`) で C7-only を v3 に切り替え可能に。
|
||||
|
||||
2. Phase B: C6/C5 など Tiny クラスを v3 に拡張
|
||||
- C6-heavy / C5-heavy ベンチで C6/C5 を v3 に載せ、v1 vs v3 の perf A/B を取得。
|
||||
- Mixed 16–1024B で C7-only v3 vs C6+C7 v3 を比較。
|
||||
- ここまでは pool v1 をそのまま使い、SmallObjectHotBox v3 側で Tiny 相当をまとめて扱う。
|
||||
|
||||
3. Phase C: mid/smallmid pool を SmallObject に寄せる
|
||||
- mid/smallmid サイズクラスを SmallObjectHotBox v3 のクラスとして増やし、pool v1 経路の一部を v3 に移管する。
|
||||
- Cold IF は Superslab/Segment 共通のまま、SmallObject クラスの範囲だけ v3 で扱う。
|
||||
|
||||
4. Phase D: v1/v2/v3 の役割を整理
|
||||
- v1 TinyHeap / pool v1 は完全な fallback/研究箱とし、標準は SmallObjectHotBox v3 をメインにする。
|
||||
- v2 系(TinyHotHeap v2 / pool v2)は v3 開発の "失敗を記録した箱" として docs/analysis に残す。
|
||||
|
||||
非ゴール(この設計フェーズでやらないこと)
|
||||
-----------------------------------------
|
||||
- Superslab/Segment/Tier/Guard/Remote のフル再設計(Segment サイズや Tier ポリシー変更など)は v3 後半〜v4 テーマとする。
|
||||
- first-touch/pf/HugePage/NUMA 最適化は SmallObjectHotBox v3 の上に乗る別箱として扱い、この設計では触らない。
|
||||
- 学習層 (ACE/ELO) の仕様変更は行わず、PolicySnapshot の更新だけを学習側が持ち、Hot パスは snapshot を読むだけにする。
|
||||
|
||||
まとめ
|
||||
------
|
||||
- SmallObjectHotBox v3 は、TinyHotHeap v2 / pool v2 で得た知見を統合し、「SmallObject 全体を 1 枚の Hot Box」として扱う設計。
|
||||
- Hot Box と Cold Box の境界を 2 箇所(refill/retire)に絞り、Policy/Stats/Learning を別箱に押し出すことで、Box Theory に沿った形で mimalloc に近い構造を目指す。
|
||||
- 実装は `docs/design/SMALLOBJECT_HOTBOX_V3_IMPLEMENTATION_GUIDE.md` に従って段階的に行い、常に v1/v2 への rollback path を維持する。
|
||||
|
||||
## Phase65 簡易ベンチメモ(C7-only v3, Tiny/Pool v2 OFF)
|
||||
- 短尺 20k/ws=64: v3 OFF 41.26M ops/s → v3 ON 57.55M ops/s(alloc_refill=49, fallback_v1=0, page_of_fail=0)。
|
||||
- 長尺 1M/ws=400: v3 OFF 38.26M ops/s → v3 ON 50.24M ops/s(alloc_refill=5077, fallback_v1=0)。
|
||||
- Mixed 16–1024B 1M/ws=400: v3 OFF 41.56M ops/s → v3 ON 49.40M ops/s(alloc_refill=2446, fallback_v1=0)。
|
||||
- デフォルトは C7-only ON (`HAKMEM_SMALL_HEAP_V3_ENABLED` 未指定 / `HAKMEM_SMALL_HEAP_V3_CLASSES` 未指定で class7 のみ v3)。明示的に `ENABLED=0` または CLASSES から bit7 を外すことで v1 経路に戻せる。
|
||||
|
||||
## Phase65-HEAP_STATS 追加観測(C7-only v3 A/B, Tiny/Pool v2 OFF)
|
||||
- 短尺 20k/ws=64:
|
||||
- v3 OFF: 40.91M ops/s, `HEAP_STATS[7] fast=11015 slow=1`。
|
||||
- v3 ON: 56.43M ops/s, v3 stats `alloc_refill=49 fb_v1=0 page_of_fail=0`(短尺ウォームアップ由来の refill)。HEAP_STATS は Tiny v1 経路のみ出力。
|
||||
- 長尺 1M/ws=400:
|
||||
- v3 OFF: 38.29M ops/s, `HEAP_STATS[7] fast=550099 slow=1`。
|
||||
- v3 ON: 50.25M ops/s, v3 stats `alloc_refill=5077 fb_v1=0 page_of_fail=0`。
|
||||
- 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`)。
|
||||
- まとめ: HEAP_STATS で slow≈1 を維持したまま v3 ON は C7-only/Mixed とも大幅プラス。デフォルトでは C7-only v3 を ON(ENABLED=1, CLASSES デフォルト=0x80)としつつ、混乱を避けるため `HAKMEM_SMALL_HEAP_V3_ENABLED=0` / クラスマスクでいつでも v1 に戻せるようにしている。***
|
||||
***
|
||||
@ -32,3 +32,53 @@
|
||||
- pop/empty 内の分岐を整理し、C7 SAFE の理想パス(current_page固定)に寄せる。
|
||||
- header write / memset を最小化する実験スイッチを検討。
|
||||
|
||||
## C7 v3 ON, Mixed 16–1024B (ws=400, iters=1,000,000, userland cycles)
|
||||
|
||||
環境: `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_POOL_V2_ENABLED=0 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80`
|
||||
|
||||
- Throughput: **48.96M ops/s**(前回 v3 ON と同レンジ)
|
||||
- perf record `cycles:u` (171 samples, release build without symbols):
|
||||
- 上位は `free` / `malloc` / `main` の無名フレームに潰れてしまい、非C7 Tiny front の細かい関数名が出ず。
|
||||
- シンボル再取得には DEBUG/記号付きビルドで perf し直す必要あり。
|
||||
- 所感: C7 v3 以外のホットパス特定には、size→class→route 前段や unified cache hit パスを再シンボル化して見る必要がある。現状のバイナリでは細部が見えない。
|
||||
|
||||
## Mixed 16–1024B (ws=400, iters=1,000,000, userland cycles, C7 v3 ON, DEBUGビルド)
|
||||
|
||||
環境: `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_POOL_V2_ENABLED=0 HAKMEM_SMALL_HEAP_V3_ENABLED=1 HAKMEM_SMALL_HEAP_V3_CLASSES=0x80`
|
||||
ビルド: `make clean && CFLAGS='-O2 -g …' USE_LTO=0 OPT_LEVEL=2 NATIVE=0 make bench_random_mixed_hakmem`
|
||||
|
||||
- Throughput: **46.1–46.3M ops/s**(リリース時の ~49M よりやや低いが符号付きビルドで許容)
|
||||
- perf record `cycles:u -F5000 --call-graph dwarf` (200 samples) の self% 上位(C7 v3 以外を抜粋):
|
||||
- free 23.5%, malloc 18.8%, main 13.7%(ベンチハーネス由来)
|
||||
- **tiny_region_id_write_header 6.7%**
|
||||
- **ss_map_lookup 3.6%**
|
||||
- unified_cache_enabled 2.8%
|
||||
- tiny_guard_is_enabled 2.2%
|
||||
- classify_ptr 1.4%(size→class 判定系)
|
||||
- mid_desc_lookup 1.3%
|
||||
- hak_free_at 0.9%, hak_pool_mid_lookup 0.7%
|
||||
- so_alloc/so_free 合計 ~7%(C7 v3 本体)
|
||||
- 所感(非C7 Tiny front 目線):
|
||||
- header 書き込み(tiny_region_id_write_header)が依然目立つ。
|
||||
- Superslab 判定前の `ss_map_lookup` が 3–4% 程度残っている。
|
||||
- route/guard 判定(unified_cache_enabled / tiny_guard_is_enabled / classify_ptr)が合わせて ~6% 程度。
|
||||
- 次は「size→class→route 前段+header」をフラット化するターゲットが有力。
|
||||
|
||||
### Front v3 snapshot 導入メモ
|
||||
- `TinyFrontV3Snapshot` を追加し、`unified_cache_on / tiny_guard_on / header_mode` を 1 回だけキャッシュする経路を front v3 ON 時に通すようにした(デフォルト OFF)。
|
||||
- Mixed 16–1024B (ws=400, iters=1M, C7 v3 ON, Tiny/Pool v2 OFF) で挙動変化なし(slow=1 維持)。ホットスポットは依然 front 前段 (`tiny_region_id_write_header`, `ss_map_lookup`, guard/route 判定) が中心。
|
||||
|
||||
### Front v3 size→class LUT メモ(Phase2-A 実装済み、A/B これから)
|
||||
- ENV `HAKMEM_TINY_FRONT_V3_LUT_ENABLED` を追加(デフォルト OFF)。front v3 ON 時に size→class→route を Tiny 専用 LUT から 1 ルックアップで取得し、従来の `hak_tiny_size_to_class` + route 読みを代替する。
|
||||
- LUT は起動時に既存の size→class 変換と route スナップショットをそのまま写経して構築するため挙動は変えない。
|
||||
- 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%)
|
||||
- HEAP_STATS は TinyHeap v1 経路外のため出力なし。C7_PAGE_STATS は prepare_calls=2446 で変化なし。
|
||||
|
||||
### Header v3 (C7-only) 簡易スキップ実験
|
||||
- ENV: `HAKMEM_TINY_HEADER_V3_ENABLED` / `HAKMEM_TINY_HEADER_V3_SKIP_C7` を追加。C7 v3 alloc 時だけ tiny_region_id_write_header を通さず 1byte store にする。
|
||||
- Mixed 16–1024B (ws=400, iters=1M, 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/page_of_fail=0
|
||||
- 所感: C7 v3 のヘッダ簡略だけでは perf 改善は見えず。free 側のヘッダ依存を落とす or header light/off を別箱で検討する必要あり。
|
||||
|
||||
@ -6,6 +6,31 @@ TinyHeap v2 Design (入口メモ)
|
||||
- C7 専用で「1 枚 lease + current/freelist を v2 で握る」状態。ページ供給・meta/ss_active/Remote/Stats はすべて v1 TinyHeap/C7 SAFE に委譲。
|
||||
- A/B でいつでも v1 に戻せる(`HAKMEM_TINY_HOTHEAP_V2` / `HAKMEM_TINY_HOTHEAP_CLASSES`)。性能はまだ v1 と同等を維持するのが目的。
|
||||
|
||||
現状評価サマリ (Phase66 時点)
|
||||
----------------------------
|
||||
- C7 v2:
|
||||
- C7-only / Mixed 16–1024B の長尺プロファイル(ws=400, iters=1M, PROFILE=C7_SAFE)では、v2 ON/OFF いずれも `HEAP_STATS[7].slow≈1`・refill≈1 に収束し、性能も v1 比で ±5% 以内(むしろ数%プラス)。
|
||||
- 短尺(20k/ws=64)の refill≒50 はウォームアップ由来であり、本命プロファイルには影響しないことを確認。
|
||||
- デフォルト構成では `HAKMEM_TINY_HOTHEAP_V2=0` を維持しつつ、C7-only の bench/pro 用プロファイルでは `HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を opt-in 推奨とする。本線候補としては「C7 SAFE v1/v2 並列」の状態。
|
||||
- C6 v2:
|
||||
- route/gate 修正後も C6-heavy / Mixed で大幅な回帰が残っており、C6-only v2 ON は v1 より明確に遅い。
|
||||
- 現状は構造レベルでは通電しているが perf 未達のため、「研究箱」として `HAKMEM_TINY_HOTHEAP_CLASSES=0x40/0xC0` を明示したときだけ有効にし、標準プロファイルでは必ず OFF にする。
|
||||
|
||||
Phase63: C6 v2 を opt-in で拡張(ベンチ結果は要改善)
|
||||
-----------------------------------------------
|
||||
- 実装: v2 Hot Box を class_idx パラメータ化し、C6 も `HAKMEM_TINY_HOTHEAP_CLASSES` の bit6 で有効化可能にした。stats もクラス配列化し、C6/C7 両方で route_hits / refill / fallback を追跡。TLS 初期化で C6 も stride と max_partial_pages=2 を設定。
|
||||
- ベンチ結果(Release, 1M/400, PROFILE=C7_SAFE, C7_HOT=1, v2 stats ON):
|
||||
- C6-heavy min=257/max=768: v2 OFF **42.15M ops/s**、v2 ON(0x40) **29.69M ops/s**。v2 stats cls6 route_hits=0 / free_fb_v1=266930 で実質 v1 経路に落ちており、大幅回帰。
|
||||
- Mixed 16–1024B: C7 v2 only (0x80) **45.07M ops/s** かつ cls7 slow_prepare=2276。C6+C7 v2 (0xC0) **35.65M ops/s** まで悪化、cls6 は v1 のまま(route_hits=0)。
|
||||
- 結論: C6 v2 は初回 A/B で大幅マイナスかつ C6 ルートが実際には v2 を踏んでいない。デフォルトは v2 OFF のまま。C6 v2 は研究箱扱いを継続し、route LUT/冷温境界の見直し・refill 多発の是正が必要。
|
||||
|
||||
Phase64: C6 v2 route 修正・C7 v2 refill 再確認
|
||||
---------------------------------------------
|
||||
- front の route switch をクラス汎用にし、class6 でも `TINY_ROUTE_HOTHEAP_V2` を通るよう修正。v2 stats に route 値を表示。
|
||||
- C6-heavy (min=257/max=768, ws=400, iters=100k, classes=0x40): route_hits=26660, alloc_refill=1, fallback_v1=0 → v2 パスが有効化。ただしスループットは **35.5M ops/s** と v1 より低めで要チューニング。
|
||||
- C7-only 20k/ws=64 v2 ON: alloc_refill=48 / HEAP_STATS slow=48(v2 OFF は slow=1)。Mixed 20k/ws=256 でも refills≈42。短尺では refill 多発が残るため原因再調査中。長尺 1M/ws=400 では slow=1 のまま。
|
||||
- `refill_with_current` / `refill_with_partial` のカウンタを追加し、短尺では current/partial が空の状態で refill が発生していることを確認(partial/retire は未発火)。当面の運用: デフォルトは v2 OFF。C6 v2 は opt-in 研究箱、C7 v2 は bench/研究プロファイルのみ。
|
||||
|
||||
Phase33: C7 v2 ON/OFF A/B(現状評価)
|
||||
-----------------------------------
|
||||
- 条件: C7 SAFE (`PROFILE=C7_SAFE HAKMEM_TINY_C7_HOT=1 HAKMEM_TINY_LARSON_FIX=1`), class mask 0x80, HEAP_STATS=ON。
|
||||
@ -333,3 +358,109 @@ Phase36 (C7-only Hot Box 暫定実装)
|
||||
- Cold 境界: `tiny_hotheap_v2_refill_slow`(`tiny_heap_c7_lease_page_for_v2()` 経由で 1 枚借りる)と `tiny_hotheap_v2_page_retire_slow`(返却+reset)の 2 箇所のみ。Superslab/Tier/Stats は v1 が保持。
|
||||
- Route/Gate: Route Snapshot に `TINY_ROUTE_HOTHEAP_V2` を設定し、C7 直線パス/汎用パスとも route==v2 のときだけ HotHeap v2 を呼ぶ。その他は v1 → legacy slow へフォールバック。
|
||||
- 今後: v2 は C7-only bench 用の A/B 前提。Mixed では v2 OFF 推奨。より本格的に進めるなら、v1 依存の lease/pop/push を減らし、Cold Stats Box 経由の更新に寄せる必要がある。
|
||||
|
||||
ChatGPT Pro からのフィードバックと v2 ロードマップ
|
||||
-----------------------------------------------
|
||||
|
||||
ChatGPT Pro との設計相談の結果、TinyHeap v2 について以下の整理とロードマップを追加する。
|
||||
|
||||
### 1. どこを優先して変えるべきか
|
||||
|
||||
- Mixed 16–1024B の現状:
|
||||
- HAKMEM ≈ 41M ops/s
|
||||
- mimalloc ≈ 113M ops/s(≒ 2.7–2.8×)
|
||||
- system ≈ 92M ops/s
|
||||
- mid/smallmid:
|
||||
- HAKMEM ≈ 28–29M / mimalloc ≈ 54M / system ≈ 15M
|
||||
- Superslab/OS:
|
||||
- 1M ops あたりの Superslab OS 呼び出しは数回(`alloc≈2, free≈3, madvise≈2`)。
|
||||
- page-fault ≈ 6.6k/1M ops はほぼ first-write 起因と推定。
|
||||
|
||||
この状態から 70–80M (mimalloc の 60–70%) を目指すなら、優先度は:
|
||||
|
||||
1. TinyHeap v2 を **v1 への依存がない本物の Hot Box** として再設計する(A案の強化)
|
||||
2. mid/smallmid/pool v2 はその次の波で攻める(現状でも system より速い)
|
||||
3. pf/first-touch/HugePage は v3 以降の「最後の 5〜10% を詰める」テーマ
|
||||
|
||||
### 2. v1 の上にラッパを乗せるのはやめる
|
||||
|
||||
Phase32–35 の v2 は「v1 の page を lease+pop/push するラッパ」であり、結果として:
|
||||
- v2 → lease → v1 `tiny_heap_prepare_page` / slow_prepare に落ちる構造
|
||||
- Mixed で slow_prepare が爆増し、v1 より遅くなるケースが多かった
|
||||
|
||||
今後の方針:
|
||||
- v2 は **「v1 の上に座るラッパ」ではなく、v1 と并列の Hot Box** として扱う。
|
||||
- Superslab/Tier/Guard/Stats/Learning とは v1/v2 共通の Cold iface を介して話し、v2 から v1 の内部関数を直接叩かない。
|
||||
|
||||
### 3. v1/v2 共通の Cold インタフェース (TinyColdIface) の導入
|
||||
|
||||
v1 TinyHeapBox / v2 TinyHotHeapBox の両方が、同じ Cold Box 群(Superslab/Tier/Guard/Stats/Learning)と話すための共通 IF を導入する。
|
||||
|
||||
```c
|
||||
// Hot → Cold (共通インタフェースのイメージ)
|
||||
typedef struct TinyColdIface {
|
||||
TinyPageMeta* (*refill_page)(void* cold_ctx, uint32_t class_idx);
|
||||
void (*retire_page)(void* cold_ctx, TinyPageMeta* page);
|
||||
} TinyColdIface;
|
||||
```
|
||||
|
||||
- v1:
|
||||
- 既存 TinyHeapBox の refill/empty 経路を `TinyColdIface` に束ねる。
|
||||
- v2:
|
||||
- Hot Box からは `TinyColdIface` 経由で Superslab/Warm/Tier/Stats に触れる。
|
||||
|
||||
Cold 側(Superslab/Tier/Guard/Stats)は、「呼び出し元が v1 か v2 か」を意識せずに済む。
|
||||
|
||||
### 4. v1/v2 並立構成(Hot Box の二系統)
|
||||
|
||||
Box 構造のイメージ:
|
||||
|
||||
```text
|
||||
[Front/Gate Box]
|
||||
|
|
||||
+-- if tiny_heap_version[class] == V1 ----> [TinyHeapBox v1]
|
||||
|
|
||||
+-- if tiny_heap_version[class] == V2 ----> [TinyHotHeapBox v2]
|
||||
|
|
||||
v
|
||||
[ColdSuperslab/Tier/Stats/Remote/Guard Box]
|
||||
```
|
||||
|
||||
- Front/Gate は `size → class → route` まで決め、その後 `tiny_heap_version[class_idx]` で v1/v2 を選ぶ。
|
||||
- v1/v2 とも Cold Box とは `TinyColdIface` だけを使う。
|
||||
- v1 は「安定線/safe path」、v2 は「新 Hot Box」として A/B 可能。
|
||||
|
||||
### 5. v2 の適用範囲と rollout 方針
|
||||
|
||||
- 設計は最初から C5–C7 をカバーできるようにする(`TinyHotHeapCtxV2.cls[0..7]` を持つ)。
|
||||
- rollout は **C7-only → C6 → C5** の順で段階的に:
|
||||
- PolicySnapshotBox に `tiny_heap_version[class_idx]` を追加(V1/V2)。
|
||||
- 初期値は `C7 = V1`, C5–C6 も V1。
|
||||
- bench/分析で v2(C7-only) が安定・同等以上になった段階で `C7=V2` に昇格。
|
||||
- Mixed で問題なければ C6/C5 を順に昇格。
|
||||
- v1 は常に fallback として残し、`HAKMEM_TINY_HEAP_PROFILE=LEGACY` や専用 ENV で「全クラス v1」に戻せるようにする。
|
||||
- Phase62 実装メモ:
|
||||
- C7 v2 に加えて C6 v2 を同じ Hot Box で扱えるようにした(Route mask bit6/0x40 で opt-in、デフォルト OFF)。
|
||||
- Cold IF は v1 をそのままラップする形で、C6/C7 どちらも refill/retire の 2 箇所のみで Superslab/Tier/Stats に触れる。
|
||||
- ステータス: C7 v2 は Mixed/C7-only で微プラス安定。C6 v2 は実装済みだが bench はこれから(bench専用・デフォルトは v1)。
|
||||
|
||||
### 6. v2 のスコープと v3 の線引き
|
||||
|
||||
- v2 世代でやること:
|
||||
- Tiny front/route Box → すでに 1 LUT + 1 switch に整理済み。
|
||||
- TinyHotHeap v2 を **v1 と并列の Hot Box** として実装し、C5–C7 を段階的に移行。
|
||||
- mid/smallmid/pool は v1 を維持しつつ、v2 の構造スケッチ(page-based pool 等)まで設計しておく。
|
||||
- Superslab/Segment/Tier/Guard/Remote の構造は **変えない**(Cold Box を動かさない)。
|
||||
- v3 以降でやること:
|
||||
- Superslab/Segment のサイズ・配置・Tier 設計を再定義。
|
||||
- Tiny と mid/pool を統合した SmallObjectHeap を設計(サイズクラス統合など)。
|
||||
- Remote/cross-thread free の方式(リモートリスト vs メッセージ vs per-CPU)を見直す。
|
||||
- HugePage/NUMA/first-touch 最適化を本格的に取り入れる。
|
||||
|
||||
まとめると:
|
||||
- v2 は「Hot Box(TinyHeap v2)を作り直し、Cold Box はほぼ据え置き」の世代。
|
||||
- v3 は「Cold Box(Superslab/Segment/Tier)も含めてオブジェクト heap 全体を再構成する」世代。
|
||||
|
||||
### 7. Phase65 後半の観測(C7 v2 長尺)
|
||||
- C7-only / Mixed (ws=400, iters=1M) で v2 ON/OFF を再取得したところ、どちらも `slow≈1 / refill≈1` に収束し、性能も v2 ON が微プラス(C7-only 38.68M vs OFF 38.24M、Mixed 41.94M vs 41.78M)。
|
||||
- 短尺 20k で見える refill≈50 はウォームアップ由来と判断。運用デフォルトは v2 OFF のまま(研究箱扱い)だが、bench では C7 v2 を本命候補として扱える状態。
|
||||
|
||||
@ -44,3 +44,34 @@ Tiny Next Steps (Phase 19 メモ)
|
||||
- HotHeap v2 (C7 専用) の扱い:
|
||||
- 現状は C7-only でも v1 より遅く、Mixed では大きく回帰。標準は `HAKMEM_TINY_HOTHEAP_V2=0`(v1 C7_SAFE を使用)。
|
||||
- 研究/実験で使う場合のみ `HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を明示し、`HAKMEM_TINY_HOTHEAP_V2_STATS=1` で fallback/fast 比率を観測する。結果が悪くてもよいベンチ専用モードとする。
|
||||
|
||||
Phase68(更新版): 次に攻める大きな箱候補
|
||||
----------------------------------------
|
||||
- C7 HotHeap v2:
|
||||
- C7-only / Mixed 長尺プロファイルでは v1 同等以上まで来ており、bench/pro 用には十分な状態。
|
||||
- ただしデフォルトは引き続き v2 OFF(C7 SAFE v1 本線)。今後は「C7-heavy なワークロード向けオプション」として扱う。
|
||||
- C6/C5 TinyHeap v2:
|
||||
- C6 v2 は route 修正後も C6-heavy/Mixed で明確にマイナス。構造は通電したが perf 未達のため、当面は研究箱として据え置く。
|
||||
- C5 への拡張も v2 の再設計フェーズ(TinyHeap v3 相当)でまとめて考えるのが良さそう。
|
||||
- mid/smallmid / pool 側:
|
||||
- Mixed 16–1024B / mid-large ベンチの perf 分析では、pool allocator(hak_pool_try_alloc/free)や smallmid パスが依然として大きな self% を占めている。
|
||||
- Phase68 以降の本命: **pool/smallmid の Hot Box 化・front 整理**。新設 `docs/analysis/POOL_V2_BOX_DESIGN.md` と `docs/design/POOL_HOTBOX_V2_IMPLEMENTATION_GUIDE.md` に箱と境界を記載。
|
||||
- Tiny v2 は C7-only ベースで一旦凍結し、mid/pool を先に +5〜10% 押し上げるのが mimalloc 7〜8割に近づく近道と考える。***
|
||||
|
||||
補足: C7 v3 と Mixed front
|
||||
---------------------------
|
||||
- C7 v3: C7-only / Mixed で v3 ON が +α(slow=1、fallback=0、refill はウォームアップ由来)を確認。デフォルトは OFF のまま、C7-heavy bench で opt-in。
|
||||
- Mixed 16–1024B で v3 ON の userland perf は、リリースビルドでは `free`/`malloc` に潰れて非C7 Tiny front が見えない。DEBUG/記号付きビルドで再 perf を取り、size→class→route 前段や header 書き込みのフラット化を次ターゲット候補として再評価する。
|
||||
|
||||
Phase69: SmallObjectHotBox v3 構想(Tiny + mid/smallmid 統合)
|
||||
----------------------------------------------------------------
|
||||
- 背景:
|
||||
- Tiny (16–1024B) と mid/smallmid の両方で mimalloc に 0.4〜0.5× 程度の差が残っており、Tiny v2 / pool v2 での局所最適では 7〜8割に届きにくいことが見えてきた。
|
||||
- TinyHotHeap v2 (C7-only) は C7-heavy/Mixed 長尺で v1 SAFE を上回るところまで到達した一方、C6/C5 や pool v2 は研究箱のまま凍結となった。
|
||||
- 方針:
|
||||
- Tiny (C0〜C7) と mid/smallmid の一部を統合して扱う SmallObjectHotBox v3 を新設し、「SmallObject 全体を 1 枚の Hot Box」として設計し直す。
|
||||
- Superslab/Segment/Tier/Guard/Remote は Cold Box として据え置き、Hot 側は SmallObjectHotBox v3 に集約する。
|
||||
- 設計は `docs/analysis/SMALLOBJECT_HOTBOX_V3_DESIGN.md` にまとめ、実装タスクは `docs/design/SMALLOBJECT_HOTBOX_V3_IMPLEMENTATION_GUIDE.md` に段階的に記載。
|
||||
- 位置づけ:
|
||||
- Tiny v2 / pool v2 で得た知見(page_of O(1)、current/partial/retire ポリシー、Cold IF の 2 箇所化)を統合しつつ、v3 では「Tiny + mid/smallmid の一体化」を目指す。
|
||||
- 実装は bench/研究プロファイルから段階的に進め、v1/v2 への戻り道を常に維持する。***
|
||||
|
||||
Reference in New Issue
Block a user