Files
hakmem/docs/archive/TINY_LEARNING_LAYER.md

244 lines
13 KiB
Markdown
Raw Normal View History

Wrap debug fprintf in !HAKMEM_BUILD_RELEASE guards (Release build optimization) ## Changes ### 1. core/page_arena.c - Removed init failure message (lines 25-27) - error is handled by returning early - All other fprintf statements already wrapped in existing #if !HAKMEM_BUILD_RELEASE blocks ### 2. core/hakmem.c - Wrapped SIGSEGV handler init message (line 72) - CRITICAL: Kept SIGSEGV/SIGBUS/SIGABRT error messages (lines 62-64) - production needs crash logs ### 3. core/hakmem_shared_pool.c - Wrapped all debug fprintf statements in #if !HAKMEM_BUILD_RELEASE: - Node pool exhaustion warning (line 252) - SP_META_CAPACITY_ERROR warning (line 421) - SP_FIX_GEOMETRY debug logging (line 745) - SP_ACQUIRE_STAGE0.5_EMPTY debug logging (line 865) - SP_ACQUIRE_STAGE0_L0 debug logging (line 803) - SP_ACQUIRE_STAGE1_LOCKFREE debug logging (line 922) - SP_ACQUIRE_STAGE2_LOCKFREE debug logging (line 996) - SP_ACQUIRE_STAGE3 debug logging (line 1116) - SP_SLOT_RELEASE debug logging (line 1245) - SP_SLOT_FREELIST_LOCKFREE debug logging (line 1305) - SP_SLOT_COMPLETELY_EMPTY debug logging (line 1316) - Fixed lock_stats_init() for release builds (lines 60-65) - ensure g_lock_stats_enabled is initialized ## Performance Validation Before: 51M ops/s (with debug fprintf overhead) After: 49.1M ops/s (consistent performance, fprintf removed from hot paths) ## Build & Test ```bash ./build.sh larson_hakmem ./out/release/larson_hakmem 1 5 1 1000 100 10000 42 # Result: 49.1M ops/s ``` Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 13:14:18 +09:00
# Tiny Learning Layer & Backend Integration (Phase 27 Snapshot)
> **⚠️ ARCHIVE NOTICE (2025-11-26)**
> Several ENV variables and files referenced in this document were removed in commit 6b791b97d:
> - `HAKMEM_TINY_ULTRA_FRONT` (deleted)
> - `HAKMEM_TINY_ULTRA_L0` (deleted)
> - `HAKMEM_TINY_ULTRA_HEAP_DUMP` (deleted)
> - `HAKMEM_TINY_ULTRA_PAGE_DUMP` (deleted)
> - `HAKMEM_TINY_BG_REMOTE` (deleted)
> - `HAKMEM_TINY_BG_REMOTE_BATCH` (deleted)
> - Files deleted: `core/front/tiny_ultrafront.h`, `core/ultra/tiny_ultra_heap.c`, `core/ultra/tiny_ultra_page_arena.c`
>
> This document is kept for historical reference but may contain outdated information.
**Date**: 2025-11-21
**Scope**: Tiny (01KB) / Shared Superslab Pool / FrozenPolicy / Ultra* Boxes
Wrap debug fprintf in !HAKMEM_BUILD_RELEASE guards (Release build optimization) ## Changes ### 1. core/page_arena.c - Removed init failure message (lines 25-27) - error is handled by returning early - All other fprintf statements already wrapped in existing #if !HAKMEM_BUILD_RELEASE blocks ### 2. core/hakmem.c - Wrapped SIGSEGV handler init message (line 72) - CRITICAL: Kept SIGSEGV/SIGBUS/SIGABRT error messages (lines 62-64) - production needs crash logs ### 3. core/hakmem_shared_pool.c - Wrapped all debug fprintf statements in #if !HAKMEM_BUILD_RELEASE: - Node pool exhaustion warning (line 252) - SP_META_CAPACITY_ERROR warning (line 421) - SP_FIX_GEOMETRY debug logging (line 745) - SP_ACQUIRE_STAGE0.5_EMPTY debug logging (line 865) - SP_ACQUIRE_STAGE0_L0 debug logging (line 803) - SP_ACQUIRE_STAGE1_LOCKFREE debug logging (line 922) - SP_ACQUIRE_STAGE2_LOCKFREE debug logging (line 996) - SP_ACQUIRE_STAGE3 debug logging (line 1116) - SP_SLOT_RELEASE debug logging (line 1245) - SP_SLOT_FREELIST_LOCKFREE debug logging (line 1305) - SP_SLOT_COMPLETELY_EMPTY debug logging (line 1316) - Fixed lock_stats_init() for release builds (lines 60-65) - ensure g_lock_stats_enabled is initialized ## Performance Validation Before: 51M ops/s (with debug fprintf overhead) After: 49.1M ops/s (consistent performance, fprintf removed from hot paths) ## Build & Test ```bash ./build.sh larson_hakmem ./out/release/larson_hakmem 1 5 1 1000 100 10000 42 # Result: 49.1M ops/s ``` Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 13:14:18 +09:00
**Goal**: 学習層FrozenPolicy / Learnerを活かして、Tiny の backend を「自動でそれなりに最適」な状態に保つための箱と境界を整理する。
---
## 1. Box TopologyTiny 向けの学習レイヤ構成)
- **Box SP-SLOT (SharedSuperSlabPool)**
- ファイル: `core/hakmem_shared_pool.{h,c}`, `core/superslab/superslab_types.h`
- 役割:
- Tiny クラス 0..7 向けの Superslab を **共有プール**として管理per-class SuperSlabHead legacy を徐々に退役)。
- Slot state: `SLOT_UNUSED / SLOT_ACTIVE / SLOT_EMPTY` を per-slab で追跡。
- 主要フィールド:
- `_Atomic uint64_t g_sp_stage1_hits[cls]` … EMPTY 再利用 (Stage1)
- `_Atomic uint64_t g_sp_stage2_hits[cls]` … UNUSED claim (Stage2)
- `_Atomic uint64_t g_sp_stage3_hits[cls]` … 新規 SuperSlab (Stage3)
- `uint32_t class_active_slots[TINY_NUM_CLASSES_SS]` … クラス別 ACTIVE slot 数
- 主要 API:
- `shared_pool_acquire_slab(int class_idx, SuperSlab** ss, int* slab_idx)`
- `shared_pool_release_slab(SuperSlab* ss, int slab_idx)`
- ENV:
- `HAKMEM_SHARED_POOL_STAGE_STATS=1`
→ プロセス終了時に Stage1/2/3 の breakdown を 1 回だけダンプ。
- **Box TinySuperslab Backend Box (`hak_tiny_alloc_superslab_box`)**
- ファイル: `core/hakmem_tiny_superslab.{h,c}`
- 役割:
- Tiny frontUnified / UltraHeap / TLSから Superslab backend への **唯一の出入口**
- shared backend / legacy backend / hint Box を 1 箇所で切り替える。
- Backend 実装:
- `hak_tiny_alloc_superslab_backend_shared(int class_idx)`
→ Shared Pool / SP-SLOT 経由。
- `hak_tiny_alloc_superslab_backend_legacy(int class_idx)`
→ 旧 `SuperSlabHead` ベース回帰・fallback 用)。
- `hak_tiny_alloc_superslab_backend_hint(int class_idx)`
→ legacy に落ちる前に、直近の (ss, slab_idx) を 1 回だけ再利用する軽量 Box。
- ENV:
- `HAKMEM_TINY_SS_SHARED=0`
→ 強制 legacy backend のみ。
- `HAKMEM_TINY_SS_LEGACY_FALLBACK=0`
→ shared 失敗時にも legacy を使わない(完全 Unified モード)。
- `HAKMEM_TINY_SS_C23_UNIFIED=1`
**C2/C3 だけ legacy fallback を無効化**(他クラスは従来どおり shared+legacy
- `HAKMEM_TINY_SS_LEGACY_HINT=1`
→ shared 失敗 → legacy の間に hint Box を挟む。
- **Box FrozenPolicy / Learner学習層**
- ファイル: `core/hakmem_policy.{h,c}`, `core/hakmem_learner.c`
- 役割:
- Mid/Large で実績がある CAP/W_MAX 調整ロジックを Tiny に拡張する足場。
- Tiny 向けフィールド:
- `uint16_t tiny_cap[8]; // classes 0..7`
→ Shared Pool の「クラス別 ACTIVE slot 上限」soft cap
- Tiny CAP デフォルトPhase 27 時点):
- `{2048, 1024, 96, 96, 256, 256, 128, 64}`
→ C2/C3 は Shared Pool 実験対象として 96/96 に設定。
- ENV:
- `HAKMEM_CAP_TINY=2048,1024,96,96,256,256,128,64`
→ 先頭から 8 個を `tiny_cap[0..7]` に上書き。
- **Box UltraPageArenaTiny→Page 層の観察箱)**
- ファイル: `core/ultra/tiny_ultra_page_arena.{h,c}`
- 役割:
- `superslab_refill(int class_idx)` をフックし、クラス別の Superslab refill 回数をカウント。
- API:
- `tiny_ultra_page_on_refill(int class_idx, SuperSlab* ss)`
- `tiny_ultra_page_stats_snapshot(uint64_t refills[8], int reset)`
- ENV:
- `HAKMEM_TINY_ULTRA_PAGE_DUMP=1`
→ 終了時に `[ULTRA_PAGE_STATS]` を 1 回だけダンプ。
---
## 2. 学習ループに見せるメトリクス
Tiny 学習層が見るべきメトリクスと取得元:
- **Active Slot / CAP 関連**
- `g_shared_pool.class_active_slots[class]`
→ クラス別 ACTIVE slot 数Shared Pool 管理下)。
- `FrozenPolicy.tiny_cap[class]`
→ soft cap。`shared_pool_acquire_slab` Stage3 で `cur >= cap` なら **新規 Superslab 拒否**
- **Acquire Stage 内訳**
- `g_sp_stage1_hits[class]` … Stage1 (EMPTY slot 再利用)
- `g_sp_stage2_hits[class]` … Stage2 (UNUSED slot claim)
- `g_sp_stage3_hits[class]` … Stage3 (新規 SuperSlab / LRU pop)
- これらの合算から:
- Stage3 割合が高い → Superslab churn が多い、CAP/Precharge/LRU を増やす候補。
- Stage1 が長期間 0% → EMPTY スロットがほぼ生成されていないfree 側のポリシー改善候補)。
- **Page 層イベント**
- `TinyUltraPageStats.superslab_refills[cls]`
→ クラス別の refill 回数。Tiny front から見た「page 層イベントの多さ」を測る。
---
## 3. 現状のポリシーと挙動Phase 27
### 3.1 Shared Pool backend 選択
`hak_tiny_alloc_superslab_box(int class_idx)` のポリシー:
1. `HAKMEM_TINY_SS_SHARED=0` のとき:
- 常に legacy backend (`hak_tiny_alloc_superslab_backend_legacy`) のみを使用。
2. shared 有効時:
- 基本経路:
- `p = hak_tiny_alloc_superslab_backend_shared(class_idx);`
- `p != NULL` ならそのまま返す。
- fallback 判定:
- `HAKMEM_TINY_SS_LEGACY_FALLBACK=0`
→ shared 失敗でも legacy へは落とさず、そのまま `NULL` 許容(完全 Unified モード)。
- `HAKMEM_TINY_SS_C23_UNIFIED=1`
→ C2/C3 の場合に限り `legacy_fallback=0` に上書き(他クラスは `g_ss_legacy_fallback` に従う)。
- hint Box:
- shared 失敗 & fallback 許可時に限り:
- `hak_tiny_alloc_superslab_backend_hint(class_idx)` を 1 回だけ試す。
- 直近成功した `(ss, slab_idx)` がまだ `used < capacity` なら、そこから 1 ブロックだけ追加 carve。
### 3.2 FrozenPolicy.tiny_cap と Shared Pool の連携
- `shared_pool_acquire_slab()` Stage3新規 Superslab 確保)直前に:
```c
uint32_t limit = sp_class_active_limit(class_idx); // = tiny_cap[class]
uint32_t cur = g_shared_pool.class_active_slots[class_idx];
if (limit > 0 && cur >= limit) {
return -1; // Soft cap reached → caller 側で legacy fallback or NULL
}
```
- 意味:
- `tiny_cap[class]==0` → 制限なし(無限に Superslab を増やせる)。
- `>0` → ACTIVE slot 数が cap に達したら **新規 SuperSlab を増やさない**churn 制御)。
現状のデフォルト:
- `{2048,1024,96,96,256,256,128,64}`
- C2/C3 を 96 に抑えつつ、C4/C5 は 256 slots まで許容。
- ENV `HAKMEM_CAP_TINY` で一括上書き可能。
### 3.3 C2/C3 限定「ほぼ完全 Unified」実験
- `HAKMEM_TINY_SS_C23_UNIFIED=1` のとき:
- C2/C3:
- shared backend のみで運転(`legacy_fallback=0`)。
- Shared Pool から Superslab/slab が取れなかった場合は `NULL` を返し、上位が UltraFront/TinyFront 経路にフォールバック。
- 他クラス:
- 従来どおり shared+legacy fallback。
- Random Mixed 256B / 200K / ws=256 での挙動:
- デフォルト設定C2/C3 cap=96: ≈16.8M ops/s 前後。
- `HAKMEM_TINY_SS_C23_UNIFIED=1` の有無で差は ±数% レベル(ランダム揺らぎ内)。
- OOM / SEGV は観測されず、C2/C3 を Shared Pool 単独で回す足場としては安定。
---
## 4. 「学習層を活かす」ための次ステップTiny 向け)
今ある土台を使って、学習層を Tiny に伸ばすときの具体的なステップと現状:
1. **Learner に Tiny メトリクスを配線(済)**
- `core/hakmem_learner.c` に Tiny 専用メトリクスを追加済み:
- `active_slots[class] = g_shared_pool.class_active_slots[class];`
- `stage3_ratio[class] = ΔStage3 / (ΔStage1+ΔStage2+ΔStage3);`
- `refills[class] = tiny_ultra_page_global_stats_snapshot()` から取得。
2. **tiny_cap[] のヒルクライム調整(実装済み/チューニング中)**
- 各 Tiny クラスごとに、ウィンドウ内の Stage3 割合を監視:
- Stage3 が多すぎ(新規 SuperSlab が頻発) → `tiny_cap[class]` を +Δ。
- Stage3 が少ない & ACTIVE slot が少ない → `tiny_cap[class]` を -Δ。
- cap の下限は `max(min_tiny, active_slots[class])` にクリップし、
既に確保済みの Superslab を急に「上限超過」にしないようにしている。
- 調整後は `hkm_policy_publish()` で新しい FrozenPolicy を公開。
3. **PageArena / Precharge / Cache との連携TinyPageAuto, 実験中)**
- UltraPageArena / SP-SLOT / PageFaultTelemetry からのメトリクスを使って、Superslab OS キャッシュprecharge を軽く制御:
- `HAKMEM_TINY_PAGE_AUTO=1` のとき、Learner が各ウィンドウで
- `refills[class]`UltraPageArena の Superslab refill 数, C2〜C5
- PageFaultTelemetry の `PF_pages(C2..C5)` および `PF_pages(SSM)` を読み取り、
- `score = refills * PF_pages(Cn) + PF_pages(SSM)/8` を計算。
- スコアが `HAKMEM_TINY_PAGE_MIN_REFILLS * HAKMEM_TINY_PAGE_PRE_MIN_PAGES` 以上のクラスだけに対して:
- `tiny_ss_precharge_set_class_target(class, target)`(既定 target=1で precharge を有効化。
- `tiny_ss_cache_set_class_cap(class, cap)`(既定 cap=2で OS Superslab キャッシュ枚数を small cap に設定。
- スコアがしきい値未満のクラスは `target=0, cap=0` に戻して OFF。
- これにより、Tiny 側から見て Superslab 層の「refill + PF が重いクラスだけ少数の Superslab を先行 fault-in / 温存」する挙動を学習層から制御できる状態まで到達している(まだパラメータ調整段階)。
4. **Near-Empty しきい値の学習統合C2/C3**
- Box: `TinyNearEmptyAdvisor``core/box/tiny_near_empty_box.{h,c}`
- free パスで C2/C3 の `TinySlabMeta.used/cap` から「near-empty slab」を検出し、イベント数を集計。
- ENV:
- `HAKMEM_TINY_SS_PACK_C23=1` … near-empty 観測 ON。
- `HAKMEM_TINY_NEAREMPTY_PCT=P` … 初期しきい値 (%), 1〜99, 既定 25。
- `HAKMEM_TINY_NEAREMPTY_DUMP=1` … 終了時に `[TINY_NEAR_EMPTY_STATS]` を 1 回ダンプ。
- Learner 側からの自動調整:
- `HAKMEM_TINY_NEAREMPTY_AUTO=1` のとき、
- ウィンドウ内で near-empty イベントC2/C3 合計)が 0 の場合:
- しきい値 P を `+STEP` だけ緩めるP_MAX まで、STEP 既定 5
- near-empty イベントが多すぎる(例: 128 以上)の場合:
- P を `-STEP` だけ締めるP_MIN まで)。
- P_MIN/P_MAX/STEP はそれぞれ
- `HAKMEM_TINY_NEAREMPTY_PCT_MIN`(既定 5
- `HAKMEM_TINY_NEAREMPTY_PCT_MAX`(既定 80
- `HAKMEM_TINY_NEAREMPTY_PCT_STEP`(既定 5
で上書き可能。
- Random Mixed / Larson では near-empty イベント自体がほとんど発生しておらず、
現状は P がゆるやかに上限側へ寄るだけ(挙動への影響はごく小さい)。
5. **総合スコアでの最適化**
- 1 ベンチ(例: Random Mixed 256Bではなく:
- Fixed-size Tiny
- Random Mixed 各サイズ
- Larson / Burst / Apps 系
をまとめたスコア(平均 ops/s + メモリフットプリント + page faultに対して、
- Tiny/Learning 層が CAP/Precharge/Cache を少しずつ動かすイメージ。
---
## 6. 既知の制限と安全策
- 8192B Random Mixed で発生していた TLS SLL head=0x60 問題は:
- `tls_sll_pop()` 内で head が低アドレスの場合に、そのクラスの SLL をリセットし slow path に逃がす形で **箱の内側で Fail-Fast** させるように修正済み。
- これにより、長尺ベンチでも SEGV せずに回し続けられる。
- `tiny_nextptr.h``tiny_next_store()` には軽いガードを入れ、
- `next` が 0 以外かつ `<0x1000` / `>0x7fff...` の場合に 1 回だけ `[NEXTPTR_GUARD]` を出すようにしてある(観測専用)。
- 現時点の観測では C4 で一度だけ `next=0x47` が記録されており、freelist/TLS 経路のどこかに残存バグがあることは認識済み。
- ただし Fail-Fast により箱の内側でリセットされるため、外側の挙動(ベンチ・アプリ)は安定している。
将来的に「完全退治」まで進める場合は、Tiny 向け debug ビルド構成を整えたうえで
`NEXTPTR_GUARD` の call site を `addr2line` などで特定し、当該経路をピンポイントに修正する予定。