Implementation:
- Intrusive LIFO tcache layer (L1) before UnifiedCache
- TLS per-class bins (head pointer + count)
- Intrusive next pointers (via tiny_next_store/load SSOT)
- Cap: 64 blocks per class (default)
- ENV: HAKMEM_TINY_TCACHE=0/1 (default: 0, OFF)
A/B Test Results (Mixed 10-run):
- Baseline (TCACHE=0): 51,083,379 ops/s
- Optimized (TCACHE=1): 51,186,838 ops/s
- Mean delta: +0.20% (below +1.0% GO threshold)
- Median delta: +0.59%
Verdict: NEUTRAL - Freeze as research box (default OFF)
Root Cause (v1 wiring incomplete):
- Free side pushes to tcache via unified_cache_push()
- Alloc hot path (tiny_hot_alloc_fast) doesn't consume tcache
- tcache becomes "sink" without alloc-side pop → ROI not measurable
Files:
- Created: core/box/tiny_tcache_{env_box,box}.h, tiny_tcache_env_box.c
- Modified: core/front/tiny_unified_cache.h (integration)
- Modified: core/bench_profile.h (refresh sync)
- Modified: Makefile (build integration)
- Results: docs/analysis/PHASE14_POINTER_CHASE_REDUCTION_1_AB_TEST_RESULTS.md
- v2 Instructions: docs/analysis/PHASE14_POINTER_CHASE_REDUCTION_2_NEXT_INSTRUCTIONS.md
Next: Phase 14 v2 (connect tcache to tiny_front_hot_box alloc/free hot path)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
5.7 KiB
Phase 14: Pointer-Chase Reduction v1(Tiny tcache-style intrusive LIFO)
Date: 2025-12-14
Status: DESIGN(Phase 14 kickoff)
0. Executive Summary(1枚)
Phase 12 の gap 仮説のうち:
- Header write tax → Phase 13 v1 / E5-2 の範囲では NEUTRAL(決定打にならない)
次の高 ROI 候補は thread cache / pointer-chase / “tcache 相当の構造差”。
現状の Tiny frontend は TinyUnifiedCache(配列 + head/tail の FIFO)を多用しており、
- pointer indirection(
cache->slots参照) - FIFO による “古いブロック再利用”(局所性低下)
- 操作あたりの命令数(full/empty 判定 + index 更新)
が system malloc(glibc tcache: intrusive LIFO)に比べて不利になり得る。
Phase 14 v1 は Box Theory を維持したまま、TinyUnifiedCache の前段に “intrusive LIFO tcache” を 1 層追加する:
- hit 時: head pointer + block 内 next だけで完結(配列アクセス無し)
- miss / overflow 時: 既存の UnifiedCache(配列)へフォールバック(境界 1 箇所)
1. 現状(why)
1.1 現行の主要ホット
Phase 10 以降の統合で front_fastlane_try_free が集約点になっている(consolidation 成功)。
その中で “legacy fallback” が unified_cache_push/pop に寄るため、TinyUnifiedCache の形状が ROI に直結する。
1.2 UnifiedCache の現行形状
core/front/tiny_unified_cache.h:slots(ヒープ確保配列)+head/tail(FIFO)- push/pop で配列アクセスが必ず発生
対して glibc tcache は:
- per-bin head pointer(intrusive LIFO)
- small count(上限)だけ
2. 提案(Phase 14 v1)
2.1 追加する箱(Box Theory)
L0: tiny_tcache_env_box (ENV gate, refresh, rollback)
↓
L1: tiny_tcache_box (intrusive LIFO: push/pop, cap, minimal stats)
↓
L2: tiny_unified_cache_box (既存: array cache)
境界は 1 箇所:
tiny_tcache_try_*()が fail したら 既存 unified_cache_*() に落とすだけ。
2.2 API(最小)
// core/box/tiny_tcache_env_box.h
int tiny_tcache_enabled(void); // ENV: HAKMEM_TINY_TCACHE=0/1 (default 0)
uint16_t tiny_tcache_cap(void); // ENV: HAKMEM_TINY_TCACHE_CAP (default 64, pow2不要)
void tiny_tcache_env_refresh_from_env(void);// bench_profile putenv 同期用
// core/box/tiny_tcache_box.h
bool tiny_tcache_try_push(int class_idx, void* base); // handled?
void* tiny_tcache_try_pop(int class_idx); // BASE or NULL
実装は tiny_next_store/load() に委譲して next layout を SSOT 化する(Phase 13 の教訓を踏襲)。
2.3 統合点(最小改造で ROI を出す)
Phase 14 v1 は “call site を増やさない” ため、統合点は unified_cache_push/pop の内部に置く。
unified_cache_push()先頭:- tcache が enabled なら
tiny_tcache_try_push()を試し、成功なら即 return(配列アクセス無し) - 失敗(cap overflow)なら既存の array push にフォールバック
- tcache が enabled なら
unified_cache_pop()先頭:- tcache が enabled なら
tiny_tcache_try_pop()を試し、成功なら即 return(配列アクセス無し) - miss なら既存の array pop にフォールバック
- tcache が enabled なら
これにより、FastLane/legacy/他経路の caller を改造せずに効果を出せる。
3. Invariants / Fail-Fast
- tcache に格納するのは BASE pointer のみ(USER は入れない)
- 一つの block は tcache or unified_cache のどちらかにしか居ない(重複禁止)
count <= capを常に守る(debug build で assert)- next pointer の読み書きは
tiny_next_store/loadのみ(直書き禁止)
Fail-fast(debug のみ):
- cap overflow をワンショットで記録(必要なら stats)
baseが怪しい値(<4096 等)の場合 abort(既存 guard パターン)
4. A/B 計測計画(同一バイナリ)
ENV:
HAKMEM_TINY_TCACHE=0/1(default 0)HAKMEM_TINY_TCACHE_CAP=64(研究用、必要なら)
ベンチ:
- Mixed:
scripts/run_mixed_10_cleanenv.sh - 追加: C6-heavy 5-run(回帰がないこと)
GO/NO-GO:
- GO: mean +1.0% 以上
- NO-GO: mean -1.0% 以下
- NEUTRAL: ±1.0% → freeze
5. リスクと対策
リスク 1: 追加 branch の固定費が勝つ(Phase 11 の再来)
対策:
- env gate は cached read(getenv を hot path に置かない)
unified_cache_push/pop内の “1回だけ if” に限定(call site helper を増やさない)
リスク 2: next layout の齟齬(C7/C0 など)
対策:
- next は SSOT:
tiny_next_store/loadを必須化 - C7 preserve header の research knob とは独立(Phase 13 v1 は freeze)
リスク 3: tcache が大きすぎて locality を壊す
対策:
- v1 は cap=64 をデフォルト(glbic tcache 相当)
- cap の探索は research knob として後段で行う
6. 期待値(当たり筋)
- tcache hit 率が高い場合、配列アクセス・FIFO の古い再利用を回避できる
- “system malloc が速い” の差分(tcache 的挙動)に寄せる最短の一手
Update(2025-12-15)
v1 の統合点(core/front/tiny_unified_cache.h)だけでは、現行の main alloc hot path(tiny_hot_alloc_fast())が tcache を消費しないため、
HAKMEM_TINY_TCACHE=1 のとき tcache が “sink” になりやすい。
次は hot path(core/box/tiny_front_hot_box.h)へ pop/push を接続して、通電した状態で再 A/B を取る(Phase 14 v2):
docs/analysis/PHASE14_POINTER_CHASE_REDUCTION_2_NEXT_INSTRUCTIONS.md