- Root cause: header-based class indexing (HEADER_CLASSIDX=1) wrote a 1-byte header during allocation, but linear carve/refill and initial slab capacity still used bare class block sizes. This mismatch could overrun slab usable space and corrupt freelists, causing reproducible SEGV at ~100k iters. Changes - Superslab: compute capacity with effective stride (block_size + header for classes 0..6; class7 remains headerless) in superslab_init_slab(). Add a debug-only bound check in superslab_alloc_from_slab() to fail fast if carve would exceed usable bytes. - Refill (non-P0 and P0): use header-aware stride for all linear carving and TLS window bump operations. Ensure alignment/validation in tiny_refill_opt.h also uses stride, not raw class size. - Drain: keep existing defense-in-depth for remote sentinel and sanitize nodes before splicing into freelist (already present). Notes - This unifies the memory layout across alloc/linear-carve/refill with a single stride definition and keeps class7 (1024B) headerless as designed. - Debug builds add fail-fast checks; release builds remain lean. Next - Re-run Tiny benches (256/1024B) in debug to confirm stability, then in release. If any remaining crash persists, bisect with HAKMEM_TINY_P0_BATCH_REFILL=0 to isolate P0 batch carve, and continue reducing branch-miss as planned.
131 lines
4.6 KiB
C
131 lines
4.6 KiB
C
// ace_pool_connector.c - ACE-Pool Connection Box Implementation
|
|
|
|
#include "ace_pool_connector.h"
|
|
#include "../hakmem_pool.h"
|
|
#include "../hakmem_ace_controller.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// External references (from Pool)
|
|
extern struct Pool {
|
|
int initialized;
|
|
// ... other fields
|
|
} g_pool;
|
|
|
|
extern size_t g_class_sizes[7]; // Pool class sizes
|
|
extern int g_wrap_l2_enabled;
|
|
|
|
// ============================================================================
|
|
// Box Implementation
|
|
// ============================================================================
|
|
|
|
AcePoolHealth ace_pool_get_health(void) {
|
|
AcePoolHealth health;
|
|
memset(&health, 0, sizeof(health));
|
|
|
|
// Check Pool initialization
|
|
health.pool_initialized = g_pool.initialized;
|
|
|
|
// Check ACE status
|
|
const char* ace_env = getenv("HAKMEM_ACE_ENABLED");
|
|
health.ace_enabled = (ace_env && atoi(ace_env) == 1);
|
|
|
|
// Check WRAP_L2 status
|
|
health.wrap_l2_enabled = g_wrap_l2_enabled;
|
|
|
|
// Check Bridge classes
|
|
health.bridge_class_5_size = (int)g_class_sizes[5];
|
|
health.bridge_class_6_size = (int)g_class_sizes[6];
|
|
|
|
// TODO: Track pre-allocated pages count
|
|
health.preallocated_pages = 0; // Not yet tracked
|
|
|
|
// Determine overall status
|
|
if (!health.pool_initialized) {
|
|
health.status = ACE_POOL_NOT_INIT;
|
|
health.message = "Pool not initialized";
|
|
} else if (!health.ace_enabled) {
|
|
health.status = ACE_POOL_NOT_INIT;
|
|
health.message = "ACE not enabled (set HAKMEM_ACE_ENABLED=1)";
|
|
} else if (!health.wrap_l2_enabled) {
|
|
health.status = ACE_POOL_WRAPPER_BLOCKED;
|
|
health.message = "WRAP_L2 not enabled (set HAKMEM_WRAP_L2=1)";
|
|
} else if (health.bridge_class_5_size == 0 && health.bridge_class_6_size == 0) {
|
|
health.status = ACE_POOL_SIZE_MISMATCH;
|
|
health.message = "Bridge classes disabled (class 5 and 6 are 0)";
|
|
} else if (health.preallocated_pages == 0) {
|
|
health.status = ACE_POOL_NO_PAGES;
|
|
health.message = "No pre-allocated pages (performance will be degraded)";
|
|
} else {
|
|
health.status = ACE_POOL_OK;
|
|
health.message = "ACE-Pool connection healthy";
|
|
}
|
|
|
|
return health;
|
|
}
|
|
|
|
int ace_pool_validate_connection(AcePoolStatus* out_status) {
|
|
AcePoolHealth health = ace_pool_get_health();
|
|
|
|
if (out_status) {
|
|
*out_status = health.status;
|
|
}
|
|
|
|
// Only OK status is considered "ready"
|
|
// NO_PAGES is warning but still functional
|
|
return (health.status == ACE_POOL_OK || health.status == ACE_POOL_NO_PAGES);
|
|
}
|
|
|
|
void* ace_pool_try_alloc(size_t size, uintptr_t site_id, AcePoolStatus* out_status) {
|
|
// Validate connection first
|
|
AcePoolStatus status;
|
|
if (!ace_pool_validate_connection(&status)) {
|
|
if (out_status) *out_status = status;
|
|
|
|
// Log why allocation failed
|
|
AcePoolHealth health = ace_pool_get_health();
|
|
static int logged_once = 0;
|
|
if (!logged_once) {
|
|
fprintf(stderr, "[ACE-Pool Connector] BLOCKED: %s\n", health.message);
|
|
logged_once = 1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Connection validated, try Pool allocation
|
|
void* ptr = hak_pool_try_alloc(size, site_id);
|
|
|
|
if (ptr) {
|
|
if (out_status) *out_status = ACE_POOL_OK;
|
|
} else {
|
|
if (out_status) *out_status = ACE_POOL_ALLOC_FAILED;
|
|
|
|
// Log allocation failure (but only once to avoid spam)
|
|
static int fail_logged = 0;
|
|
if (!fail_logged) {
|
|
fprintf(stderr, "[ACE-Pool Connector] Pool allocation failed for size=%zu (will fallback to mmap)\n", size);
|
|
fail_logged = 1;
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void ace_pool_print_health(void) {
|
|
AcePoolHealth health = ace_pool_get_health();
|
|
|
|
fprintf(stderr, "\n=== ACE-Pool Connector Health Check ===\n");
|
|
fprintf(stderr, "Pool Initialized: %s\n", health.pool_initialized ? "YES" : "NO");
|
|
fprintf(stderr, "ACE Enabled: %s\n", health.ace_enabled ? "YES" : "NO");
|
|
fprintf(stderr, "WRAP_L2 Enabled: %s\n", health.wrap_l2_enabled ? "YES" : "NO");
|
|
fprintf(stderr, "Bridge Class 5: %d KB (%s)\n",
|
|
health.bridge_class_5_size / 1024,
|
|
health.bridge_class_5_size > 0 ? "ENABLED" : "DISABLED");
|
|
fprintf(stderr, "Bridge Class 6: %d KB (%s)\n",
|
|
health.bridge_class_6_size / 1024,
|
|
health.bridge_class_6_size > 0 ? "ENABLED" : "DISABLED");
|
|
fprintf(stderr, "Pre-allocated Pages: %d\n", health.preallocated_pages);
|
|
fprintf(stderr, "Status: %s\n", health.message);
|
|
fprintf(stderr, "========================================\n\n");
|
|
}
|