Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
107 lines
3.3 KiB
C
107 lines
3.3 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <hakx/hakx_api.h>
|
|
#include "hakmem.h"
|
|
#include "hakx_front_tiny.h"
|
|
#include "hakx_l25_tuner.h"
|
|
|
|
// Optional mimalloc backend (weak; library may be absent at link/runtime)
|
|
void* mi_malloc(size_t size) __attribute__((weak));
|
|
void mi_free(void* p) __attribute__((weak));
|
|
void* mi_realloc(void* p, size_t newsize) __attribute__((weak));
|
|
void* mi_calloc(size_t count, size_t size) __attribute__((weak));
|
|
|
|
// Phase A: HAKX uses selectable backend (env HAKX_BACKEND=hakmem|mi|sys; default=hakmem).
|
|
// Front/Back specialization will be layered later.
|
|
|
|
static enum { HAKX_B_HAKMEM=0, HAKX_B_MI=1, HAKX_B_SYS=2 } g_hakx_backend = HAKX_B_HAKMEM;
|
|
static int g_hakx_env_parsed = 0;
|
|
|
|
static inline void hakx_parse_backend_once(void) {
|
|
if (g_hakx_env_parsed) return;
|
|
const char* s = getenv("HAKX_BACKEND");
|
|
if (s) {
|
|
if (strcmp(s, "mi") == 0) g_hakx_backend = HAKX_B_MI;
|
|
else if (strcmp(s, "sys") == 0) g_hakx_backend = HAKX_B_SYS;
|
|
else g_hakx_backend = HAKX_B_HAKMEM;
|
|
}
|
|
const char* tuner = getenv("HAKX_L25_TUNER");
|
|
if (tuner && atoi(tuner) != 0) {
|
|
hakx_l25_tuner_start();
|
|
}
|
|
g_hakx_env_parsed = 1;
|
|
}
|
|
|
|
void* hakx_malloc(size_t size) {
|
|
hakx_parse_backend_once();
|
|
switch (g_hakx_backend) {
|
|
case HAKX_B_MI: return mi_malloc ? mi_malloc(size) : malloc(size);
|
|
case HAKX_B_SYS: return malloc(size);
|
|
default: {
|
|
if (hakx_tiny_can_handle(size)) {
|
|
void* p = hakx_tiny_alloc(size);
|
|
if (p) return p;
|
|
// Tiny miss: fall through
|
|
}
|
|
return hak_alloc_at(size, HAK_CALLSITE());
|
|
}
|
|
}
|
|
}
|
|
|
|
void hakx_free(void* ptr) {
|
|
hakx_parse_backend_once();
|
|
if (!ptr) return;
|
|
switch (g_hakx_backend) {
|
|
case HAKX_B_MI: if (mi_free) mi_free(ptr); else free(ptr); break;
|
|
case HAKX_B_SYS: free(ptr); break;
|
|
default:
|
|
if (hakx_tiny_maybe_free(ptr)) break;
|
|
hak_free_at(ptr, 0, HAK_CALLSITE());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void* hakx_realloc(void* ptr, size_t new_size) {
|
|
if (!ptr) return hakx_malloc(new_size);
|
|
if (new_size == 0) { hakx_free(ptr); return NULL; }
|
|
hakx_parse_backend_once();
|
|
switch (g_hakx_backend) {
|
|
case HAKX_B_MI:
|
|
return mi_realloc ? mi_realloc(ptr, new_size) : realloc(ptr, new_size);
|
|
case HAKX_B_SYS:
|
|
return realloc(ptr, new_size);
|
|
default: {
|
|
void* np = hak_alloc_at(new_size, HAK_CALLSITE());
|
|
if (!np) return NULL;
|
|
memcpy(np, ptr, new_size);
|
|
hak_free_at(ptr, 0, HAK_CALLSITE());
|
|
return np;
|
|
}
|
|
}
|
|
}
|
|
|
|
void* hakx_calloc(size_t n, size_t size) {
|
|
size_t total;
|
|
if (__builtin_mul_overflow(n, size, &total)) return NULL;
|
|
hakx_parse_backend_once();
|
|
switch (g_hakx_backend) {
|
|
case HAKX_B_MI: return mi_calloc ? mi_calloc(n, size) : calloc(n, size);
|
|
case HAKX_B_SYS: return calloc(n, size);
|
|
default: {
|
|
void* p = hak_alloc_at(total, HAK_CALLSITE());
|
|
if (p) memset(p, 0, total);
|
|
return p;
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t hakx_usable_size(void* ptr) {
|
|
(void)ptr;
|
|
// Not exposed in public HAKMEM header; return 0 for now.
|
|
return 0;
|
|
}
|
|
|
|
void hakx_trim(void) {
|
|
// Future: call tiny/SS trim once exported; currently no-op
|
|
}
|