Root Cause: 1. C7 stride was 1024B, unable to serve 1024B user requests (need 1025B with header) 2. New SuperSlabs start with meta->class_idx=0 (mmap zero-init) 3. superslab_init_slab() only sets class_idx if meta->class_idx==255 4. Multiple code paths used conditional assignment (if class_idx==255), leaving C7 slabs with class_idx=0 5. This caused C7 blocks to be misidentified as C0, leading to HDR_META_MISMATCH errors Changes: 1. Upgrade C7 stride: 1024B → 2048B (can now serve 1024B requests) 2. Update blocks_per_slab[7]: 64 → 32 (2048B stride / 64KB slab) 3. Update size-to-class LUT: entries 513-2048 now map to C7 4. Fix superslab_init_slab() fail-safe: only reinitialize if class_idx==255 (not 0) 5. Add explicit class_idx assignment in 6 initialization paths: - tiny_superslab_alloc.inc.h: superslab_refill() after init - hakmem_tiny_superslab.c: backend_shared after init (main path) - ss_unified_backend_box.c: unconditional assignment - ss_legacy_backend_box.c: explicit assignment - superslab_expansion_box.c: explicit assignment - ss_allocation_box.c: fail-safe condition fix Fix P0 refill bug: - Update obsolete array access after Phase 3d-B TLS SLL unification - g_tls_sll_head[cls] → g_tls_sll[cls].head - g_tls_sll_count[cls] → g_tls_sll[cls].count Results: - HDR_META_MISMATCH: eliminated (0 errors in 100K iterations) - 1024B allocations now routed to C7 (Tiny fast path) - NXT_MISALIGN warnings remain (legacy 1024B SuperSlabs, separate issue) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
184 lines
7.4 KiB
C
184 lines
7.4 KiB
C
// Box: Unified Backend (Phase 12)
|
||
// Purpose: Unified entry point for SuperSlab allocation (shared pool + legacy fallback)
|
||
|
||
#include "ss_unified_backend_box.h"
|
||
#include "ss_legacy_backend_box.h"
|
||
#include "hakmem_tiny_superslab.h"
|
||
#include "hakmem_shared_pool.h"
|
||
#include "hakmem_tiny_config.h"
|
||
#include "ss_allocation_box.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
// ============================================================================
|
||
// Shared Pool Backend
|
||
// ============================================================================
|
||
|
||
/*
|
||
* Shared pool backend for hak_tiny_alloc_superslab_box().
|
||
*
|
||
* Phase 12-2:
|
||
* - Uses SharedSuperSlabPool (g_shared_pool) to obtain a SuperSlab/slab
|
||
* for the requested class_idx.
|
||
* - This backend EXPRESSLY owns only:
|
||
* - choosing (ss, slab_idx) via shared_pool_acquire_slab()
|
||
* - initializing that slab's TinySlabMeta via superslab_init_slab()
|
||
* and nothing else; all callers must go through hak_tiny_alloc_superslab_box().
|
||
*
|
||
* - For now this is a minimal, conservative implementation:
|
||
* - One linear bump-run is carved from the acquired slab using tiny_block_stride_for_class().
|
||
* - No complex per-slab freelist or refill policy yet (Phase 12-3+).
|
||
* - If shared_pool_acquire_slab() fails, we fall back to legacy backend.
|
||
*/
|
||
void* hak_tiny_alloc_superslab_backend_shared(int class_idx)
|
||
{
|
||
if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES_SS) {
|
||
return NULL;
|
||
}
|
||
|
||
SuperSlab* ss = NULL;
|
||
int slab_idx = -1;
|
||
|
||
if (shared_pool_acquire_slab(class_idx, &ss, &slab_idx) != 0 || !ss) {
|
||
// Shared pool could not provide a slab; caller may choose to fall back.
|
||
return NULL;
|
||
}
|
||
|
||
TinySlabMeta* meta = &ss->slabs[slab_idx];
|
||
|
||
// Defensive: shared_pool must either hand us an UNASSIGNED slab or one
|
||
// already bound to this class. Anything else is a hard bug.
|
||
if (meta->class_idx != 255 && meta->class_idx != (uint8_t)class_idx) {
|
||
#if !HAKMEM_BUILD_RELEASE
|
||
fprintf(stderr,
|
||
"[HAKMEM][SS_SHARED] BUG: acquire_slab mismatch: cls=%d meta->class_idx=%u slab_idx=%d ss=%p\n",
|
||
class_idx, (unsigned)meta->class_idx, slab_idx, (void*)ss);
|
||
#endif
|
||
return NULL;
|
||
}
|
||
|
||
// Initialize slab geometry once for this class.
|
||
if (meta->capacity == 0) {
|
||
size_t block_size = g_tiny_class_sizes[class_idx];
|
||
// owner_tid_low is advisory; we can use 0 in this backend.
|
||
superslab_init_slab(ss, slab_idx, block_size, 0);
|
||
meta = &ss->slabs[slab_idx];
|
||
|
||
// CRITICAL FIX: Always set class_idx after init to avoid C0/C7 confusion.
|
||
// New SuperSlabs start with meta->class_idx=0 (mmap zero-init).
|
||
// Must explicitly set to requested class, not just when class_idx==255.
|
||
meta->class_idx = (uint8_t)class_idx;
|
||
}
|
||
|
||
// Final contract check before computing addresses.
|
||
if (meta->class_idx != (uint8_t)class_idx ||
|
||
meta->capacity == 0 ||
|
||
meta->used > meta->capacity) {
|
||
#if !HAKMEM_BUILD_RELEASE
|
||
fprintf(stderr,
|
||
"[HAKMEM][SS_SHARED] BUG: invalid slab meta before alloc: "
|
||
"cls=%d slab_idx=%d meta_cls=%u used=%u cap=%u ss=%p\n",
|
||
class_idx, slab_idx,
|
||
(unsigned)meta->class_idx,
|
||
(unsigned)meta->used,
|
||
(unsigned)meta->capacity,
|
||
(void*)ss);
|
||
#endif
|
||
return NULL;
|
||
}
|
||
|
||
// Simple bump allocation within this slab.
|
||
if (meta->used >= meta->capacity) {
|
||
// Slab exhausted: in minimal Phase12-2 backend we do not loop;
|
||
// caller or future logic must acquire another slab.
|
||
return NULL;
|
||
}
|
||
|
||
size_t stride = tiny_block_stride_for_class(class_idx);
|
||
size_t offset = (size_t)meta->used * stride;
|
||
|
||
// Phase 12-2 minimal geometry:
|
||
// - slab 0 data offset via SUPERSLAB_SLAB0_DATA_OFFSET
|
||
// - subsequent slabs at fixed SUPERSLAB_SLAB_USABLE_SIZE strides.
|
||
size_t slab_base_off = SUPERSLAB_SLAB0_DATA_OFFSET
|
||
+ (size_t)slab_idx * SUPERSLAB_SLAB_USABLE_SIZE;
|
||
uint8_t* base = (uint8_t*)ss + slab_base_off + offset;
|
||
|
||
meta->used++;
|
||
atomic_fetch_add_explicit(&ss->total_active_blocks, 1, memory_order_relaxed);
|
||
|
||
hak_tiny_ss_hint_record(class_idx, ss, slab_idx);
|
||
|
||
return (void*)base;
|
||
}
|
||
|
||
// ============================================================================
|
||
// Unified Entry Point
|
||
// ============================================================================
|
||
|
||
/*
|
||
* Box API entry:
|
||
* - Single front-door for tiny-side Superslab allocations.
|
||
*
|
||
* Phase 27 policy (Unified backend line):
|
||
* - デフォルト: Shared Pool backend のみを使用(legacy backend は利用しない)。
|
||
* - 回帰/デバッグ用途でのみ、ENV で legacy fallback を明示的に有効化できる。
|
||
*
|
||
* ENV:
|
||
* HAKMEM_TINY_SS_SHARED=0 → 強制的に legacy backend のみを使用(過去挙動の回帰確認用)
|
||
* HAKMEM_TINY_SS_LEGACY_FALLBACK=0 → shared 失敗時の legacy fallback を無効化(デフォルト: 1, 有効)
|
||
* HAKMEM_TINY_SS_C23_UNIFIED=1 → C2/C3 限定で legacy fallback を無効化(Shared Pool のみで運転)
|
||
* HAKMEM_TINY_SS_LEGACY_HINT=1 → shared→legacy 間の軽量な hint Box を有効化
|
||
*/
|
||
void* hak_tiny_alloc_superslab_box(int class_idx)
|
||
{
|
||
static int g_ss_shared_mode = -1;
|
||
static int g_ss_legacy_fallback = -1;
|
||
static int g_ss_c23_unified = -1;
|
||
|
||
if (__builtin_expect(g_ss_shared_mode == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_SS_SHARED");
|
||
// デフォルト: shared 有効。ENV=0 のときのみ legacy 専用に切り替え。
|
||
g_ss_shared_mode = (e && *e == '0') ? 0 : 1;
|
||
}
|
||
if (__builtin_expect(g_ss_legacy_fallback == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_SS_LEGACY_FALLBACK");
|
||
// デフォルト: legacy fallback 有効。
|
||
// ENV=0 のときのみ fallback 無効(完全 Unified backend モード)。
|
||
g_ss_legacy_fallback = (e && *e == '0') ? 0 : 1;
|
||
}
|
||
if (__builtin_expect(g_ss_c23_unified == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_SS_C23_UNIFIED");
|
||
// ENV=1 のときだけ C2/C3 を「ほぼ完全 Unified」モードに切り替える。
|
||
g_ss_c23_unified = (e && *e && *e != '0') ? 1 : 0;
|
||
}
|
||
|
||
// shared OFF 時は legacy のみ(強制回帰モード)
|
||
if (!g_ss_shared_mode) {
|
||
return hak_tiny_alloc_superslab_backend_legacy(class_idx);
|
||
}
|
||
|
||
int legacy_fallback = g_ss_legacy_fallback;
|
||
if ((class_idx == 2 || class_idx == 3) && g_ss_c23_unified == 1) {
|
||
// C2/C3 は専用の Shared Pool 実験モード:
|
||
// - ENV=1 のときだけ legacy fallback を OFF にする。
|
||
legacy_fallback = 0;
|
||
}
|
||
|
||
// Unified backend ライン: Shared Pool backend を唯一の正経路とする。
|
||
void* p = hak_tiny_alloc_superslab_backend_shared(class_idx);
|
||
if (p != NULL || !legacy_fallback) {
|
||
// shared 成功、または legacy fallback 無効 → そのまま返す(NULLも許容)
|
||
return p;
|
||
}
|
||
|
||
// オプション: shared 失敗時に、軽量な hint Box を一度だけ試す
|
||
void* hint = hak_tiny_alloc_superslab_backend_hint(class_idx);
|
||
if (hint != NULL) {
|
||
return hint;
|
||
}
|
||
|
||
// shared 失敗時のみ legacy backend へフォールバック(回帰/デバッグ用)
|
||
return hak_tiny_alloc_superslab_backend_legacy(class_idx);
|
||
}
|