121 lines
3.7 KiB
Markdown
121 lines
3.7 KiB
Markdown
|
|
# Phase 15: UnifiedCache FIFO→LIFO (Stack) v1 Design
|
|||
|
|
|
|||
|
|
**Date:** 2025-12-15
|
|||
|
|
**Status:** DESIGN (next candidate)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 0. Motivation (Why this next?)
|
|||
|
|
|
|||
|
|
Phase 14(intrusive tcache)v1/v2 は通電確認まで行ったが **NEUTRAL**。
|
|||
|
|
一方で system/mimalloc と比べると、Tiny の thread cache 形状は依然として最重要仮説のまま。
|
|||
|
|
|
|||
|
|
現行の `TinyUnifiedCache` は **FIFO ring (head/tail + mask)**:
|
|||
|
|
- pop/push が毎回 `head/tail` と `mask` の更新を行う
|
|||
|
|
- “最近 free したブロック” を最優先で再利用できない(局所性が薄い)
|
|||
|
|
|
|||
|
|
glibc tcache / mimalloc 系の勝ちパターンは **LIFO** が多い。
|
|||
|
|
Phase 15 は intrusive(nextptr)を増やさず、既存 `slots[]` 配列をそのまま使って
|
|||
|
|
**FIFO→LIFO(stack)**へ形状変更し、命令数・局所性の両方で勝ち筋を狙う。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Design (Box Theory)
|
|||
|
|
|
|||
|
|
### 1.1 Boxes
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
L0: unified_cache_shape_env_box (ENV gate, reversible)
|
|||
|
|
↓
|
|||
|
|
L1: unified_cache_lifo_box (push/pop LIFO only, no side effects)
|
|||
|
|
↓
|
|||
|
|
L2: existing unified_cache (FIFO) (fallback / compatibility)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**境界は 1 箇所**:
|
|||
|
|
- LIFO disabled → FIFO を使う
|
|||
|
|
- LIFO enabled → LIFO を使う
|
|||
|
|
|
|||
|
|
(実装上は “同一関数内で分岐” になる可能性があるが、責務は箱で分ける)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. API (minimal)
|
|||
|
|
|
|||
|
|
ENV:
|
|||
|
|
- `HAKMEM_TINY_UNIFIED_LIFO=0/1` (default 0, opt-in)
|
|||
|
|
|
|||
|
|
L1 API(内部用、static inline):
|
|||
|
|
- `unified_cache_pop_lifo(int class_idx) -> BASE or NULL`
|
|||
|
|
- `unified_cache_push_lifo(int class_idx, BASE) -> 1/0`
|
|||
|
|
|
|||
|
|
統合点(候補):
|
|||
|
|
- `tiny_hot_alloc_fast()` / `tiny_hot_free_fast()`
|
|||
|
|
- ここが “実ホットパス” で、FIFO/LIFO の差分を最も素直に測れる
|
|||
|
|
- もしくは `unified_cache_pop()` / `unified_cache_push()`
|
|||
|
|
- 既存 caller を増やさず広く効かせたい場合
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Implementation sketch (concept)
|
|||
|
|
|
|||
|
|
### 3.1 LIFO state
|
|||
|
|
|
|||
|
|
`TinyUnifiedCache` に `top` を追加するのではなく、v1 では互換性優先:
|
|||
|
|
- 既存の `head/tail` のうち **`tail` を “top” とみなす**(stack depth)
|
|||
|
|
- `head` は常に 0(または未使用)
|
|||
|
|
- `mask` は不要(wrap-around しない)
|
|||
|
|
|
|||
|
|
LIFO push:
|
|||
|
|
- if `tail < capacity`: `slots[tail++] = base`
|
|||
|
|
|
|||
|
|
LIFO pop:
|
|||
|
|
- if `tail > 0`: `base = slots[--tail]`
|
|||
|
|
|
|||
|
|
(FIFO とは並立できないため、モード切替時の整合は “drain/reset” を境界に置く)
|
|||
|
|
|
|||
|
|
### 3.2 Mode switch safety (Fail-Fast)
|
|||
|
|
|
|||
|
|
- LIFO ON へ切り替える際は `unified_cache_init()` 後に **各 class の `head/tail` を reset**(empty扱い)
|
|||
|
|
- bench/profile では init 前に ENV が確定する前提だが、研究箱として “refresh” を持つなら
|
|||
|
|
- refresh 時は切替を禁止(または drain/reset を強制)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. A/B Plan (same binary)
|
|||
|
|
|
|||
|
|
Baseline:
|
|||
|
|
```sh
|
|||
|
|
HAKMEM_TINY_UNIFIED_LIFO=0 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Optimized:
|
|||
|
|
```sh
|
|||
|
|
HAKMEM_TINY_UNIFIED_LIFO=1 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
追加で “局所性が効くか” を確認:
|
|||
|
|
```sh
|
|||
|
|
HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_UNIFIED_LIFO=0 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_UNIFIED_LIFO=1 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
GO/NO-GO:
|
|||
|
|
- GO: Mixed mean +1.0% 以上
|
|||
|
|
- NO-GO: mean -1.0% 以下
|
|||
|
|
- NEUTRAL: ±1.0%(freeze)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Risks
|
|||
|
|
|
|||
|
|
1) **mode 分岐の固定費**で相殺(Phase 11/14 の再来)
|
|||
|
|
→ 対策: “入口で 1 回だけ” 判定し、hot では分岐を増やさない(関数ポインタ or snapshot)
|
|||
|
|
|
|||
|
|
2) **切替時の整合**(FIFO state と LIFO state の互換なし)
|
|||
|
|
→ 対策: refresh 時の切替は禁止 or drain/reset を境界 1 箇所に固定
|
|||
|
|
|
|||
|
|
3) **容量チューニング依存**
|
|||
|
|
→ v1 はまず形状のみを変えて ROI を確認し、cap 探索は v2 へ分離
|
|||
|
|
|