Phase 17-1 Revision: Small-Mid Front Box Only (ChatGPT Strategy)
STRATEGY CHANGE (ChatGPT reviewed): - Phase 17-1: Build FRONT BOX ONLY (no dedicated SuperSlab backend) - Backend: Reuse existing Tiny SuperSlab/SharedPool APIs - Goal: Measure performance impact before building dedicated infrastructure - A/B test: Does thin front layer improve 256-1KB performance? RATIONALE (ChatGPT analysis): 1. Tiny/Middle/Large need different properties - same SuperSlab causes conflict 2. Metadata shapes collide - struct bloat → L1 miss increase 3. Learning signals get muddied - size-specific control becomes difficult IMPLEMENTATION: - Reduced size classes: 5 → 3 (256B/512B/1KB only) - Removed dedicated SuperSlab backend stub - Backend: Direct delegation to hak_tiny_alloc/free - TLS freelist: Thin front cache (32/24/16 capacity) - Fast path: TLS hit (pop/push with header 0xb0) - Slow path: Backend alloc via Tiny (no TLS refill) - Free path: TLS push if space, else delegate to Tiny ARCHITECTURE: Tiny: 0-255B (C0-C5, unchanged) Small-Mid: 256-1KB (SM0-SM2, Front Box, backend=Tiny) Mid: 8KB-32KB (existing) FILES CHANGED: - hakmem_smallmid.h: Reduced to 3 classes, updated docs - hakmem_smallmid.c: Removed SuperSlab stub, added backend delegation NEXT STEPS: - Integrate into hak_alloc_api.inc.h routing - A/B benchmark: Small-Mid ON/OFF comparison - If successful (2x improvement), consider Phase 17-2 dedicated backend 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,20 +1,28 @@
|
||||
/**
|
||||
* hakmem_smallmid.c - Small-Mid Allocator Box Implementation
|
||||
* hakmem_smallmid.c - Small-Mid Allocator Front Box Implementation
|
||||
*
|
||||
* Phase 17: Dedicated allocator layer for 256B-4KB range
|
||||
* Phase 17-1: Front Box Only (No Dedicated SuperSlab Backend)
|
||||
*
|
||||
* Strategy (ChatGPT reviewed):
|
||||
* - Thin front layer with TLS freelist (256B/512B/1KB)
|
||||
* - Backend: Use existing Tiny SuperSlab/SharedPool APIs
|
||||
* - Goal: Measure performance impact before building dedicated backend
|
||||
* - A/B test: Does Small-Mid front improve 256-1KB performance?
|
||||
*
|
||||
* Architecture:
|
||||
* - Dedicated SuperSlab pool (separated from Tiny)
|
||||
* - TLS freelist for fast alloc/free
|
||||
* - Header-based class identification (Phase 7)
|
||||
* - 3 size classes: 256B/512B/1KB (reduced from 5)
|
||||
* - TLS freelist for fast alloc/free (static inline)
|
||||
* - Backend: Call Tiny allocator APIs (reuse existing infrastructure)
|
||||
* - ENV controlled (HAKMEM_SMALLMID_ENABLE=1)
|
||||
*
|
||||
* Created: 2025-11-16
|
||||
* Updated: 2025-11-16 (Phase 17-1 revision - Front Box only)
|
||||
*/
|
||||
|
||||
#include "hakmem_smallmid.h"
|
||||
#include "hakmem_build_flags.h"
|
||||
#include "tiny_region_id.h" // For header writing
|
||||
#include "hakmem_tiny.h" // For backend: hak_tiny_alloc / hak_tiny_free
|
||||
#include "tiny_region_id.h" // For header writing
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
@ -26,15 +34,13 @@ __thread void* g_smallmid_tls_head[SMALLMID_NUM_CLASSES] = {NULL};
|
||||
__thread uint32_t g_smallmid_tls_count[SMALLMID_NUM_CLASSES] = {0};
|
||||
|
||||
// ============================================================================
|
||||
// Size Class Table
|
||||
// Size Class Table (Phase 17-1: 3 classes)
|
||||
// ============================================================================
|
||||
|
||||
const size_t g_smallmid_class_sizes[SMALLMID_NUM_CLASSES] = {
|
||||
256, // SM0: 256B
|
||||
512, // SM1: 512B
|
||||
1024, // SM2: 1KB
|
||||
2048, // SM3: 2KB
|
||||
4096 // SM4: 4KB
|
||||
1024 // SM2: 1KB
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@ -95,7 +101,7 @@ void smallmid_init(void) {
|
||||
pthread_mutex_lock(&g_smallmid_init_lock);
|
||||
|
||||
if (!g_smallmid_initialized) {
|
||||
SMALLMID_LOG("Initializing Small-Mid allocator...");
|
||||
SMALLMID_LOG("Initializing Small-Mid Front Box...");
|
||||
|
||||
// Check ENV
|
||||
if (!smallmid_is_enabled()) {
|
||||
@ -105,12 +111,11 @@ void smallmid_init(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Phase 17-2: Initialize dedicated SuperSlab pool
|
||||
// - Allocate SuperSlab pool (separated from Tiny)
|
||||
// - Set up refill logic
|
||||
// Phase 17-1: No dedicated backend - use existing Tiny infrastructure
|
||||
// No additional initialization needed (TLS state is static)
|
||||
|
||||
g_smallmid_initialized = 1;
|
||||
SMALLMID_LOG("Small-Mid allocator initialized (5 classes: 256B-4KB)");
|
||||
SMALLMID_LOG("Small-Mid Front Box initialized (3 classes: 256B/512B/1KB, backend=Tiny)");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_smallmid_init_lock);
|
||||
@ -165,32 +170,41 @@ static inline bool smallmid_tls_push(int class_idx, void* ptr) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// SuperSlab Backend (Stub for Phase 17-2)
|
||||
// Backend: Use Tiny Allocator APIs (Phase 17-1)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* smallmid_superslab_refill - Refill TLS from dedicated SuperSlab pool
|
||||
* smallmid_backend_alloc - Allocate from Tiny backend
|
||||
*
|
||||
* @param class_idx Size class index
|
||||
* @param count Number of blocks to refill
|
||||
* @return true on success, false on OOM
|
||||
* @param size Allocation size
|
||||
* @return Allocated pointer (user pointer, no Small-Mid header)
|
||||
*
|
||||
* TODO Phase 17-2: Implement dedicated SuperSlab backend
|
||||
* Phase 17-1: Delegate to existing Tiny allocator infrastructure
|
||||
* This reuses Tiny's SuperSlab/SharedPool without building dedicated backend
|
||||
*/
|
||||
static bool smallmid_superslab_refill(int class_idx, uint32_t count) {
|
||||
(void)class_idx;
|
||||
(void)count;
|
||||
|
||||
static inline void* smallmid_backend_alloc(size_t size) {
|
||||
#ifdef HAKMEM_SMALLMID_STATS
|
||||
__atomic_fetch_add(&g_smallmid_stats.tls_misses, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&g_smallmid_stats.superslab_refills, 1, __ATOMIC_RELAXED);
|
||||
#endif
|
||||
|
||||
// TODO: Allocate from dedicated SuperSlab pool
|
||||
// For now, return false (not implemented)
|
||||
SMALLMID_LOG("smallmid_superslab_refill: not yet implemented (class=%d, count=%u)",
|
||||
class_idx, count);
|
||||
return false;
|
||||
// Call Tiny allocator (reuses existing SuperSlab/SharedPool)
|
||||
void* ptr = hak_tiny_alloc(size);
|
||||
SMALLMID_LOG("smallmid_backend_alloc(%zu) = %p (via Tiny)", size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* smallmid_backend_free - Free to Tiny backend
|
||||
*
|
||||
* @param ptr User pointer (no Small-Mid header)
|
||||
* @param size Allocation size
|
||||
*
|
||||
* Phase 17-1: Delegate to existing Tiny allocator infrastructure
|
||||
*/
|
||||
static inline void smallmid_backend_free(void* ptr, size_t size) {
|
||||
(void)size; // Unused: Tiny free reads header, doesn't need size
|
||||
SMALLMID_LOG("smallmid_backend_free(%p) (via Tiny)", ptr);
|
||||
hak_tiny_free(ptr);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -233,22 +247,16 @@ void* smallmid_alloc(size_t size) {
|
||||
return (uint8_t*)ptr + 1; // Return user pointer (skip header)
|
||||
}
|
||||
|
||||
// Slow path: Refill from SuperSlab
|
||||
uint32_t refill_count = smallmid_tls_capacity(class_idx) / 2; // Refill 50%
|
||||
if (!smallmid_superslab_refill(class_idx, refill_count)) {
|
||||
SMALLMID_LOG("smallmid_alloc(%zu) = NULL (SuperSlab refill failed)", size);
|
||||
return NULL; // OOM or not implemented yet
|
||||
// Slow path: Allocate from Tiny backend (no refill, direct delegation)
|
||||
// Phase 17-1: Simplified - no TLS refill, just pass through to Tiny
|
||||
void* backend_ptr = smallmid_backend_alloc(size);
|
||||
if (!backend_ptr) {
|
||||
SMALLMID_LOG("smallmid_alloc(%zu) = NULL (backend alloc failed)", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try again after refill
|
||||
ptr = smallmid_tls_pop(class_idx);
|
||||
if (ptr) {
|
||||
SMALLMID_LOG("smallmid_alloc(%zu) = %p (after refill, class=%d)", size, ptr, class_idx);
|
||||
return (uint8_t*)ptr + 1; // Return user pointer (skip header)
|
||||
}
|
||||
|
||||
SMALLMID_LOG("smallmid_alloc(%zu) = NULL (refill succeeded but TLS still empty?)", size);
|
||||
return NULL;
|
||||
SMALLMID_LOG("smallmid_alloc(%zu) = %p (backend alloc, class=%d)", size, backend_ptr, class_idx);
|
||||
return backend_ptr; // Backend returns user pointer directly
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -267,31 +275,32 @@ void smallmid_free(void* ptr) {
|
||||
__atomic_fetch_add(&g_smallmid_stats.total_frees, 1, __ATOMIC_RELAXED);
|
||||
#endif
|
||||
|
||||
// Header-based fast free (Phase 7 technology)
|
||||
// Read 1-byte header at [ptr - 1] to get class_idx
|
||||
// Phase 17-1: Read header to identify if this is a Small-Mid TLS allocation
|
||||
// or a backend (Tiny) allocation
|
||||
uint8_t* base = (uint8_t*)ptr - 1;
|
||||
uint8_t header = *base;
|
||||
|
||||
// Header format: 0xa0 | class_idx (same as Tiny)
|
||||
// For Small-Mid, we use a different magic to distinguish from Tiny
|
||||
// Small-Mid magic: 0xb0 | class_idx
|
||||
// Small-Mid TLS allocations have magic 0xb0
|
||||
// Tiny allocations have magic 0xa0
|
||||
uint8_t magic = header & 0xf0;
|
||||
int class_idx = header & 0x0f;
|
||||
|
||||
if (class_idx < 0 || class_idx >= SMALLMID_NUM_CLASSES) {
|
||||
SMALLMID_LOG("smallmid_free(%p): invalid class_idx=%d from header=0x%02x",
|
||||
ptr, class_idx, header);
|
||||
return; // Invalid header, skip
|
||||
if (magic == 0xb0 && class_idx >= 0 && class_idx < SMALLMID_NUM_CLASSES) {
|
||||
// This is a Small-Mid TLS allocation, push to TLS freelist
|
||||
if (smallmid_tls_push(class_idx, base)) {
|
||||
SMALLMID_LOG("smallmid_free(%p): pushed to TLS (class=%d)", ptr, class_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
// TLS full: Delegate to Tiny backend
|
||||
SMALLMID_LOG("smallmid_free(%p): TLS full, delegating to backend", ptr);
|
||||
// Fall through to backend free
|
||||
}
|
||||
|
||||
// Push to TLS freelist
|
||||
if (smallmid_tls_push(class_idx, base)) {
|
||||
SMALLMID_LOG("smallmid_free(%p): pushed to TLS (class=%d)", ptr, class_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
// TLS full: Drain to remote or SuperSlab
|
||||
// TODO Phase 17-3: Implement remote drain
|
||||
SMALLMID_LOG("smallmid_free(%p): TLS full, remote drain not yet implemented", ptr);
|
||||
// This is a backend (Tiny) allocation, or TLS full - delegate to Tiny
|
||||
// Tiny will handle the free based on its own header (0xa0)
|
||||
size_t size = 0; // Tiny free doesn't need size, it reads header
|
||||
smallmid_backend_free(ptr, size);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@ -303,9 +312,15 @@ void smallmid_thread_exit(void) {
|
||||
|
||||
SMALLMID_LOG("smallmid_thread_exit: cleaning up TLS state");
|
||||
|
||||
// TODO Phase 17-3: Return TLS blocks to SuperSlab
|
||||
// For now, just reset counts (memory leak for testing)
|
||||
// Phase 17-1: Return TLS blocks to Tiny backend
|
||||
for (int i = 0; i < SMALLMID_NUM_CLASSES; i++) {
|
||||
void* head = g_smallmid_tls_head[i];
|
||||
while (head) {
|
||||
void* next = *(void**)((uint8_t*)head + 1);
|
||||
void* user_ptr = (uint8_t*)head + 1;
|
||||
smallmid_backend_free(user_ptr, 0);
|
||||
head = next;
|
||||
}
|
||||
g_smallmid_tls_head[i] = NULL;
|
||||
g_smallmid_tls_count[i] = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user