## Summary
Implemented Front-Direct architecture with complete SLL bypass:
- Direct SuperSlab → FastCache refill (1-hop, bypasses SLL)
- SLL-free allocation/free paths when Front-Direct enabled
- Legacy path sealing (SLL inline opt-in, SFC cascade ENV-only)
## New Modules
- core/refill/ss_refill_fc.h (236 lines): Standard SS→FC refill entry point
- Remote drain → Freelist → Carve priority
- Header restoration for C1-C6 (NOT C0/C7)
- ENV: HAKMEM_TINY_P0_DRAIN_THRESH, HAKMEM_TINY_P0_NO_DRAIN
- core/front/fast_cache.h: FastCache (L1) type definition
- core/front/quick_slot.h: QuickSlot (L0) type definition
## Allocation Path (core/tiny_alloc_fast.inc.h)
- Added s_front_direct_alloc TLS flag (lazy ENV check)
- SLL pop guarded by: g_tls_sll_enable && !s_front_direct_alloc
- Refill dispatch:
- Front-Direct: ss_refill_fc_fill() → fastcache_pop() (1-hop)
- Legacy: sll_refill_batch_from_ss() → SLL → FC (2-hop, A/B only)
- SLL inline pop sealed (requires HAKMEM_TINY_INLINE_SLL=1 opt-in)
## Free Path (core/hakmem_tiny_free.inc, core/hakmem_tiny_fastcache.inc.h)
- FC priority: Try fastcache_push() first (same-thread free)
- tiny_fast_push() bypass: Returns 0 when s_front_direct_free || !g_tls_sll_enable
- Fallback: Magazine/slow path (safe, bypasses SLL)
## Legacy Sealing
- SFC cascade: Default OFF (ENV-only via HAKMEM_TINY_SFC_CASCADE=1)
- Deleted: core/hakmem_tiny_free.inc.bak, core/pool_refill_legacy.c.bak
- Documentation: ss_refill_fc_fill() promoted as CANONICAL refill entry
## ENV Controls
- HAKMEM_TINY_FRONT_DIRECT=1: Enable Front-Direct (SS→FC direct)
- HAKMEM_TINY_P0_DIRECT_FC_ALL=1: Same as above (alt name)
- HAKMEM_TINY_REFILL_BATCH=1: Enable batch refill (also enables Front-Direct)
- HAKMEM_TINY_SFC_CASCADE=1: Enable SFC cascade (default OFF)
- HAKMEM_TINY_INLINE_SLL=1: Enable inline SLL pop (default OFF, requires AGGRESSIVE_INLINE)
## Benchmarks (Front-Direct Enabled)
```bash
ENV: HAKMEM_BENCH_FAST_FRONT=1 HAKMEM_TINY_FRONT_DIRECT=1
HAKMEM_TINY_REFILL_BATCH=1 HAKMEM_TINY_P0_DIRECT_FC_ALL=1
HAKMEM_TINY_REFILL_COUNT_HOT=256 HAKMEM_TINY_REFILL_COUNT_MID=96
HAKMEM_TINY_BUMP_CHUNK=256
bench_random_mixed (16-1040B random, 200K iter):
256 slots: 1.44M ops/s (STABLE, 0 SEGV)
128 slots: 1.44M ops/s (STABLE, 0 SEGV)
bench_fixed_size (fixed size, 200K iter):
256B: 4.06M ops/s (has debug logs, expected >10M without logs)
128B: Similar (debug logs affect)
```
## Verification
- TRACE_RING test (10K iter): **0 SLL events** detected ✅
- Complete SLL bypass confirmed when Front-Direct=1
- Stable execution: 200K iterations × multiple sizes, 0 SEGV
## Next Steps
- Disable debug logs in hak_alloc_api.inc.h (call_num 14250-14280 range)
- Re-benchmark with clean Release build (target: 10-15M ops/s)
- 128/256B shortcut path optimization (FC hit rate improvement)
Co-Authored-By: ChatGPT <chatgpt@openai.com>
Suggested-By: ultrathink
19 KiB
CURRENT TASK (Phase 12: Shared SuperSlab Pool – Debug Phase)
Phase12 の設計に沿った shared SuperSlab pool 実装および Box API 境界リファクタリングは導入済み。 現在は shared backend 有効状態での SEGV 解消と安定化 を行うデバッグフェーズに入っている。
本タスクでは以下をゴールとする:
- shared Superslab pool backend (
hakmem_shared_pool.[ch]+hak_tiny_alloc_superslab_backend_shared) を Box API (hak_tiny_alloc_superslab_box) 経由で安全に運用できる状態にする。 bench_random_mixed_hakmem実行時に SEGV が発生しないことを確認し、 shared backend を実用レベルの「最小安定実装」として確定させる。
2. 現状サマリ(実装済み)
-
Box/API 境界
- tiny フロントエンドから Superslab への入口:
hak_tiny_alloc_superslab_box(int class_idx)に一本化。
- TLS SLL:
- slow path を含む呼び出しは
tls_sll_box.h(tls_sll_pop(int, void**)等) の Box API 経由に統一。
- slow path を含む呼び出しは
- tiny フロントエンドから Superslab への入口:
-
shared Superslab pool 実装
hakmem_shared_pool.[ch]:SharedSuperSlabPool g_shared_poolとshared_pool_init,shared_pool_acquire_slab,shared_pool_release_slabを実装。- SuperSlab を global に管理し、slab 単位で
class_idxを割当/解放する shared pool 構造を提供。
hakmem_tiny_superslab.c:hak_tiny_alloc_superslab_backend_shared(int class_idx):shared_pool_acquire_slabにより(ss, slab_idx)を取得。superslab_init_slabで未初期化 slab を初期化。- ジオメトリは
SUPERSLAB_SLAB0_DATA_OFFSET+slab_idx * SUPERSLAB_SLAB_USABLE_SIZE+used * strideを使用。 - 単純 bump でブロックを返却。
hak_tiny_alloc_superslab_backend_legacy(int class_idx):- 旧 per-class
g_superslab_headsベースの実装を static backend に封じ込め。
- 旧 per-class
hak_tiny_alloc_superslab_box(int class_idx):- shared backend → 失敗時に legacy backend へフォールバックする実装に更新。
make bench_random_mixed_hakmem:- ビルドは成功し、shared backend を含む構造的な不整合は解消済み。
-
現状の問題(2025-11-14 更新)
bench_random_mixed_hakmemは SLL(TLS 単方向リスト)有効時に早期 SEGV。- SLL を無効化(
HAKMEM_TINY_TLS_SLL=0)すると、shared ON/OFF いずれも安定完走(Throughput 表示)。 - よって、現時点のクラッシュ主因は「共有SS」ではなく「SLL フロント経路の不整合(BASE/USER/next 取り扱い)」である可能性が高い。
以降は、この SEGV を潰し「shared Superslab pool 最小安定版」を完成させるためのデバッグタスクとする。
3. デバッグフェーズの具体タスク
3-1. shared backend ON/OFF 制御と原因切り分け
- shared backend スイッチ導入・確認
hak_tiny_alloc_superslab_box(int class_idx)に環境変数または定数フラグを導入し:HAKMEM_TINY_SS_SHARED=0→ legacy backend のみ(回帰確認用)HAKMEM_TINY_SS_SHARED=1→ 現行 shared backend(デバッグ対象)
- 手順:
- legacy 固定で
bench_random_mixed_hakmem実行 → SEGV が消えることを確認し、問題が shared 経路に限定されることを保証。
- legacy 固定で
3-2. shared slab メタデータの一貫性検証
-
shared_pool_acquire_slabとhak_tiny_alloc_superslab_backend_sharedの整合確認- 確認事項:
class_idx割当時に:meta->class_idxが正しくclass_idxにセットされているか。superslab_init_slab呼び出し後、capacity > 0,used == 0,freelist == NULLになっているか。
meta->used++/total_active_blocks++の更新が free パスの期待と一致しているか。
- 必要なら:
- debug build で
assert(meta->class_idx == class_idx)等を追加して早期検出。
- debug build で
- 確認事項:
-
free/refill 経路との整合性
- 対象ファイル:
tiny_superslab_free.inc.hhakmem_tiny_free.inchakmem_tiny_bg_spill.c
- 確認事項:
- pointer→SuperSlab→TinySlabMeta 解決ロジックが:
meta->class_idxベースで正しい class を判定しているか。- shared/legacy の違いに依存せず動作するか。
- 空 slab 判定時に:
shared_pool_release_slabを呼ぶ条件とmeta->used == 0の扱いが矛盾していないか。
- pointer→SuperSlab→TinySlabMeta 解決ロジックが:
- 必要な修正:
- shared slab 専用の「空になった slab の返却」パスを導入し、UNASSIGNED への戻しを一元化。
- 対象ファイル:
3-3. Superslab registry / LRU / shared pool の連携確認
- Registry & LRU 連携
hakmem_super_registry.cの:hak_super_register,hak_super_unregisterhak_ss_lru_pop/push
- 確認:
- shared pool で確保した SuperSlab も registry に登録されていること。
- LRU 経由再利用時に
class_idx/slab 割付が破綻していないこと。
- 必要に応じて:
- shared pool 管理下の SuperSlab を区別するフラグや、再利用前のメタリセットを追加。
3-4. SEGV の直接解析
- gdb によるスタックトレース取得(実施)
- コマンド例:
cd hakmemgdb --args ./bench_random_mixed_hakmemrunbt
- 結果(抜粋):
hak_tiny_alloc_fast_wrapper()内で SEGV。SLL 無効化で再現しないため、SLL 経路の BASE/USER/next の整合に絞る。
- コマンド例:
3-5. 安定版 shared Superslab pool の確定
- 修正後確認
HAKMEM_TINY_SS_SHARED=1(shared 有効)で:bench_random_mixed_hakmemが SEGV 無しで完走すること。- 簡易的な統計・ログで:
- shared Superslab が複数 class で共有されていること。
- メタデータ破綻や異常な解放が発生していないこと。
- これをもって:
- 「Phase12 Shared Superslab Pool 最小安定版」が完了。
2-3. TLS / SLL / Refill の整合性確保
スコープ: core/hakmem_tiny_refill.inc.h, core/hakmem_tiny_tls_ops.h, core/hakmem_tiny.c(局所)
-
sll_refill_small_from_ss の Phase12 対応
- 入力:
class_idx,max_take - 動作:
- shared pool から該当
class_idxの slab を取得 or bind。 - slab の freelist/bump から
max_take個を TLS SLL に積む。
- shared pool から該当
- ここでは:
- g_sll_cap_override を参照しない(将来廃止しやすい形に)。
- cap 計算は
sll_cap_for_class(class_idx, mag_cap)に集約。
- 入力:
-
tiny_fast_refill_and_take / TLS SLL 経路の一貫性
tiny_fast_refill_and_takeが:- まず TLS SLL / FastCache を見る。
- 足りなければ
sll_refill_small_from_ssを必ず経由するよう整理(旧経路の枝刈り)。
- ただし:
- 既存インラインとの整合性を崩さないよう、分岐削除は段階的に行う。
2-4. g_sll_cap_override の段階的無効化(安全版)
-
参照経路のサニタイズ(非破壊)
hakmem_tiny_intel.inc,hakmem_tiny_background.inc,hakmem_tiny_init.incなどで:- g_sll_cap_override を書き換える経路を
#if 0or コメントアウトで停止。 - 配列定義自体はそのまま残し、リンク切れを防ぐ。
- g_sll_cap_override を書き換える経路を
sll_cap_for_class()は Phase12 ポリシーに従う実装に置き換える。- これにより:
- 実際の SLL cap は sll_cap_for_class 経由に統一されるが、
- ABI/シンボル互換性は保持される。
-
ビルド & アセンブリ確認
make bench_random_mixed_hakmemgdb -q ./bench_random_mixed_hakmem -ex "disassemble sll_refill_small_from_ss" -ex "quit"- 確認項目:
- g_sll_cap_override 更新経路は実際には使われていない。
- sll_refill_small_from_ss が shared SuperSlab pool を用いる単一ロジックになっている。
2-5. Shared Pool 実装の検証とバグ切り分け
-
機能検証
bench_random_mixed_hakmemを実行:- SIGSEGV / abort の有無
- ログと
HAKMEM_TINY_SUPERSLAB_TRACEで shared pool の挙動を確認。
-
パフォーマンス確認
- 目標: 設計書の期待値に対し、オーダーとして妥当な速度になっているか:
- 9M → 70–90M ops/s のレンジを狙う(まずは退行していないことを確認)。
- 目標: 設計書の期待値に対し、オーダーとして妥当な速度になっているか:
-
問題発生時の切り分け
- クラッシュ/不正挙動があれば:
- まず shared pool 周辺(slab class_idx, freelist 管理, owner/bind/unbind)に絞って原因特定。
- Tiny front-end (bump, SLL, HotMag 等) を疑うのはその後。
- クラッシュ/不正挙動があれば:
3. 実装ルール(再確認)
- hakmem_tiny.c は write_to_file で全書き換えしない。
- 変更は:
#if 0/ コメントアウト- 局所的な関数実装差し替え
- 新しい shared pool 関数の追加
- 既存呼び出し先の付け替え に限定し、逐次ビルド確認する。
4. 直近の変更(2025-11-14 追記)
- 定数/APIの復元・宣言不足解消(
SUPERSLAB_LG_*, 所有権API, active dec, fail-fast スタブ 等)。 - Box 2 drain 境界を
_ss_remote_drain_to_freelist_unsafe()に一本化。 tiny_fast_pop()が USER を返していた不具合を修正(BASE返却へ)。- SLL トグルの実効化:
- free v2(ヘッダ系)で
g_tls_sll_enable==0時は即スローパスへ。 - alloc fast でも SLL 無効時は TLS SLL pop を完全スキップ。
- free v2(ヘッダ系)で
tls_sll_boxの capacity > 1<<20 を「無制限」扱いへ(過剰警告を抑制)。
暫定ガイド(shared の検証を先に進めるため)
HAKMEM_TINY_TLS_SLL=0で shared ON/OFF の安定動作を確認し、shared 経路の SEGV 有無を切り分ける。
次の一手(SLL ルートの最小修正)
- SLL push/pop すべての呼び出しを Box API 経由(BASEのみ)に強制。直書き・next手計算を禁止。
tls_sll_boxにデバッグ限定の軽量ガードを追加(slab範囲+stride整合)して最初の破綻ノードを特定。- 必要なら一時的に
HAKMEM_TINY_SLL_C03_ONLY=1(C0–C3 のみ SLL 使用)で範囲を狭め、原因箇所を早期確定。
現在のトリアージ結果(2025-11-14 後半)
- 共有SS: SLL を C0..C4 に限定(
HAKMEM_TINY_SLL_MASK=0x1F)で ON は安定完走。OFF(legacy)は SEGV(別途) - SLL: C5(256B)を含めると SEGV 再現。
HAKMEM_TINY_HOTPATH_CLASS5=0にすると安定化。- 対策(小変更):
- クラス4以上の alloc fast POP は
tls_sll_pop()(Box API)で安全化。 - SLL PUSH は
HAKMEM_TINY_SLL_SAFEHEADER=1でヘッダ不一致時に上書きせず拒否(blind write回避)。 - class5 ホットパスは POP/PUSH をガード付き(
tls_list_pop/push)に変更。
- クラス4以上の alloc fast POP は
- それでも
g_tiny_hotpath_class5=1だと再現 → ホットパス経路のどこかに BASE/USER/next 整合不備が残存。 - 当面の安定デフォルト:
g_tiny_hotpath_class5=0(Env で A/B 可:HAKMEM_TINY_HOTPATH_CLASS5=1)。
- 対策(小変更):
C5 SEGV 根治(実装済み・最小パッチ)
- 直接原因(再現ログ/リングより)
- TLS SLL へ push される C5 ノードの header が 0x00(
safeheaderによる reject が連発) - パターン: 連番アドレス(
...8800, ...8900, ...8a00, ...)で header=0 → carve/remote 経由の未整備ノード
- TLS SLL へ push される C5 ノードの header が 0x00(
- 修正点(Box 境界厳守の“点”修正)
- Remote Queue → FreeList 変換時に header を復元
- ファイル:
core/hakmem_tiny_superslab.c:120付近(_ss_remote_drain_to_freelist_unsafe) - 処理: クラス1–6は
*(uint8_t*)node = HEADER_MAGIC | (cls & HEADER_CLASS_MASK)を実行後、tiny_next_write()で next を Box 形式に書換
- ファイル:
- Superslab→TLS SLL への refill 時に header を整備
- ファイル:
core/hakmem_tiny_refill.inc.h:...(sll_refill_small_from_ss) - 処理: SLL へ積む直前にクラス1–6の header を設定してから
tls_sll_push()
- ファイル:
- 参考: 旧
pool_tls_remote.cも Box API 化(未使用系だが将来不整合防止)
- Remote Queue → FreeList 変換時に header を復元
- 検証(リング+ベンチ)
- 環境:
HAKMEM_TINY_SLL_MASK=0x3F HAKMEM_TINY_SLL_SAFEHEADER=1 HAKMEM_TINY_HOTPATH_CLASS5=1 - 以前:
tls_sll_reject(class=5)が多数 → SIGSEGV - 以後:
bench_random_mixed_hakmem 200000 256 42正常完走(リングに tls_sll_* 異常なし) - C5 単独(
mask=0x20)でも異常なしを確認
- 環境:
次の実装(根治方針/小粒)
- 共有SSの観測を先に確定(
HAKMEM_TINY_SLL_MASK=0x1FでON/OFFのA/B、軽いFail‑Fast/リング有効) - C5根治: C5のみON(
HAKMEM_TINY_SLL_MASK=0x20、HAKMEM_TINY_SLL_SAFEHEADER=1、HAKMEM_TINY_HOTPATH_CLASS5=0)で短尺実行→最初の破綻箇所をログ採取- 追加可視化(異常時のみリング記録):
HAKMEM_TINY_SLL_RING=1 HAKMEM_TINY_TRACE_RING=1- 追加イベント:
tls_sll_reject(safeheaderで拒否),tls_sll_sentinel(リモート哨戒混入),tls_sll_hdr_corrupt(POP時ヘッダ不整合) - 実行例:
HAKMEM_TINY_SLL_MASK=0x20 HAKMEM_TINY_SLL_SAFEHEADER=1 HAKMEM_TINY_HOTPATH_CLASS5=0 HAKMEM_TINY_SLL_RING=1 HAKMEM_TINY_TRACE_RING=1 ./bench_random_mixed_hakmem 100000 256 42
- 追加イベント:
- 追加可視化(異常時のみリング記録):
- 該当箇所(BASE/USER/next、ヘッダ整合)に点で外科修正(~20–30行)。
- 段階的にマスク拡張(C6→C7)し再検証。
5. Tiny フロント最適化ロードマップ(Phase 2/3 反映)
目的: 全ベンチで強い Tiny 層(≤1KB)を、箱理論の境界を守ったまま高速化。配列ベース(QuickSlot/FastCache)を主役に、SLL はオーバーフロー/合流専用に後退配置する。
構造(箱と境界)
- L0: QuickSlot(C0–C3向け 6–8 スロット固定)
- 配列 push/pop だけ。ノードに一切書かない(BASE/USER/next 不触)。
- Miss→L1。
- L1: FastCache(C0–C7、cap 128–256)
- Refill は SS→FC へ“直補充”のみ(目標 cap まで一気に埋める)。
- 1個返却: FC→返却(ヘッダ整備は Box 内 1 点)。
- L2: TLS SLL(Box API)
- 役割は「オーバーフロー/合流」のみ(Remote Drain の合流や FC 溢れ時)。
- アプリの通常ヒット経路からは外す(alloc 側の inline pop は行わない)。
- 採用境界(1 箇所維持)
superslab_refill()に adopt→remote_drain→bind→owner の順序を集約。- Remote Queue(Box 2)は push(offset0 書き)専任、drain は境界 1 箇所のみ。
A/B トグル(既存に追加・整理)
HAKMEM_TINY_REFILL_BATCH=1(P0: SS→FC 直補充 ON)HAKMEM_TINY_P0_DIRECT_FC_ALL=1(全クラス FC 直補充)HAKMEM_TINY_FRONT_DIRECT=1(中間層をスキップし FC 直補充→FC 再ポップ、既定 OFF)- プリセット(ベンチ良好):
HAKMEM_TINY_REFILL_COUNT_HOT=256 HAKMEM_TINY_REFILL_COUNT_MID=96 HAKMEM_TINY_BUMP_CHUNK=256
レガシー整理方針(本体を美しく)
- 入口/出口をモジュール化し、本体は 500 行以内を目安に維持。
- front 層:
core/front/quick_slot.h,core/front/fast_cache.h,core/front/front_gate.h - refill 層:
core/refill/ss_refill_fc.h(SS→FC 直補充の 1 本化) - SLL 層(後退配置):
core/box/tls_sll_box.hのみ公開、呼出しは refill/合流だけに限定
- front 層:
- レガシー経路の段階的削除/封印
- inline SLL pop(C0–C3 用)や SFC cascade の常用経路を削除/既定無効化。
.bak系や重複/未使用ユーティリティを整理(削除)- すべて A/B ガード付きで移行、Fail‑Fast とリングは“異常時のみ”記録。
受け入れ基準(箱単位)
- Front(L0/L1)ヒット率>80% を狙い、Refill 回数/1 回あたり取得数・SS 書換回数を計測。
- Remote Drain は採用境界 1 箇所だけで発生し、drain 後の
remote_counts==0を保証。 - ベンチ指標(単スレ)
- 128/256B: 15M→30M→60M の順に上積み(A/B でトレンド確認)。
- 安定性: sentinel 混入・ヘッダ不整合は Fail‑Fast、リングは異常時のみワンショット。
実装ステップ(Phase 2/3)
- SS→FC 直補充の標準化(現行
HAKMEM_TINY_REFILL_BATCHを標準パスに昇格) - L0/L1 先頭化(alloc は FC→返却が基本、SLL は合流専用)
- SFC は残差処理へ限定(既定 OFF、A/B 実験のみ)
- レガシー経路の削除・モジュール化(500 行以内目安で本体を分割)
- プリセットの標準化(Hot-heavy をデフォルト、A/B で Balanced/Light 切替)
6. 現在の進捗と次作業(Claude code 君に引き継ぎ)
完了済み(沙汰の通り)
- 新モジュール:
core/refill/ss_refill_fc.h(SS→FC 直補充、236行) - Front モジュール化:
core/front/quick_slot.h,core/front/fast_cache.h - Front‑Direct 経路: alloc/free 双方で SLL バイパス(ENV:
HAKMEM_TINY_FRONT_DIRECT=1) - Refill dispatch: ENV で
ss_refill_fc_fill()を使用(HAKMEM_TINY_REFILL_BATCH/…DIRECT_FC_ALL) - SFC cascade: 既定 OFF(ENV:
HAKMEM_TINY_SFC_CASCADE=1で opt‑in) - ベンチ短尺での安定確認(SLL イベント 0, SEGV なし)
未了・次作業(Claude code 君にお願い)
- レガシー封印/削除(A/B 残し)
- inline SLL pop 常用呼び出しを封印(
#if HAKMEM_TINY_INLINE_SLL未定義時は無効) .bak系や未使用ユーティリティの削除(参照有無をrgで確認)- SFC cascade は ENV でのみ有効(既定 OFF の確認)
- inline SLL pop 常用呼び出しを封印(
- Refill 一本化の明文化
ss_refill_fc_fill()を唯一の補充入口に昇格(コメントと呼び出し点整理)- Front‑Direct 時は SLL/TLS List を通らないことをコード上明示
- 128/256 専用ショートパスの薄化(FC 命中率 UP)
- C0–C3: QuickSlot→FC→(必要時のみ)直補充→FC 再ポップ
- C4–C7: FC→(必要時のみ)直補充→FC 再ポップ
- 本体の簡素化(500 行目安)
- front*/refill*/box* への分割を継続、入口/出口の箱のみ本体に残す
ベンチの推奨プリセット(再起動後の確認用)
HAKMEM_BENCH_FAST_FRONT=1 \
HAKMEM_TINY_FRONT_DIRECT=1 \
HAKMEM_TINY_REFILL_BATCH=1 \
HAKMEM_TINY_P0_DIRECT_FC_ALL=1 \
HAKMEM_TINY_REFILL_COUNT_HOT=256 \
HAKMEM_TINY_REFILL_COUNT_MID=96 \
HAKMEM_TINY_BUMP_CHUNK=256
備考: 既存の SLL 由来 SEGV は Front‑Direct 経路で回避済。SLL 経路は当面合流専用に後退配置し、常用経路からは外す。
備考(計測メモ)
- Phase 0/1 の改善で ~10M→~15M。Front-Direct 単体はブレが増え安定増速せず(既定 OFF)。
- 次は FC 命中率を上げる配分とリフィル簡素化で 30–60M を狙う。