Phase TLS-UNIFY-3: C6 intrusive freelist implementation (完成)

Implement C6 ULTRA intrusive LIFO freelist with ENV gating:
- Single-linked LIFO using next pointer at USER+1 offset
- tiny_next_store/tiny_next_load for pointer access (single source of truth)
- Segment learning via ss_fast_lookup (per-class seg_base/seg_end)
- ENV gate: HAKMEM_TINY_C6_ULTRA_INTRUSIVE_FL (default OFF)
- Counters: c6_ifl_push/pop/fallback in FREE_PATH_STATS

Files:
- core/box/tiny_ultra_tls_box.h: Added c6_head field for intrusive LIFO
- core/box/tiny_ultra_tls_box.c: Pop/push with intrusive branching (case 6)
- core/box/tiny_c6_ultra_intrusive_env_box.h: ENV gate (new)
- core/box/tiny_c6_intrusive_freelist_box.h: L1 pure LIFO (new)
- core/tiny_debug_ring.h: C6_IFL events
- core/box/free_path_stats_box.h/c: c6_ifl_* counters

A/B Test Results (1M iterations, ws=200, 257-512B):
- ENV_OFF (array): 56.6 Mop/s avg
- ENV_ON (intrusive): 57.6 Mop/s avg (+1.8%, within noise)
- Counters verified: c6_ifl_push=265890, c6_ifl_pop=265815, fallback=0

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Moe Charm (CI)
2025-12-12 16:26:42 +09:00
parent bf83612b97
commit 1a8652a91a
18 changed files with 1268 additions and 217 deletions

View File

