Tiny Pool redesign: P0.1, P0.3, P1.1, P1.2 - Out-of-band class_idx lookup

This commit implements the first phase of Tiny Pool redesign based on
ChatGPT architecture review. The goal is to eliminate Header/Next pointer
conflicts by moving class_idx lookup out-of-band (to SuperSlab metadata).

## P0.1: C0(8B) class upgraded to 16B
- Size table changed: {16,32,64,128,256,512,1024,2048} (8 classes)
- LUT updated: 1..16 → class 0, 17..32 → class 1, etc.
- tiny_next_off: C0 now uses offset 1 (header preserved)
- Eliminates edge cases for 8B allocations

## P0.3: Slab reuse guard Box (tls_slab_reuse_guard_box.h)
- New Box for draining TLS SLL before slab reuse
- ENV gate: HAKMEM_TINY_SLAB_REUSE_GUARD=1
- Prevents stale pointers when slabs are recycled
- Follows Box theory: single responsibility, minimal API

## P1.1: SuperSlab class_map addition
- Added uint8_t class_map[SLABS_PER_SUPERSLAB_MAX] to SuperSlab
- Maps slab_idx → class_idx for out-of-band lookup
- Initialized to 255 (UNASSIGNED) on SuperSlab creation
- Set correctly on slab initialization in all backends

## P1.2: Free fast path uses class_map
- ENV gate: HAKMEM_TINY_USE_CLASS_MAP=1
- Free path can now get class_idx from class_map instead of Header
- Falls back to Header read if class_map returns invalid value
- Fixed Legacy Backend dynamic slab initialization bug

## Documentation added
- HAKMEM_ARCHITECTURE_OVERVIEW.md: 4-layer architecture analysis
- TLS_SLL_ARCHITECTURE_INVESTIGATION.md: Root cause analysis
- PTR_LIFECYCLE_TRACE_AND_ROOT_CAUSE_ANALYSIS.md: Pointer tracking
- TINY_REDESIGN_CHECKLIST.md: Implementation roadmap (P0-P3)

## Test results
- Baseline: 70% success rate (30% crash - pre-existing issue)
- class_map enabled: 70% success rate (same as baseline)
- Performance: ~30.5M ops/s (unchanged)

## Next steps (P1.3, P2, P3)
- P1.3: Add meta->active for accurate TLS/freelist sync
- P2: TLS SLL redesign with Box-based counting
- P3: Complete Header out-of-band migration

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm (CI)
2025-11-28 13:42:39 +09:00
parent 0ce20bb835
commit dc9e650db3
23 changed files with 5338 additions and 80 deletions

View File

@ -108,10 +108,10 @@ extern __thread const char* g_tls_sll_last_writer[TINY_NUM_CLASSES];
// mov %rsi, g_tls_sll_head(%rdi)
//
#if HAKMEM_TINY_HEADER_CLASSIDX
// Phase E1-CORRECT: Restore header on FREE for ALL classes (including C7)
// ROOT CAUSE: User may have overwritten byte 0 (header). tls_sll_splice() checks
// byte 0 for HEADER_MAGIC. Without restoration, it finds 0x00 → uses wrong offset → SEGV.
// COST: 1 byte write (~1-2 cycles per free, negligible).
// DESIGN RULE: "Header is written by BOTH Alloc and Free/Drain"
// FREE path: Restore header for Class 1-6, then write Next pointer
// ALLOC path: Write header before returning to user (HAK_RET_ALLOC)
// This ensures Free path can read header to determine class_idx
#define TINY_ALLOC_FAST_PUSH_INLINE(class_idx, ptr) do { \
extern int g_tls_sll_class_mask; \
if (__builtin_expect(((g_tls_sll_class_mask & (1u << (class_idx))) == 0), 0)) { \
@ -120,20 +120,10 @@ extern __thread const char* g_tls_sll_last_writer[TINY_NUM_CLASSES];
if (!(ptr)) break; \
/* Phase E1-CORRECT: API ptr is USER pointer (= base+1). Convert back to BASE. */ \
uint8_t* _base = (uint8_t*)(ptr) - 1; \
/* Light header diag: alert if header already mismatched before we overwrite */ \
do { \
static _Atomic uint32_t g_fast_hdr_diag = 0; \
uint8_t _expect = HEADER_MAGIC | ((class_idx) & HEADER_CLASS_MASK); \
uint8_t _got = *_base; \
if (_got != _expect) { \
uint32_t _n = atomic_fetch_add_explicit(&g_fast_hdr_diag, 1, memory_order_relaxed); \
if (_n < 16) { \
fprintf(stderr, "[FAST_PUSH_HDR_MISMATCH] cls=%d base=%p got=0x%02x expect=0x%02x\n", (class_idx), _base, _got, _expect); \
} \
} \
} while (0); \
/* Restore header at BASE (not at user). */ \
*_base = HEADER_MAGIC | ((class_idx) & HEADER_CLASS_MASK); \
/* C0-C6: Restore header BEFORE writing Next. C7: skip (next overwrites header). */ \
if ((class_idx) != 7) { \
*_base = HEADER_MAGIC | ((class_idx) & HEADER_CLASS_MASK); \
} \
/* Link node using BASE as the canonical SLL node address. */ \
tiny_next_write((class_idx), _base, g_tls_sll[(class_idx)].head); \
g_tls_sll[(class_idx)].head = _base; \