161 lines
4.6 KiB
C
161 lines
4.6 KiB
C
|
|
// hakmem_whale.c - Whale Fast-Path Implementation
|
||
|
|
//
|
||
|
|
// License: MIT
|
||
|
|
// Date: 2025-10-21
|
||
|
|
|
||
|
|
#include "hakmem_whale.h"
|
||
|
|
#include "hakmem_sys.h"
|
||
|
|
#include "hakmem_debug.h"
|
||
|
|
#include "hakmem_internal.h" // Phase 6.15 P0.1: For HAKMEM_LOG macro
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Internal State (FIFO Ring Buffer)
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
void* ptr; // Block pointer
|
||
|
|
size_t size; // Block size
|
||
|
|
} WhaleSlot;
|
||
|
|
|
||
|
|
static WhaleSlot g_ring[WHALE_RING_CAPACITY];
|
||
|
|
static int g_head = 0; // Next slot to read (FIFO output)
|
||
|
|
static int g_tail = 0; // Next slot to write (FIFO input)
|
||
|
|
static int g_count = 0; // Current number of cached blocks
|
||
|
|
|
||
|
|
// Statistics
|
||
|
|
static uint64_t g_hits = 0;
|
||
|
|
static uint64_t g_misses = 0;
|
||
|
|
static uint64_t g_puts = 0;
|
||
|
|
static uint64_t g_evictions = 0;
|
||
|
|
|
||
|
|
static int g_initialized = 0;
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Public API Implementation
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void hkm_whale_init(void) {
|
||
|
|
if (g_initialized) return;
|
||
|
|
|
||
|
|
memset(g_ring, 0, sizeof(g_ring));
|
||
|
|
g_head = 0;
|
||
|
|
g_tail = 0;
|
||
|
|
g_count = 0;
|
||
|
|
g_hits = 0;
|
||
|
|
g_misses = 0;
|
||
|
|
g_puts = 0;
|
||
|
|
g_evictions = 0;
|
||
|
|
|
||
|
|
g_initialized = 1;
|
||
|
|
HAKMEM_LOG("[Whale] Initialized (capacity=%d, threshold=%zu MB)\n",
|
||
|
|
WHALE_RING_CAPACITY, WHALE_MIN_SIZE / (1024 * 1024));
|
||
|
|
}
|
||
|
|
|
||
|
|
void hkm_whale_shutdown(void) {
|
||
|
|
if (!g_initialized) return;
|
||
|
|
|
||
|
|
// Free all cached blocks
|
||
|
|
for (int i = 0; i < g_count; i++) {
|
||
|
|
int idx = (g_head + i) % WHALE_RING_CAPACITY;
|
||
|
|
if (g_ring[idx].ptr) {
|
||
|
|
hkm_sys_munmap(g_ring[idx].ptr, g_ring[idx].size);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
g_initialized = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void* hkm_whale_get(size_t size) {
|
||
|
|
if (!g_initialized) hkm_whale_init();
|
||
|
|
if (size < WHALE_MIN_SIZE) return NULL; // Not a whale
|
||
|
|
|
||
|
|
HKM_TIME_START(t0);
|
||
|
|
|
||
|
|
// FIFO: check if we have any cached blocks
|
||
|
|
if (g_count == 0) {
|
||
|
|
HKM_TIME_END(HKM_CAT_WHALE_GET, t0);
|
||
|
|
g_misses++;
|
||
|
|
return NULL; // Cache miss
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get oldest block (FIFO head)
|
||
|
|
WhaleSlot* slot = &g_ring[g_head];
|
||
|
|
void* ptr = slot->ptr;
|
||
|
|
size_t cached_size = slot->size;
|
||
|
|
|
||
|
|
// Check if size matches (exact match only for now)
|
||
|
|
if (cached_size < size) {
|
||
|
|
HKM_TIME_END(HKM_CAT_WHALE_GET, t0);
|
||
|
|
g_misses++;
|
||
|
|
return NULL; // Size mismatch
|
||
|
|
}
|
||
|
|
|
||
|
|
// Cache hit! Remove from ring
|
||
|
|
slot->ptr = NULL;
|
||
|
|
slot->size = 0;
|
||
|
|
g_head = (g_head + 1) % WHALE_RING_CAPACITY;
|
||
|
|
g_count--;
|
||
|
|
|
||
|
|
HKM_TIME_END(HKM_CAT_WHALE_GET, t0);
|
||
|
|
g_hits++;
|
||
|
|
|
||
|
|
return ptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
int hkm_whale_put(void* ptr, size_t size) {
|
||
|
|
if (!g_initialized) hkm_whale_init();
|
||
|
|
if (!ptr) return 1; // Invalid pointer
|
||
|
|
if (size < WHALE_MIN_SIZE) return 1; // Not a whale
|
||
|
|
|
||
|
|
HKM_TIME_START(t0);
|
||
|
|
|
||
|
|
g_puts++;
|
||
|
|
|
||
|
|
// Check if cache is full
|
||
|
|
if (g_count >= WHALE_RING_CAPACITY) {
|
||
|
|
// Phase 6.11.2: Region Cache (Keep-Map Reuse)
|
||
|
|
// Evict oldest block with MADV_DONTNEED instead of munmap
|
||
|
|
// - Releases physical pages (RSS reduction)
|
||
|
|
// - Keeps VMA mapped (faster than munmap + mmap)
|
||
|
|
// - OS can reuse VMA for next mmap
|
||
|
|
WhaleSlot* evict_slot = &g_ring[g_head];
|
||
|
|
if (evict_slot->ptr) {
|
||
|
|
hkm_sys_madvise_dontneed(evict_slot->ptr, evict_slot->size);
|
||
|
|
g_evictions++;
|
||
|
|
}
|
||
|
|
g_head = (g_head + 1) % WHALE_RING_CAPACITY;
|
||
|
|
g_count--;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add new block to tail
|
||
|
|
WhaleSlot* slot = &g_ring[g_tail];
|
||
|
|
slot->ptr = ptr;
|
||
|
|
slot->size = size;
|
||
|
|
g_tail = (g_tail + 1) % WHALE_RING_CAPACITY;
|
||
|
|
g_count++;
|
||
|
|
|
||
|
|
HKM_TIME_END(HKM_CAT_WHALE_PUT, t0);
|
||
|
|
|
||
|
|
return 0; // Successfully cached
|
||
|
|
}
|
||
|
|
|
||
|
|
void hkm_whale_dump_stats(void) {
|
||
|
|
if (!g_initialized) return;
|
||
|
|
|
||
|
|
fprintf(stderr, "\n========================================\n");
|
||
|
|
fprintf(stderr, "Whale Fast-Path Statistics\n");
|
||
|
|
fprintf(stderr, "========================================\n");
|
||
|
|
fprintf(stderr, "Hits: %lu\n", (unsigned long)g_hits);
|
||
|
|
fprintf(stderr, "Misses: %lu\n", (unsigned long)g_misses);
|
||
|
|
fprintf(stderr, "Puts: %lu\n", (unsigned long)g_puts);
|
||
|
|
fprintf(stderr, "Evictions: %lu\n", (unsigned long)g_evictions);
|
||
|
|
|
||
|
|
uint64_t total_gets = g_hits + g_misses;
|
||
|
|
double hit_rate = total_gets > 0 ? (double)g_hits / total_gets * 100.0 : 0.0;
|
||
|
|
fprintf(stderr, "Hit Rate: %.1f%%\n", hit_rate);
|
||
|
|
fprintf(stderr, "Cached: %d / %d slots\n", g_count, WHALE_RING_CAPACITY);
|
||
|
|
fprintf(stderr, "========================================\n");
|
||
|
|
}
|