156 lines
8.9 KiB
Markdown
156 lines
8.9 KiB
Markdown
|
|
# 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 評価の“共通言語”です。新しい最適化や経路を足す前に、まず箱と境界を設計してから手を動かしましょう。
|
|||
|
|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 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 / Don’t(壊れやすいパターンの禁止)
|
|||
|
|
- Don’t: Remote Queue から publish を直接呼ばない条件分岐を増やす(通知の濫用)。
|
|||
|
|
- Don’t: publish 側で drain / owner をいじる。
|
|||
|
|
- Do: Remote Queue は push と count 更新のみ。publish は通知のみ。採用境界で drain/bind/owner を一度に行う。
|
|||
|
|
|
|||
|
|
デバッグ・トリアージ順序(Fail‑Fast)
|
|||
|
|
1) Box 2(Remote)単体: push→drain→freelist の整合をアサート(範囲検証 ON, `remote_counts` 符合)。
|
|||
|
|
2) Box 3(Ownership)単体: `owner_tid==0` からの acquire/release を並行で連続試験。
|
|||
|
|
3) Box 4(Publish/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` を採用境界前後に記録。
|
|||
|
|
- Env(A/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/リングとワンショットログで芯を掴んでから上に進む。
|