Files
hakmem/AGENTS.md
Moe Charm (CI) 0546454168 WIP: Add TLS SLL validation and SuperSlab registry fallback
ChatGPT's diagnostic changes to address TLS_SLL_HDR_RESET issue.
Current status: Partial mitigation, but root cause remains.

Changes Applied:
1. SuperSlab Registry Fallback (hakmem_super_registry.h)
   - Added legacy table probe when hash map lookup misses
   - Prevents NULL returns for valid SuperSlabs during initialization
   - Status:  Works but may hide underlying registration issues

2. TLS SLL Push Validation (tls_sll_box.h)
   - Reject push if SuperSlab lookup returns NULL
   - Reject push if class_idx mismatch detected
   - Added [TLS_SLL_PUSH_NO_SS] diagnostic message
   - Status:  Prevents list corruption (defensive)

3. SuperSlab Allocation Class Fix (superslab_allocate.c)
   - Pass actual class_idx to sp_internal_allocate_superslab
   - Prevents dummy class=8 causing OOB access
   - Status:  Root cause fix for allocation path

4. Debug Output Additions
   - First 256 push/pop operations traced
   - First 4 mismatches logged with details
   - SuperSlab registration state logged
   - Status:  Diagnostic tool (not a fix)

5. TLS Hint Box Removed
   - Deleted ss_tls_hint_box.{c,h} (Phase 1 optimization)
   - Simplified to focus on stability first
   - Status:  Can be re-added after root cause fixed

Current Problem (REMAINS UNSOLVED):
- [TLS_SLL_HDR_RESET] still occurs after ~60 seconds of sh8bench
- Pointer is 16 bytes offset from expected (class 1 → class 2 boundary)
- hak_super_lookup returns NULL for that pointer
- Suggests: Use-After-Free, Double-Free, or pointer arithmetic error

Root Cause Analysis:
- Pattern: Pointer offset by +16 (one class 1 stride)
- Timing: Cumulative problem (appears after 60s, not immediately)
- Location: Header corruption detected during TLS SLL pop

Remaining Issues:
⚠️ Registry fallback is defensive (may hide registration bugs)
⚠️ Push validation prevents symptoms but not root cause
⚠️ 16-byte pointer offset source unidentified

Next Steps for Investigation:
1. Full pointer arithmetic audit (Magazine ⇔ TLS SLL paths)
2. Enhanced logging at HDR_RESET point:
   - Expected vs actual pointer value
   - Pointer provenance (where it came from)
   - Allocation trace for that block
3. Verify Headerless flag is OFF throughout build
4. Check for double-offset application in conversions

Technical Assessment:
- 60% root cause fixes (allocation class, validation)
- 40% defensive mitigation (registry fallback, push rejection)

Performance Impact:
- Registry fallback: +10-30 cycles on cold path (negligible)
- Push validation: +5-10 cycles per push (acceptable)
- Overall: < 2% performance impact estimated

Related Issues:
- Phase 1 TLS Hint Box removed temporarily
- Phase 2 Headerless blocked until stability achieved

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 20:42:28 +09:00

179 lines
10 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.

