Guard madvise ENOMEM and stabilize pool/tiny front v3
This commit is contained in:
@ -9,6 +9,23 @@
|
||||
- `CURRENT_TASK.md` (Phase36 状況メモ)
|
||||
- ステータス: Phase36 で C7-only の Hot 部(current_page+freelist)を v2 で自前管理する暫定実装を投入済み。Superslab/Tier/Stats は v1 に委譲する lease/refill/retire 境界で A/B できる状態。
|
||||
|
||||
### Phase65/66: C7-only フェーズ完了サマリ
|
||||
- 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 SAFE v1)を維持。
|
||||
- C7-only の bench/pro 用プロファイルでは `HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を opt-in 推奨とし、v2 を本命候補の Hot Box として使う。
|
||||
- C6 v2 は構造こそ通電したものの perf 未達のため、引き続き研究箱(classes=0x40/0xC0 を明示したときだけ有効)に留める。
|
||||
|
||||
### Phase60 速報(C7-only 空ページ保持ポリシー)
|
||||
- 追加したもの:
|
||||
- `max_partial_pages`(C7 デフォルト 2)と `partial_count` を Hot Box に追加し、free で `used==0` の page は一度 partial へ温存。上限超のみ retire を呼ぶ。
|
||||
- partial push/pop/peak と retire_v2 を v2 stats に追加(`HAKMEM_TINY_HOTHEAP_V2_STATS=1` で確認)。
|
||||
- 初期ベンチ:
|
||||
- C7-only v2 ON で slow_prepare は `alloc_lease` と一致(≈48 回)。live ブロックが多く page が空にならないため partial/retire は未発火。
|
||||
- Mixed でも v2 ON は +2〜3% だが slow≈refill(42)。空ページを作れる workload またはページ容量/lease の見直しが次課題。
|
||||
- 運用: v2 は引き続き研究箱(デフォルト OFF)。C7-only で安定後に Mixed への適用を検討する。
|
||||
|
||||
---
|
||||
|
||||
## 0. ゴールと非ゴール
|
||||
@ -396,3 +413,181 @@ Step 7-6: 再ベンチと判定基準
|
||||
次フェーズで C6/C5 への拡張や C7 超ホットレーン(B案)を検討できる。
|
||||
- 満たせない場合は v2 を引き続き **デフォルト OFF / 研究用箱** としたまま、
|
||||
current_page / retire ポリシーの再修正に戻る。
|
||||
|
||||
---
|
||||
|
||||
## 8. Phase58: TinyColdIface 導入後の課題整理と次の実装指示
|
||||
|
||||
現状ステータス(Phase58 時点)
|
||||
------------------------------
|
||||
- `core/box/tiny_cold_iface_v1.h` に `TinyColdIface` が導入され、v1 TinyHeap の
|
||||
- `tiny_heap_prepare_page()` → `refill_page(cold_ctx, class_idx)`
|
||||
- `tiny_heap_page_becomes_empty()` → `retire_page(cold_ctx, class_idx, page)`
|
||||
としてラップ済み。Hot Box 側からはこの IF だけを見れば Superslab/Tier/Stats に触れられる状態になっている。
|
||||
- C7 v2 の Cold 境界は次のように接続済み:
|
||||
- `tiny_hotheap_v2_refill_slow()`:
|
||||
- `TinyColdIface cold = tiny_cold_iface_v1();`
|
||||
- `tiny_heap_ctx_t* cold_ctx = tiny_heap_ctx_for_thread();`
|
||||
- `ipage = cold.refill_page(cold_ctx, class_idx)` で v1 から `tiny_heap_page_t` を 1 枚借りる。
|
||||
- v2 側の `tiny_hotheap_page_v2` ノードを確保し、`base/capacity/meta/ss/slab_idx` をコピー。
|
||||
- freelist が無い場合は v2 が `used=0` にリセットし、`tiny_hotheap_v2_build_freelist()` で carve する。
|
||||
- freelist がある場合は `lease_page->meta->freelist` を v2 freelist で更新。
|
||||
- `hc->current_page` に必ず freelist 付きページが入るよう Fail-Fast チェックを追加。
|
||||
- `tiny_hotheap_v2_page_retire_slow()`:
|
||||
- v2 の `current_page` / `partial_pages` / `full_pages` から対象ページを unlink。
|
||||
- `cold.retire_page(cold_ctx, class_idx, page->lease_page)` を呼んで v1 側へ返却。
|
||||
- `storage_page` 以外は `free(page)`、storage は `tiny_hotheap_v2_page_reset()` で初期化。
|
||||
- TLS 初期化 (`tiny_hotheap_v2_tls_get()`) では、`tiny_hotheap_ctx_v2` を `calloc` し、各クラスの `storage_page` を reset、`stride` を `tiny_stride_for_class(i)` で事前設定するようにした。
|
||||
- v2 Stats:
|
||||
- `g_tiny_hotheap_v2_c7_*` に `alloc_calls/route_hits/alloc_fast/alloc_refill/alloc_fallback_v1/free_*` や
|
||||
`cold_refill_fail` / `cold_retire_calls` を追加し、`HAKMEM_TINY_HOTHEAP_V2_STATS=1` で destructor ダンプ。
|
||||
|
||||
残っている問題(なぜ v2 ON で SEGV するか)
|
||||
-----------------------------------------
|
||||
- `tiny_hotheap_v2_try_pop()` は依然として v1 TinyHeap の page API に強く依存している:
|
||||
- `candidate->lease_page` を `ipage` として取り出し、
|
||||
- `v1hcls->current_page = ipage;`
|
||||
- `tiny_heap_page_pop(v1hcls, 7, ipage);`
|
||||
- 必要なら `tiny_heap_page_mark_full(v1hcls, ipage);`
|
||||
を呼んだうえで、
|
||||
- `candidate->freelist = ipage->free_list;`
|
||||
- `candidate->used = ipage->used;`
|
||||
と v2 側 state にもコピーしている。
|
||||
- これは Box Theory 的には
|
||||
> Hot Box (v2) が Cold Box (v1 TinyHeap) の内部状態 (`free_list/used`) を直接操作している
|
||||
ことになり、境界が二重になっている。
|
||||
- refill で v2 が独自に carve した freelist と、v1 の `tiny_heap_page_pop()` が更新する `free_list/used/meta` がずれていくと、
|
||||
- 無効な `ipage->base` / `capacity` / `meta` を deref したり
|
||||
- v2 の `candidate->freelist` が壊れた状態で次の pop に進んでしまう
|
||||
可能性がある。現状の SIGSEGV はこのあたりの不整合に起因していると考えられる。
|
||||
|
||||
Phase58 でやるべきこと(実装指示)
|
||||
---------------------------------
|
||||
|
||||
### 8-1. `tiny_hotheap_v2_try_pop()` から v1 依存を外し、v2 freelist だけで完結させる
|
||||
|
||||
目的:
|
||||
- Hot Box v2 は「自分の freelist を自分で pop する箱」とし、Cold Box v1 には refill/retire でしか触れないようにする。
|
||||
|
||||
作業指示:
|
||||
- `tiny_hotheap_v2_try_pop()` を次の方針で書き換える:
|
||||
- 引数から `tiny_heap_class_t* v1hcls` を削除し、`TinyColdIface` / v1 TinyHeap の型に依存しない形にする。
|
||||
- `candidate` から直接 freelist を pop:
|
||||
|
||||
```c
|
||||
static inline void* tiny_hotheap_v2_try_pop(tiny_hotheap_page_v2* candidate,
|
||||
TinyHeapClassStats* stats,
|
||||
int stats_on) {
|
||||
if (!candidate || !candidate->freelist || candidate->used >= candidate->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
void* user = candidate->freelist;
|
||||
candidate->freelist = *(void**)user;
|
||||
candidate->used++;
|
||||
if (__builtin_expect(stats != NULL, 0)) {
|
||||
atomic_fetch_add_explicit(&stats->alloc_fast_current, 1, memory_order_relaxed);
|
||||
}
|
||||
if (stats_on) {
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_alloc_fast, 1, memory_order_relaxed);
|
||||
}
|
||||
return tiny_region_id_write_header(user, 7);
|
||||
}
|
||||
```
|
||||
|
||||
- v1 TinyHeap (`tiny_heap_page_pop` / `tiny_heap_page_mark_full` / `v1hcls->current_page` など) の呼び出しは完全に削除する。
|
||||
- `candidate->lease_page` は **Cold 側に返すための token** として保持するだけにし、Hot path では一切触らない。
|
||||
|
||||
### 8-2. Cold 境界 (`refill_page` / `retire_page`) を「イベント 2 箇所だけ」に限定する
|
||||
|
||||
目的:
|
||||
- Hot Box v2 と Cold Box v1 の境界を「page を借りる」「page を返す」の 2 箇所だけにし、meta/used/freelist の二重管理をやめる。
|
||||
|
||||
作業指示:
|
||||
- `tiny_hotheap_v2_refill_slow()`:
|
||||
- `TinyColdIface.refill_page()` から返ってきた `tiny_heap_page_t* ipage` については、
|
||||
- `base` / `capacity` / `slab_idx` / `meta` / `ss` など **geometry 情報だけ** を読む。
|
||||
- `ipage->free_list` / `ipage->used` は Hot path では信頼しない(v2 が自前で carve した freelist を使う)。
|
||||
- v2 側の `tiny_hotheap_page_v2` に freelist を構築したら、以降の alloc/free は v2 freelist だけで完結させる。
|
||||
- どうしても meta に初期値を書き戻す必要がある場合は、Cold Stats Box 経由の更新に寄せる(直接 meta->used に触らない方向を優先)。
|
||||
- `tiny_hotheap_v2_page_retire_slow()`:
|
||||
- `page->used == 0` かつ v2 内のリストから unlink した段階でのみ `TinyColdIface.retire_page()` を呼ぶ。
|
||||
- 返却後は `page->lease_page` を含めて v2 側 state を破棄または reset し、同じ token を Hot path から再利用しない。
|
||||
|
||||
### 8-3. 安全側のガードと Stats での確認ポイント
|
||||
|
||||
目的:
|
||||
- v2 を再度 ON にした際、segv や Cold IF への過剰依存がないかをすぐに検知できるようにする。
|
||||
|
||||
作業指示:
|
||||
- `tiny_hotheap_v2_alloc()` / `tiny_hotheap_v2_free()` の入口で:
|
||||
- `class_idx != 7` は即 `NULL` or fallback(C7-only 実験箱のまま)。
|
||||
- `v2ctx == NULL` / `hc == NULL` / `hc->stride == 0` などは Fail-Fast(abort)で早期検出。
|
||||
- `tiny_hotheap_v2_try_pop()`:
|
||||
- `candidate->capacity == 0` や `candidate->used > candidate->capacity` の場合は即 `NULL` を返す(デバッグビルドでは 1 回だけログ)。
|
||||
- Stats:
|
||||
- C7-only ベンチ (`ws=64, iters=20k, PROFILE=C7_SAFE`) で:
|
||||
- v2 OFF: 既存どおり `HEAP_STATS[7] fast≈11015 slow≈1`。
|
||||
- v2 ON:
|
||||
- `alloc_fast` が 1 回目の page refill 後に `route_hits` と同程度まで増えていくこと。
|
||||
- `cold_refill_fail` が常に 0 付近であること。
|
||||
- `alloc_fallback_v1` / `free_fallback_v1` が 0〜ごく少数に収まっていること。
|
||||
|
||||
備考
|
||||
----
|
||||
- Phase58 の目的は **「TinyColdIface を導入したうえで、v2 Hot Box と v1 TinyHeap の境界を 2 箇所 (refill/retire) に絞ること」** であり、
|
||||
この段階では性能よりも安定性(segv しないこと)と Box 境界の明確化を優先する。
|
||||
- C7-only で v2 が v1 と同等レベルで安定したら、次フェーズで C6/C5 への拡張や perf チューニング(分岐削減・命令数削減)に進む。
|
||||
|
||||
---
|
||||
|
||||
## 9. Phase60/61: C7-only フェーズ完了と次のターゲット (C6 拡張) メモ
|
||||
|
||||
現状まとめ(C7 v2 フェーズの着地)
|
||||
---------------------------------
|
||||
- C7-only:
|
||||
- v2 OFF (C7 SAFE v1) ≈ 42M ops/s / slow≈1。
|
||||
- v2 ON (C7-only, classes=0x80) ≈ 50M ops/s / slow≈40〜50 → 空ページ保持ポリシー導入前の状態。
|
||||
- 空ページ保持ポリシー導入 (`max_partial_pages` / `partial_count` 追加) 後も、C7-only ではページが実質 full のまま回るため partial/retire はほぼ発火せず、slow は主に refill 回数として現れる。
|
||||
- Mixed 16–1024B:
|
||||
- 短尺 (ws=256, iters=20k, PROFILE=C7_SAFE):
|
||||
- v2 OFF: ≈43.3M ops/s, HEAP_STATS[7] fast=5691 slow=1。
|
||||
- v2 ON: ≈44.6M ops/s(約 +3%), HEAP_STATS[7] fast=5691 slow=1, fail/fallback=0。
|
||||
- 長尺 (ws=400, iters=1M, PROFILE=C7_SAFE):
|
||||
- v2 OFF: ≈41.6M ops/s, HEAP_STATS[7] fast≈283k slow=1。
|
||||
- v2 ON: ≈42.4M ops/s(約 +2%), HEAP_STATS[7] fast≈283k slow=1, fail/fallback=0。
|
||||
- 境界:
|
||||
- Cold IF (`TinyColdIface`) 経由の refill/retire は安定しており、`cold_refill_fail` / fallback_v1 は 0 に張り付き。
|
||||
- C7 v2 の Hot パスは `tiny_hotheap_page_v2.freelist` のみで完結し、v1 TinyHeap の page/pop は参照しない構造になった。
|
||||
|
||||
結論(C7 フェーズ)
|
||||
-------------------
|
||||
- C7 v2 Hot Box は:
|
||||
- C7-only / Mixed / 短尺・長尺のいずれでも v1 C7 SAFE を上回るスループットを達成。
|
||||
- slow_prepare は v2 OFF/ON ともに 1(長尺)またはワークロード由来の refill 回数程度に収まり、Cold IF の異常ではない。
|
||||
- fail/fallback=0 で、v2→v1 フォールバックに頼らずに Hot Box 単体で完結できている。
|
||||
- 運用上の位置づけ:
|
||||
- 標準デフォルト: 引き続き `HAKMEM_TINY_HOTHEAP_V2=0`(どの環境でも即 v1 C7 SAFE に戻せるようにする)。
|
||||
- bench/研究プロファイル: C7 クラスに限り `HAKMEM_TINY_HOTHEAP_V2=1` / `HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を推奨設定とし、C7 v2 を本命候補として扱う。
|
||||
|
||||
次のターゲット候補 (C6/C5 拡張の入り口)
|
||||
--------------------------------------
|
||||
- 目的:
|
||||
- TinyHotHeap v2 の設計ゴールどおり、C7-only から C6/C5 へ段階的に適用範囲を広げて、Mixed 16–1024B 全体の性能を押し上げる。
|
||||
- Gate/Policy 側の前提:
|
||||
- PolicySnapshot / Route LUT に `tiny_heap_version[class_idx]` または `HAKMEM_TINY_HOTHEAP_CLASSES` のマスクを持ち、
|
||||
- C7: まず v2 を有効(研究/bench向け)。
|
||||
- C6: 将来的に `classes |= 0x40` で C6 を v2 に昇格させる余地を残す。
|
||||
- C5: 同様に `classes |= 0x20` で C5 を v2 に載せる最終フェーズ。
|
||||
- C6 拡張時に検討すべきポイント(設計メモのみ、実装は別フェーズ):
|
||||
- ワークロード分布: Mixed 16–1024B で C6 がどの程度トラフィックを持つか(既存 FRONT_CLASS stats を参考にする)。
|
||||
- 以前の Tiny C6 v1 実験では Mixed 回帰があったため、C6 v2 では:
|
||||
- Route/Gate で C6 の Hot path を C7 と同じ 1 LUT + 1 switch に揃える。
|
||||
- Unified Cache / WarmPool / Superslab へのアクセス回数が増えないようにする(pure Hot Box 化を徹底)。
|
||||
- rollout 戦略:
|
||||
1. C6-only bench プロファイルで C6 v2 を ON にし、C6-heavy なベンチで C6 v1 と A/B(少なくとも回帰なし)。
|
||||
2. Mixed 16–1024B で C7 v2 + C6 v2 構成と C7 v2 のみ構成を比較し、±5% 以内 or 微プラスであれば「C6 v2 を本命候補」とする。
|
||||
3. いずれも満たせない場合は、C6 v2 を C7 v2 と同様に研究箱(ENV で個別に OFF 可能)として維持し、本線は C7 v2 + C6 v1 のままにする。
|
||||
|
||||
メモ:
|
||||
- 本ガイドは C7 フェーズまでの実装指針とログを含んでおり、C6/C5 拡張は「同じ TinyHotHeapBox v2 の枠内で class を増やす」作業として扱う。
|
||||
- C6/C5 拡張の具体的な API 変更や stats 追加は、今後の Phase (例: Phase62 以降) で別途「C6 v2 指示書」として追記する想定。***
|
||||
|
||||
Reference in New Issue
Block a user