@ -39,6 +39,7 @@ HAKMEM_BENCH_MAX_SIZE=1024
- `HAKMEM_TINY_FRONT_V3_LUT_ENABLED=1`
- `HAKMEM_MID_V3_ENABLED=1`Phase MID-V3: 257-768B, C6 only
- `HAKMEM_MID_V3_CLASSES=0x40`C6 only, C7 は ULTRA に任せる)
- `HAKMEM_MID_V35_ENABLED=0`Phase v11a-5: Mixed では MID v3.5 OFF が最速)
### 任意オプション
- stats を見たいとき:
@ -85,6 +86,8 @@ HAKMEM_POOL_V2_ENABLED=0
HAKMEM_POOL_V1_FLATTEN_ENABLED=0 # flatten は初回 OFF
HAKMEM_MID_V3_ENABLED=1 # Phase MID-V3: 257-768B, C6 only
HAKMEM_MID_V3_CLASSES=0x40 # C6 only (+11% on C6-heavy)
HAKMEM_MID_V35_ENABLED=1 # Phase v11a-5: C6-heavy で +8% 改善
HAKMEM_MID_V35_CLASSES=0x40 # C6 only (53.1M ops/s)
```
- mid_desc_lookup TLS キャッシュを試すときだけ: `HAKMEM_MID_DESC_CACHE_ENABLED=1` を上乗せ(デフォルトは OFF

View File

@ -0,0 +1,46 @@
# mimalloc Gap Summary (Phase v11b-1)
## Current Status: 2025-12-12
### Throughput Comparison (Mixed 16-1024B, ws=400, 10M iter)
| Allocator | Throughput | vs mimalloc |
|-----------|------------|-------------|
| mimalloc | 65.5M ops/s | 1.00x |
| hakmem v11b-1 | 50.7M ops/s | **0.77x** |
### Progress Summary
| Phase | Throughput | vs mimalloc | Key Change |
|-------|------------|-------------|------------|
| v11a-4 | 38.6M | 0.59x | baseline |
| v11a-5 | 45.4M | 0.69x | alloc path: single switch + C7 early-exit |
| v11b-1 | 50.7M | **0.77x** | free path: single switch + C7 early-exit |
### perf stat Comparison (Mixed 16-1024B, v11a-5 data)
| Metric | mimalloc | hakmem | Ratio |
|--------|----------|--------|-------|
| cycles | ~500M | 1.04B | 2.1x |
| instructions | ~920M | 2.2B | 2.4x |
| cache-misses | ~90K | 408K | 4.5x |
| branch-misses | ~6.3M | 14.5M | 2.3x |
### Next Target
**フロント alloc/free 両方を最適化完了。次は backend core または cache locality 改善。**
Candidates:
1. **cache locality**: cache-misses 4.5x が最大差 → TLS page prefetch, hot page reuse
2. **instructions削減**: 2.4x → inline 化, マクロ展開
3. small-object v7 の small帯 (C2-C3) 設計
### Key Insight
- alloc + free 両パスで switch (jump table) 化が有効
- フロント層の最適化だけで v11a-4 → v11b-1 で +31% 改善 (38.6M → 50.7M)
- mimalloc との差は主に cache-misses (4.5x) と instructions (2.4x)
---
**Date**: 2025-12-12
**Phase**: v11b-1 complete

View File

@ -435,4 +435,30 @@ v3 backend の so_alloc_fast/so_free_fast パスの「内部最適化」に進
**推奨**: Phase SO-BACKEND-OPT-2 は実装前に perf profile (cycles:u) で so_alloc_fast/so_free_fast を詳細計測することを推奨。
---
## Phase v11b-1: Free Path Micro-Optimization (2025-12-12)
### 変更内容
perf profile で `free_tiny_fast()` のシリアル ULTRA チェック (C7→C6→C5→C4) が 11.73% overhead を占めていることを発見。`malloc_tiny_fast()` と同様のパターンを適用:
1. **C7 ULTRA early-exit**: Policy snapshot 前に C7 判定(最頻出パスを最短化)
2. **Single switch**: route_kind[class_idx] で一発分岐jump table 生成)
3. **Dead code 削除**: 未使用の v4 チェック、重複 v7 チェックを除去
### 結果
| Workload | v11a-5 | v11b-1 | 改善 |
|----------|--------|--------|------|
| Mixed 16-1024B | 45.4M ops/s | 50.7M ops/s | **+11.7%** |
| C6-heavy | 49.1M ops/s | 52.0M ops/s | **+5.9%** |
| C6-heavy + MID v3.5 | 53.1M ops/s | 53.6M ops/s | +0.9% |
### 教訓
- alloc パス最適化 (v11a-5) と同じパターンが free パスにも有効
- シリアル if-else チェーン → switch (jump table) で大幅改善
- フロント層の分岐コストは backend より大きい(今回 +11.7% vs 想定 +1-2%
***

View File

@ -0,0 +1,177 @@
# TLS Layout Analysis (Phase v11b-1 Current State)
## Overview
現在の ULTRA TLS は **クラス別に独立した struct** が散在しており、L1D キャッシュ効率が悪い。
## TLS Structures (ULTRA C4-C7)
### 1. TinyC7UltraFreeTLS (`tiny_c7_ultra_tls_t`)
```c
typedef struct tiny_c7_ultra_tls_t {
uint16_t count; // 2B (hot)
uint16_t _pad; // 2B
void* freelist[128]; // 1024B (128 * 8)
// --- cold fields ---
uintptr_t seg_base; // 8B
uintptr_t seg_end; // 8B
tiny_c7_ultra_segment_t* seg; // 8B
void* page_base; // 8B
size_t block_size; // 8B
uint32_t page_idx; // 4B
tiny_c7_ultra_page_meta_t* page_meta; // 8B
bool headers_initialized; // 1B
} tiny_c7_ultra_tls_t;
```
| Field | Size | Total |
|-------|------|-------|
| Hot (count + freelist) | 4 + 1024 | 1028B |
| Cold (seg_base...headers_initialized) | ~53B | ~53B |
| **Total** | | **~1080B (17 cache lines)** |
### 2. TinyC6UltraFreeTLS
```c
typedef struct TinyC6UltraFreeTLS {
void* freelist[128]; // 1024B (128 * 8)
uint8_t count; // 1B
uint8_t _pad[7]; // 7B
uintptr_t seg_base; // 8B
uintptr_t seg_end; // 8B
} TinyC6UltraFreeTLS;
```
| Field | Size |
|-------|------|
| freelist | 1024B |
| count + pad | 8B |
| seg_base/end | 16B |
| **Total** | **1048B (17 cache lines)** |
### 3. TinyC5UltraFreeTLS
Same as C6: **1048B (17 cache lines)**
### 4. TinyC4UltraFreeTLS
```c
typedef struct TinyC4UltraFreeTLS {
void* freelist[64]; // 512B (64 * 8)
uint8_t count; // 1B
uint8_t _pad[7]; // 7B
uintptr_t seg_base; // 8B
uintptr_t seg_end; // 8B
} TinyC4UltraFreeTLS;
```
| Field | Size |
|-------|------|
| freelist | 512B |
| count + pad | 8B |
| seg_base/end | 16B |
| **Total** | **536B (9 cache lines)** |
### 5. SmallMidV35TlsCtx (MID v3.5)
```c
typedef struct {
void *page[8]; // 64B
uint32_t offset[8]; // 32B
uint32_t capacity[8]; // 32B
SmallPageMeta_MID_v3 *meta[8]; // 64B
} SmallMidV35TlsCtx;
```
| Field | Size |
|-------|------|
| page[8] | 64B |
| offset[8] | 32B |
| capacity[8] | 32B |
| meta[8] | 64B |
| **Total** | **192B (3 cache lines)** |
## Summary: Total TLS Footprint
| Structure | Size | Cache Lines |
|-----------|------|-------------|
| TinyC7UltraFreeTLS | 1080B | 17 |
| TinyC6UltraFreeTLS | 1048B | 17 |
| TinyC5UltraFreeTLS | 1048B | 17 |
| TinyC4UltraFreeTLS | 536B | 9 |
| SmallMidV35TlsCtx | 192B | 3 |
| **Total ULTRA (C4-C7)** | **3712B** | **~60 lines** |
## Problem Analysis
### 1. Hot Path に必要な最小フィールド
| Operation | Required Fields |
|-----------|-----------------|
| alloc (TLS hit) | count, freelist[count-1] |
| free (TLS push) | count, freelist[count], seg_base/end |
**Hot path は実質 count + head + seg_range の ~24B で済む。**
### 2. 現状の問題
1. **freelist 配列が巨大**: 各クラス 512-1024B の配列を TLS に保持
2. **クラス間で seg_base/end が重複**: C4-C7 が同一セグメント範囲なら共有可能
3. **count の配置が非統一**: C7 は先頭、C4-C6 は freelist の後ろ
4. **Cold fields が hot 領域に混在**: C7 の page_meta 等が毎回ロード
### 3. Cache Miss の原因
- alloc/free のたびに **各クラス専用の TLS struct** をアクセス
- 4 クラス × 平均 16 cache lines = **64 cache lines が L1D を争奪**
- Mixed workload では C4-C7 がランダムに切り替わり、thrashing 発生
---
## Phase TLS-UNIFY-2a: C4-C6 Unified TLS (2025-12-12)
### 実装内容
C4-C6 ULTRA の TLS を `TinyUltraTlsCtx` 1箱に統合:
```c
typedef struct TinyUltraTlsCtx {
// Hot line: counts (8B aligned)
uint16_t c4_count;
uint16_t c5_count;
uint16_t c6_count;
uint16_t _pad_count;
// Per-class segment ranges (learned on first free)
uintptr_t c4_seg_base, c4_seg_end;
uintptr_t c5_seg_base, c5_seg_end;
uintptr_t c6_seg_base, c6_seg_end;
// Per-class array magazines
void* c4_freelist[64]; // 512B
void* c5_freelist[64]; // 512B
void* c6_freelist[128]; // 1024B
} TinyUltraTlsCtx;
// Total: ~2KB per thread
```
**変更点**:
- C4/C5/C6 の TLS を 1 struct に統合
- 配列マガジン方式を維持(安全)
- C7 は別箱のまま(既に安定)
-`TinyC4/5/6UltraFreeTLS` への委譲を廃止
### A/B テスト結果
| Test | v11b-1 (Phase 1) | TLS-UNIFY-2a | Diff |
|------|------------------|--------------|------|
| Mixed 16-1024B | 8.0-8.8 Mop/s | 8.5-9.0 Mop/s | +0~5% |
| MID 257-768B | 8.5-9.0 Mop/s | 8.1-9.0 Mop/s | ±0% |
**結果**: 性能同等以上、SEGV/assert なし ✅
---
**Date**: 2025-12-12
**Phase**: TLS-UNIFY-2a completed

View File

@ -0,0 +1,158 @@
# TLS Layout Plan: Unified ULTRA TLS (Phase v11b-2 Target)
## Goal
C4-C7 ULTRA の hot path を **1 cache line (64B)** に収める。
## Design: TinyUltraTlsCtx
```c
// ============================================================================
// LINE 1: Hot fields (64B) - alloc/free hot path
// ============================================================================
typedef struct TinyUltraTlsCtx {
// Counts (8B total, padded for alignment)
uint16_t c4_count; // 2B
uint16_t c5_count; // 2B
uint16_t c6_count; // 2B
uint16_t c7_count; // 2B
// Freelist heads (32B)
void* c4_head; // 8B - next free slot for C4
void* c5_head; // 8B
void* c6_head; // 8B
void* c7_head; // 8B
// Segment range (shared across C4-C7, 16B)
uintptr_t seg_base; // 8B
uintptr_t seg_end; // 8B
// ========== LINE 1 END: 56B used, 8B spare ==========
uint64_t _hot_pad; // 8B - align to 64B
// ============================================================================
// LINE 2+: Cold fields (refill/retire, debug, stats)
// ============================================================================
// Freelist tails (for bulk push, 32B)
void* c4_tail; // 8B
void* c5_tail; // 8B
void* c6_tail; // 8B
void* c7_tail; // 8B
// Segment metadata (16B)
void* segment; // 8B - owning segment pointer
uint32_t page_idx; // 4B - current page index
uint32_t _cold_pad; // 4B
// Stats (optional, 16B)
uint64_t alloc_count; // 8B
uint64_t free_count; // 8B
} TinyUltraTlsCtx;
// Total: 128B (2 cache lines)
```
## Memory Layout
```
Offset Field Size Cache Line
------ ----- ---- ----------
0x00 c4_count 2B LINE 1 (HOT)
0x02 c5_count 2B LINE 1
0x04 c6_count 2B LINE 1
0x06 c7_count 2B LINE 1
0x08 c4_head 8B LINE 1
0x10 c5_head 8B LINE 1
0x18 c6_head 8B LINE 1
0x20 c7_head 8B LINE 1
0x28 seg_base 8B LINE 1
0x30 seg_end 8B LINE 1
0x38 _hot_pad 8B LINE 1
------ ----- ---- ----------
0x40 c4_tail 8B LINE 2 (COLD)
0x48 c5_tail 8B LINE 2
0x50 c6_tail 8B LINE 2
0x58 c7_tail 8B LINE 2
0x60 segment 8B LINE 3
0x68 page_idx 4B LINE 3
0x6C _cold_pad 4B LINE 3
0x70 alloc_count 8B LINE 3
0x78 free_count 8B LINE 3
```
## Hot Path Access Pattern
### alloc (TLS hit)
```c
static inline void* tiny_ultra_alloc_fast(TinyUltraTlsCtx* ctx, uint8_t class_idx) {
// Single cache line access
uint16_t* counts = &ctx->c4_count;
void** heads = &ctx->c4_head;
uint16_t c = counts[class_idx - 4];
if (likely(c > 0)) {
counts[class_idx - 4] = c - 1;
return heads[class_idx - 4]; // pop from linked list
}
return tiny_ultra_alloc_slow(ctx, class_idx);
}
```
### free (TLS push)
```c
static inline void tiny_ultra_free_fast(TinyUltraTlsCtx* ctx, void* ptr, uint8_t class_idx) {
// Range check (seg_base/end in same cache line)
uintptr_t p = (uintptr_t)ptr;
if (likely(p >= ctx->seg_base && p < ctx->seg_end)) {
// Push to freelist (single cache line)
void** heads = &ctx->c4_head;
uint16_t* counts = &ctx->c4_count;
*(void**)ptr = heads[class_idx - 4];
heads[class_idx - 4] = ptr;
counts[class_idx - 4]++;
return;
}
tiny_ultra_free_slow(ctx, ptr, class_idx);
}
```
## Comparison: Before vs After
| Metric | Current (v11b-1) | Unified (v11b-2) |
|--------|------------------|------------------|
| TLS size (C4-C7) | 3712B | 128B |
| Cache lines (hot) | ~60 | **1** |
| seg_base/end copies | 4 | 1 |
| count access | scattered | contiguous |
## Freelist Design: Linked List vs Array
**選択: Linked List (head/tail)**
理由:
1. **固定配列不要**: freelist[128] の 1KB を削除
2. **O(1) push/pop**: head だけで十分
3. **Bulk drain**: tail があれば一括返却可能
4. **メモリ効率**: 使用中スロットにのみリンク
トレードオフ:
- prefetch しにくい(配列なら連続アクセス可能)
- 空間局所性が落ちる可能性
→ プロファイル後に配列版も検討可能
## Implementation Notes
1. **Backward Compatibility**: 既存の TinyC*UltraFreeTLS API を維持しつつ、内部で TinyUltraTlsCtx を使う
2. **Gradual Migration**: まず C7 を新構造に移行し、効果を計測
3. **ENV Gate**: `HAKMEM_ULTRA_UNIFIED_TLS=1` で有効化
---
**Date**: 2025-12-12
**Phase**: v11b-2 planning

View File

@ -0,0 +1,268 @@
# ULTRA C6 Intrusive Freelist Design (Phase TLS-UNIFY-3)
## Overview
C6 ULTRA の TLS freelist を配列マガジン方式から intrusive LIFO 方式に移行する設計。
header は維持したまま、freed ブロックの user 先頭 8B に next ポインタを格納する。
## 1. ブロックレイアウト
### 現状 (C6 配列マガジン)
```
base[0]: header (1B, class_idx=6)
base[1..]: user data (511B usable)
TLS: void* c6_freelist[128]; // 1KB の配列
uint16_t c6_count;
```
### 提案 (C6 intrusive LIFO)
```
【Allocated block】
base[0]: header (1B, class_idx=6) ← 従来通り
base[1..]: user data (511B usable) ← 従来通り
【Freed block in TLS】
base[0]: header (1B, class_idx=6) ← 維持
base[1..8]: next pointer (8B) ← intrusive link
base[9..]: garbage / unused
TLS: void* c6_head; // LIFO head (BASE pointer)
uint16_t c6_count; // optional: for cap enforcement
```
### 設計判断
| 項目 | 選択 | 理由 |
|------|------|------|
| header | **維持** | base→user (+1)、分類ロジック、HAK_RET_ALLOC_* と整合 |
| next 位置 | user先頭 (base+1) | tiny_nextptr.h の既存パターンと一致 |
| alignment | 8B aligned | next ポインタが自然にアクセス可能 |
### C6 ページ内スロット数
```
Page size: 64 KiB = 65536B
Block size: 512B (including 1B header)
Slots/page: 65536 / 512 = 128 slots
```
## 2. C6-only ULTRA Lane API
### C6IntrusiveFreeListBox (L1 箱)
**重要**: next ポインタは必ず `tiny_next_store/load()` 経由で触る(直接 `*(void**)` 禁止)。
```c
// core/box/c6_intrusive_freelist_box.h
#include "../tiny_nextptr.h"
// C6 固定ラッパ (tiny_next_* の唯一の真実に委譲)
static inline void* c6_ifl_next_load(void* base) {
return tiny_next_load(base, 6); // off=1 (user先頭)
}
static inline void c6_ifl_next_store(void* base, void* next) {
tiny_next_store(base, 6, next); // off=1 (user先頭)
}
// Pop from intrusive LIFO
static inline void* c6_ifl_pop(void** head, uint16_t* count) {
void* base = *head;
if (base == NULL) return NULL;
*head = c6_ifl_next_load(base);
(*count)--;
return base;
}
// Push to intrusive LIFO
static inline void c6_ifl_push(void** head, uint16_t* count, void* base) {
c6_ifl_next_store(base, *head);
*head = base;
(*count)++;
}
// Check if empty
static inline bool c6_ifl_empty(void* head) {
return head == NULL;
}
```
### 新 API (v12 intrusive)
```c
// Alloc: pop from intrusive LIFO
void* c6_ultra_alloc_intrusive(void) {
TinyUltraTlsCtx* ctx = tiny_ultra_tls_ctx();
return c6_ifl_pop(&ctx->c6_head, &ctx->c6_count);
// Returns NULL if empty → caller fallbacks to slow path
}
// Free: push to intrusive LIFO
void c6_ultra_free_intrusive(void* base) {
TinyUltraTlsCtx* ctx = tiny_ultra_tls_ctx();
uintptr_t addr = (uintptr_t)base;
// Segment range check + capacity check
if (ctx->c6_seg_base != 0 &&
addr >= ctx->c6_seg_base &&
addr < ctx->c6_seg_end &&
ctx->c6_count < TINY_ULTRA_C6_CAP) {
c6_ifl_push(&ctx->c6_head, &ctx->c6_count, base);
return;
}
// Slow path: fallback to segment free
c6_ultra_free_intrusive_slow(base);
}
```
### 既存 C6 ULTRA との関係
| Phase | C6 ULTRA 方式 | ENV gate |
|-------|---------------|----------|
| v11 (現行) | 配列マガジン | `HAKMEM_C6_ULTRA_ENABLED=1` |
| v12 (新規) | intrusive LIFO | `HAKMEM_C6_ULTRA_V12=1` |
- v11 と v12 は排他 (両方ON は未定義)
- A/B テスト期間中は ENV で切り替え
- 安定後は v12 をデフォルトに昇格
## 3. 移行プラン
### Phase 1: v12 lane 実装 (別 ENV)
- `HAKMEM_C6_ULTRA_V12=1` で有効化
- 既存 C6 ULTRA (v11 配列) は `HAKMEM_C6_ULTRA_V12=0` で維持
- TinyUltraTlsCtx に `c6_head` フィールド追加 (v12用)
- Policy route で v12/v11 を分岐
### Phase 2: A/B テスト
- C6-heavy workload で v11 vs v12 を比較
- 目標: v12 が v11 と同等以上の性能
- メモリ効率: TLS サイズ削減 (1KB配列 → 8B head)
### Phase 3: v12 昇格
- v12 が安定したら `HAKMEM_C6_ULTRA_V12=1` をデフォルト化
- v11 配列方式は deprecated → 将来削除
## 4. TLS 統合との整合性
### TinyUltraTlsCtx の拡張
```c
typedef struct TinyUltraTlsCtx {
// Hot line: counts
uint16_t c4_count;
uint16_t c5_count;
uint16_t c6_count;
uint16_t _pad_count;
// Per-class segment ranges
uintptr_t c4_seg_base, c4_seg_end;
uintptr_t c5_seg_base, c5_seg_end;
uintptr_t c6_seg_base, c6_seg_end;
// C4/C5: array magazine (現状維持)
void* c4_freelist[64];
void* c5_freelist[64];
// C6: intrusive LIFO (v12)
void* c6_head; // NEW: intrusive head
// void* c6_freelist[128]; // REMOVED in v12
// or: conditional compilation で両方保持
#if HAKMEM_C6_ULTRA_V12
void* c6_head;
#else
void* c6_freelist[128];
#endif
} TinyUltraTlsCtx;
```
### C4/C5 の方針
- **当面は配列マガジン維持**
- C6 intrusive の成功を確認後、C4/C5 も検討
- C4 (128B) / C5 (256B) は next ポインタ 8B の相対オーバーヘッドが大きい
- C4: 8/128 = 6.25% overhead
- C5: 8/256 = 3.125% overhead
- C6: 8/512 = 1.56% overhead ← 最も効率的
## 5. 互換性と将来拡張
### 今回の intrusive は header を壊さない
- base[0] = header (1B) は従来通り維持
- hak_base_to_user() / hak_user_to_base() は +1/-1 のまま
- HAK_RET_ALLOC_* / HAK_BASE_FROM_RAW は変更不要
- tiny_header_* マクロは従来通り動作
- free 側の C0-C6 分類は header 読み取りで動作
### 将来: 真の headerless C6 intrusive (TLS-UNIFY-3b)
真の headerless 化を目指す場合は別フェーズで検討:
1. **lane-param 化**: `tiny_user_offset` を class ごとに可変化
- C0-C5: offset=1 (header あり)
- C6 v12b: offset=0 (headerless)
2. **ptr conversion 分岐**: `hak_base_to_user()` を lane-aware に
```c
static inline void* hak_base_to_user(void* base, int class_idx) {
int offset = (class_idx == 6 && c6_headerless_enabled()) ? 0 : 1;
return (uint8_t*)base + offset;
}
```
3. **分類境界の再設計**: headerless ブロックの class 判定
- Option A: side metadata (page header に class 記録)
- Option B: address range check (segment→class mapping)
4. **A/B テスト**: headerless C6 vs header-maintained C6
**結論**: headerless 化は大手術。今回は header維持 + intrusive で安全に進める。
---
## 6. 実装指示 (Phase TLS-UNIFY-3-IMPL)
小さく積む順:
1. **ENV ガード追加**
- `HAKMEM_TINY_C6_ULTRA_INTRUSIVE_FL=1` (デフォルト OFF)
- 既存 C6 ULTRA と併存
2. **C6IntrusiveFreeListBox 作成**
- `core/box/c6_intrusive_freelist_box.h`
- static inline で `c6_ifl_push/pop/empty` のみ
- 必ず `tiny_next_store/load(base, 6, ...)` 経由 (直書き禁止)
3. **TinyUltraTlsCtx 拡張**
- `void* c6_head;` 追加 (intrusive LIFO head)
- `c6_count` は既存を流用可
- init/reset/slowpath 境界でのみ操作
4. **c6_ultra_alloc/free_intrusive() 実装**
- ENV_OFF または空 → 既存 magazine/ULTRA へ Fail-Fast フォールバック
- 採用境界は `tiny_refill_try_fast()` / `superslab_refill()` に固定
- drain→bind→owner は refill でのみ踏む (intrusive 箱は副作用ゼロ)
5. **可視化**
- ring に `C6_IFL_PUSH/POP/REFILL_EMPTY`
- 異常系のみワンショット
- push/pop/fallback カウンタ
6. **健康診断**
- `scripts/verify_health_profiles.sh` を ENV_OFF/ON で各1回
- 差分が出たら L1/L2 境界違反を疑う
---
**Date**: 2025-12-12
**Phase**: TLS-UNIFY-3-DESIGN
**Status**: Design document (implementation in next session)