Files
hakmem/core/hakmem_smallmid.c

313 lines
11 KiB
C
Raw Normal View History

/**
* hakmem_smallmid.c - Small-Mid Allocator Box Implementation
*
* Phase 17: Dedicated allocator layer for 256B-4KB range
*
* Architecture:
* - Dedicated SuperSlab pool (separated from Tiny)
* - TLS freelist for fast alloc/free
* - Header-based class identification (Phase 7)
* - ENV controlled (HAKMEM_SMALLMID_ENABLE=1)
*
* Created: 2025-11-16
*/
#include "hakmem_smallmid.h"
#include "hakmem_build_flags.h"
#include "tiny_region_id.h" // For header writing
#include <string.h>
#include <pthread.h>
// ============================================================================
// TLS State
// ============================================================================
__thread void* g_smallmid_tls_head[SMALLMID_NUM_CLASSES] = {NULL};
__thread uint32_t g_smallmid_tls_count[SMALLMID_NUM_CLASSES] = {0};
// ============================================================================
// Size Class Table
// ============================================================================
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
};
// ============================================================================
// Global State
// ============================================================================
static pthread_mutex_t g_smallmid_init_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_smallmid_initialized = 0;
static int g_smallmid_enabled = -1; // -1 = not checked, 0 = disabled, 1 = enabled
// ============================================================================
// Statistics (Debug)
// ============================================================================
#ifdef HAKMEM_SMALLMID_STATS
SmallMidStats g_smallmid_stats = {0};
void smallmid_print_stats(void) {
fprintf(stderr, "\n=== Small-Mid Allocator Statistics ===\n");
fprintf(stderr, "Total allocs: %lu\n", g_smallmid_stats.total_allocs);
fprintf(stderr, "Total frees: %lu\n", g_smallmid_stats.total_frees);
fprintf(stderr, "TLS hits: %lu\n", g_smallmid_stats.tls_hits);
fprintf(stderr, "TLS misses: %lu\n", g_smallmid_stats.tls_misses);
fprintf(stderr, "SuperSlab refills: %lu\n", g_smallmid_stats.superslab_refills);
if (g_smallmid_stats.total_allocs > 0) {
double hit_rate = (double)g_smallmid_stats.tls_hits / g_smallmid_stats.total_allocs * 100.0;
fprintf(stderr, "TLS hit rate: %.2f%%\n", hit_rate);
}
fprintf(stderr, "=======================================\n\n");
}
#endif
// ============================================================================
// ENV Control
// ============================================================================
bool smallmid_is_enabled(void) {
if (__builtin_expect(g_smallmid_enabled == -1, 0)) {
const char* env = getenv("HAKMEM_SMALLMID_ENABLE");
g_smallmid_enabled = (env && atoi(env) == 1) ? 1 : 0;
if (g_smallmid_enabled) {
SMALLMID_LOG("Small-Mid allocator ENABLED (ENV: HAKMEM_SMALLMID_ENABLE=1)");
} else {
SMALLMID_LOG("Small-Mid allocator DISABLED (default, set HAKMEM_SMALLMID_ENABLE=1 to enable)");
}
}
return (g_smallmid_enabled == 1);
}
// ============================================================================
// Initialization
// ============================================================================
void smallmid_init(void) {
if (g_smallmid_initialized) return;
pthread_mutex_lock(&g_smallmid_init_lock);
if (!g_smallmid_initialized) {
SMALLMID_LOG("Initializing Small-Mid allocator...");
// Check ENV
if (!smallmid_is_enabled()) {
SMALLMID_LOG("Small-Mid allocator is disabled, skipping initialization");
g_smallmid_initialized = 1;
pthread_mutex_unlock(&g_smallmid_init_lock);
return;
}
// TODO Phase 17-2: Initialize dedicated SuperSlab pool
// - Allocate SuperSlab pool (separated from Tiny)
// - Set up refill logic
g_smallmid_initialized = 1;
SMALLMID_LOG("Small-Mid allocator initialized (5 classes: 256B-4KB)");
}
pthread_mutex_unlock(&g_smallmid_init_lock);
}
// ============================================================================
// TLS Freelist Operations
// ============================================================================
/**
* smallmid_tls_pop - Pop a block from TLS freelist
*
* @param class_idx Size class index
* @return Block pointer (with header), or NULL if empty
*/
static inline void* smallmid_tls_pop(int class_idx) {
void* head = g_smallmid_tls_head[class_idx];
if (!head) return NULL;
// Read next pointer (stored at offset 0 in user data, after 1-byte header)
void* next = *(void**)((uint8_t*)head + 1);
g_smallmid_tls_head[class_idx] = next;
g_smallmid_tls_count[class_idx]--;
#ifdef HAKMEM_SMALLMID_STATS
__atomic_fetch_add(&g_smallmid_stats.tls_hits, 1, __ATOMIC_RELAXED);
#endif
return head;
}
/**
* smallmid_tls_push - Push a block to TLS freelist
*
* @param class_idx Size class index
* @param ptr Block pointer (with header)
* @return true on success, false if TLS full
*/
static inline bool smallmid_tls_push(int class_idx, void* ptr) {
uint32_t capacity = smallmid_tls_capacity(class_idx);
if (g_smallmid_tls_count[class_idx] >= capacity) {
return false; // TLS full
}
// Write next pointer (at offset 0 in user data, after 1-byte header)
void* head = g_smallmid_tls_head[class_idx];
*(void**)((uint8_t*)ptr + 1) = head;
g_smallmid_tls_head[class_idx] = ptr;
g_smallmid_tls_count[class_idx]++;
return true;
}
// ============================================================================
// SuperSlab Backend (Stub for Phase 17-2)
// ============================================================================
/**
* smallmid_superslab_refill - Refill TLS from dedicated SuperSlab pool
*
* @param class_idx Size class index
* @param count Number of blocks to refill
* @return true on success, false on OOM
*
* TODO Phase 17-2: Implement dedicated SuperSlab backend
*/
static bool smallmid_superslab_refill(int class_idx, uint32_t count) {
(void)class_idx;
(void)count;
#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;
}
// ============================================================================
// Allocation
// ============================================================================
void* smallmid_alloc(size_t size) {
// Check if enabled
if (!smallmid_is_enabled()) {
return NULL; // Disabled, fall through to Mid or other allocators
}
// Initialize if needed
if (__builtin_expect(!g_smallmid_initialized, 0)) {
smallmid_init();
}
// Validate size range
if (__builtin_expect(!smallmid_is_in_range(size), 0)) {
SMALLMID_LOG("smallmid_alloc: size %zu out of range [%d-%d]",
size, SMALLMID_MIN_SIZE, SMALLMID_MAX_SIZE);
return NULL;
}
// Get size class
int class_idx = smallmid_size_to_class(size);
if (__builtin_expect(class_idx < 0, 0)) {
SMALLMID_LOG("smallmid_alloc: invalid class for size %zu", size);
return NULL;
}
#ifdef HAKMEM_SMALLMID_STATS
__atomic_fetch_add(&g_smallmid_stats.total_allocs, 1, __ATOMIC_RELAXED);
#endif
// Fast path: Pop from TLS freelist
void* ptr = smallmid_tls_pop(class_idx);
if (ptr) {
SMALLMID_LOG("smallmid_alloc(%zu) = %p (TLS hit, class=%d)", size, ptr, class_idx);
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
}
// 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;
}
// ============================================================================
// Free
// ============================================================================
void smallmid_free(void* ptr) {
if (!ptr) return;
// Check if enabled
if (!smallmid_is_enabled()) {
return; // Disabled, should not be called
}
#ifdef HAKMEM_SMALLMID_STATS
__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
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
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
}
// 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);
}
// ============================================================================
// Thread Cleanup
// ============================================================================
void smallmid_thread_exit(void) {
if (!smallmid_is_enabled()) return;
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)
for (int i = 0; i < SMALLMID_NUM_CLASSES; i++) {
g_smallmid_tls_head[i] = NULL;
g_smallmid_tls_count[i] = 0;
}
}