# AGENTS: 箱理論Box Theory設計ガイドライン
本リポジトリでは、変更・最適化・デバッグを一貫して「箱理論Box Theory」で進めます。すべてを“箱”で分け、境界で接続し、いつでも戻せるように積み上げることで、複雑性を抑えつつ失敗コストを最小化します。
---
## 何が効くのか(実績)
- ❌ Rust/inkwell: 複雑なライフタイム管理
- ✅ 箱理論適用: 650行 → 100行SSA構築
なぜ効果があるか:
- PHI/Block/Value を「箱」として扱い、境界変換点を1箇所に集約
- 複雑な依存関係を箱の境界で切ることで単体検証が容易
- シンプルな Python/llvmlite で 2000行で完結道具に依存せず“箱”で分割して繋ぐ
補足C 実装時の利点)
- C の場合は `static inline` により箱間のオーバーヘッドをゼロに近づけられる(インライン展開)
---
## 🎯 AI協働での合言葉5原則
1. 「箱にする」: 設定・状態・橋渡しは Box 化
- 例: TLS 状態、SuperSlab adopt、remote queue などは役割ごとに箱を分離
2. 「境界を作る」: 変換は境界1箇所で
- 例: adopt → bind、remote → freelist 統合、owner 移譲などの変換点を関数1箇所に集約
3. 「戻せる」: フラグ・feature で切替可能に
- `#ifdef FEATURE_X` / 環境変数 で新旧経路を A/B 可能に(回帰や切り戻しを即時化)
4. 「見える化」: ダンプ/JSON/DOT で可視化
- 1回だけのワンショットログ、統計カウンタで“芯”を掴む常時ログは避ける
5. 「Fail-Fast」: エラー隠さず即座に失敗
- ENOMEM/整合性違反は早期に露呈させる(安易なフォールバックで隠さない)
要するに: 「すべてを箱で分けて、いつでも戻せるように積み上げる」設計哲学にゃ😺🎁
---
## 適用ガイド(このリポジトリ)
- 小さく積むBox 化)
- Remote Free Queue, Partial SS Adopt, TLS Bind/Unbind を独立した“箱”として定義
- 箱の API は最小・明確init/publish/adopt/drain/bind など)
- 境界は1箇所
- Superslab 再利用の境界は `superslab_refill()` に集約publish/adopt の接点)
- Free の境界は “same-thread / cross-thread” の判定1回
- 切替可能(戻せる)
- 新経路は `#ifdef` / 環境変数でオンオフA/B と回帰容易化)
- 例: `HAKMEM_TINY_PHASE6_ULTRA_SIMPLE``HAKMEM_DEBUG_VERBOSE``HAKMEM_TINY_*` env
- 見える化(最小限)
- 1回だけのデバッグ出力ワンショットと統計カウンタで芯を掴む
- 例: [SS OOM]、[SS REFILL] のワンショットログ、alloc/freed/bytes の瞬間値
- Fail-Fast
- ENOMEM・整合性違反はマスクせず露出。フォールバックは“停止しないための最後の手段”に限定
---
## 実装規約C向けの具体
- `static inline` を多用し箱間の呼び出しをゼロコスト化
- 共有状態は `_Atomic` で明示、CAS ループは局所化MPSC push/pop はユーティリティ化)
- 競合制御は「箱の内側」に閉じ込め、外側はシンプルに保つ
- 1つの箱に 1つの責務publish/adopt、drain、bind、owner 移譲 など)
---
## チェックリストPR/レビュー時)
- 箱の境界は明確か変換点が1箇所に集約されているか
- フラグで戻せるかA/B が即時に可能か)
- 可視化のフックは最小か(ワンショット or カウンタ)
- Fail-Fast になっているか(誤魔化しのフォールバックを入れていないか)
- C では `static inline` でオーバーヘッドを消しているか
---
この AGENTS.md は、箱理論の適用・コーディング・デバッグ・A/B 評価の“共通言語”です。新しい最適化や経路を足す前に、まず箱と境界を設計してから手を動かしましょう。
---
## Learning LayerACE / ELO / Learnerの箱化ポリシー
ACE/ELO/CAP Learner などの「学習する機能」も、Tiny や Superslab と同様に Box として扱います。
ホットパスを汚さず、いつでも FROZEN/OFF に戻せるようにすることが原則です。
- 学習は上層の箱に閉じ込める
- L0 Tiny / L1 Superslab / TLS SLL / Remote Queue は **学習ロジックを持たない**
- ELO / ACE Controller / CAP Learner は「ポリシー箱」として、ノブやしきい値だけを更新する。
- ホットパス側は「現在のポリシー値」を読むだけにし、学習の有無を意識しない。
- FROZEN / LEARN / OBSERVE を明確に分ける
- FROZEN: 学習 OFF。固定ポリシーのみ使用デフォルト運用
- LEARN: バックグラウンドでポリシー更新を行う(ベンチ / 研究用)。
- OBSERVE: Tiny などの下層の箱を「観測だけ」するモード(動作は変えない)。
- モード切り替えは `HAKMEM_MODE` / `HAKMEM_ACE_ENABLED` / `HAKMEM_LEARN` 等の ENV から行い、いつでも戻せるようにする。
- ドキュメントと設計の窓口
- 学習レイヤ全体の構造と責務は `docs/analysis/LEARNING_LAYER_OVERVIEW.md` にまとめる。
- 各学習 BoxELO / ACE Controller / CAP Learnerの詳細仕様や A/B 結果は、docs/analysis / docs/benchmarks / docs/paper 配下に箱ごとに整理する。
- AGENTS.md では「学習は必ず別箱」「ホットパスを汚さない」「ENV で切り戻せる」というルールだけを守る。
---
## Tiny 向け「積み方 v2」(層を下から固める)
下層の箱が壊れている状態で上層を積むと必ず崩れます。まず下から順に箱を“堅牢化”してから上を載せる、を徹底します。
層と責務
- Box 1: Atomic Ops (最下層)
- 役割: `stdatomic.h` による CAS/Exchange の秩序付けAcquire/Release
- ルール: メモリ順序を箱内で完結させる(外側に弱い順序を漏らさない)。
- Box 2: Remote Queue (下層)
- 役割: cross-thread free の MPSC スタックpush/exchangeとカウント管理。
- API: `ss_remote_push(ss, slab_idx, ptr) -> transitioned(0/1)``ss_remote_drain_to_freelist(ss, slab_idx)``ss_remote_drain_light(ss)`
- 不変条件 (Invariants):
- push はノードの next を書き換える以外に副作用を持たないfreelist/owner へは触れない)。
- head は SuperSlab 範囲内Fail-Fast 範囲検証)。
- `remote_counts[s]` は push/drain で単調に整合するdrain 後は 0
- 境界: freelist への統合は必ず drain 関数内1 箇所。publish/adopt からの直接 drain は禁止。
- Box 3: Ownership (中層)
- 役割: slab の所有者遷移(`owner_tid`)。
- API: `ss_owner_try_acquire(meta, tid) -> bool``owner_tid==0` の時のみ CAS で取得)、`ss_owner_release(meta, tid)``ss_owner_is_mine(meta, tid)`
- 不変条件:
- Remote Queue は owner に触らないBox 2→3 への侵入禁止)。
- Acquire 成功後のみ “同一スレッド” の高速経路を使用する。
- 境界: bind 時にのみ acquire/release を行う(採用境界 1 箇所)。
- Box 4: Publish / Adopt (上層)
- 役割: 供給の提示publishと消費adopt
- API: `tiny_publish_notify(class, ss, slab)``tiny_mailbox_publish()``tiny_mailbox_fetch()``ss_partial_publish()``ss_partial_adopt()`
- 不変条件:
- publish は “通知とヒント” のみfreelist/remote/owner に触れない)。
- `ss_partial_publish()` は unsafe drain をしない。必要なら drain は採用側境界で実施。
- publish 時に `owner_tid=0` を設定してもよいが、実際の acquire は採用境界でのみ行う。
- 境界: adopt 成功直後にだけ `drain → bind → owner_acquire` を行う(順序は必ずこの 1 箇所)。
実装ガイド(境界の 1 か所化)
- Refill 経路(`superslab_refill()` / `tiny_refill_try_fast()`)でのみ:
1) sticky/hot/bench/mailbox/reg を “peek して” 候補を得る
2) 候補が見つかったら当該 slab で `ss_remote_drain_to_freelist()` を 1 回だけ実行(必要時)
3) freelist が非空であれば `tiny_tls_bind_slab()``ss_owner_try_acquire()` の順で確定
4) 確定後にのみ publish/overflow は扱う(不要な再 publish/drain はしない)
Do / Dont壊れやすいパターンの禁止
- Dont: Remote Queue から publish を直接呼ばない条件分岐を増やす(通知の濫用)。
- Dont: publish 側で drain / owner をいじる。
- Do: Remote Queue は push と count 更新のみ。publish は通知のみ。採用境界で drain/bind/owner を一度に行う。
デバッグ・トリアージ順序FailFast
1) Box 2Remote単体: push→drain→freelist の整合をアサート(範囲検証 ON, `remote_counts` 符合)。
2) Box 3Ownership単体: `owner_tid==0` からの acquire/release を並行で連続試験。
3) Box 4Publish/Adopt単体: publish→mailbox_register/fetch の通電fetch ヒット時のみ adopt を許可)。
4) 全体: adopt 境界でのみ `drain→bind→owner_acquire` を踏んでいるかリングで確認。
可視化と安全化(最小構成)
- Tiny Ring: `TINY_RING_EVENT_REMOTE_PUSH/REMOTE_DRAIN/MAILBOX_PUBLISH/MAILBOX_FETCH/BIND` を採用境界前後に記録。
- EnvA/B・切戻し:
- `HAKMEM_TINY_SS_ADOPT=1/0`publish/adopt 全体の ON/OFF
- `HAKMEM_TINY_RF_FORCE_NOTIFY=1`(初回通知の見逃し検出)
- `HAKMEM_TINY_MAILBOX_SLOWDISC(_PERIOD)`(遅延登録の発見)
- `HAKMEM_TINY_MUST_ADOPT=1`mmap 直前の採用ゲート)
最小テスト(箱単位の smoke
- Remote Queue: 同一 slab へ N 回 `ss_remote_push()``ss_remote_drain_to_freelist()``remote_counts==0` と freelist 長の一致。
- Ownership: 複数スレッドで `ss_owner_try_acquire()` の成功が 1 本だけになること、`release` 後に再取得可能。
- Publish/Mailbox: `tiny_mailbox_publish()``tiny_mailbox_fetch()` のヒットを 1 回保証。`fetch_null` のとき `used` 拡張が有効。
運用の心得
- 下層Remote/Ownershipに疑義がある間は、上層Publish/Adoptを “無理に” 積み増さない。
- 変更は常に A/B ガード付きで導入し、SIGUSR2/リングとワンショットログで芯を掴んでから上に進む。