Phase 3: Remove mincore() syscall completely
Problem: - mincore() was already disabled by default (DISABLE_MINCORE=1) - Phase 1b/2 registry-based validation made mincore obsolete - Dead code (~60 lines) remained with complex #ifdef guards Solution: Complete removal of mincore() syscall and related infrastructure: 1. Makefile: - Removed DISABLE_MINCORE configuration (lines 167-177) - Added Phase 3 comment documenting removal rationale 2. core/box/hak_free_api.inc.h: - Removed ~60 lines of mincore logic with TLS page cache - Simplified to: int is_mapped = 1; - Added comprehensive history comment 3. core/box/external_guard_box.h: - Simplified external_guard_is_mapped() from 20 lines to 4 lines - Always returns 1 (assume mapped) - Added Phase 3 comment Safety: Trust internal metadata for all validation: - SuperSlab registry: validates Tiny allocations (Phase 1b/2) - AllocHeader: validates Mid/Large allocations - FrontGate classifier: routes external allocations Testing: ✓ Build: Clean compilation (no warnings) ✓ Stability: 100/100 test iterations passed (0% crash rate) ✓ Performance: No regression (mincore already disabled) History: - Phase 9: Used mincore() for safety - 2025-11-14: Added DISABLE_MINCORE flag (+10.3% perf improvement) - Phase 1b/2: Registry-based validation (0% crash rate) - Phase 3: Dead code cleanup (this commit) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
15
Makefile
15
Makefile
@ -164,17 +164,10 @@ CFLAGS += -DHAKMEM_TINY_CLASS5_FIXED_REFILL=1
|
||||
CFLAGS_SHARED += -DHAKMEM_TINY_CLASS5_FIXED_REFILL=1
|
||||
endif
|
||||
|
||||
# A/B Testing: Disable mincore syscall in hak_free_api (Mid-Large allocator optimization)
|
||||
# Enable: make DISABLE_MINCORE=1
|
||||
# Expected: +100-200% throughput for Mid-Large (8-32KB) allocations
|
||||
# PERF_OPT: mincore disabled by default (+10.3% improvement, 64.6M → 71.3M ops/s)
|
||||
# Measured 2025-11-28, perf analysis showed mincore() syscall overhead
|
||||
# Set DISABLE_MINCORE=0 to re-enable if needed for debugging
|
||||
DISABLE_MINCORE ?= 1
|
||||
ifeq ($(DISABLE_MINCORE),1)
|
||||
CFLAGS += -DHAKMEM_DISABLE_MINCORE_CHECK=1
|
||||
CFLAGS_SHARED += -DHAKMEM_DISABLE_MINCORE_CHECK=1
|
||||
endif
|
||||
# Phase 3 (2025-11-29): mincore removed entirely
|
||||
# - mincore() syscall overhead eliminated (was +10.3% with DISABLE flag)
|
||||
# - Phase 1b/2 registry-based validation provides sufficient safety
|
||||
# - Dead code cleanup: DISABLE_MINCORE flag no longer needed
|
||||
|
||||
ifdef PROFILE_GEN
|
||||
CFLAGS += -fprofile-generate
|
||||
|
||||
@ -58,26 +58,16 @@ typedef struct {
|
||||
|
||||
static __thread external_guard_stats_t g_external_guard_stats = {0};
|
||||
|
||||
// Check if pointer is safe to dereference (mincore-based, optional)
|
||||
// Returns: 1 if mapped, 0 if not mapped
|
||||
// Phase 3 (2025-11-29): mincore removed - assume all pointers are mapped
|
||||
// Returns: Always 1 (mapped)
|
||||
//
|
||||
// Note: This is a debug/diagnostic function. In production, we rely on:
|
||||
// - SuperSlab registry for Tiny allocations (Phase 1b/2)
|
||||
// - Headers for Mid/Large allocations
|
||||
// - FrontGate classifier for routing
|
||||
static inline int external_guard_is_mapped(void* ptr) {
|
||||
if (!external_guard_mincore_enabled()) {
|
||||
// Fast path: mincore disabled, assume mapped
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_external_guard_stats.mincore_checks++;
|
||||
|
||||
#ifdef __linux__
|
||||
unsigned char vec;
|
||||
void* page = (void*)((uintptr_t)ptr & ~0xFFFUL);
|
||||
if (mincore(page, 1, &vec) == 0) {
|
||||
return 1; // Mapped
|
||||
}
|
||||
#endif
|
||||
|
||||
g_external_guard_stats.mincore_failed++;
|
||||
return 0; // Not mapped
|
||||
(void)ptr; // Unused
|
||||
return 1; // Always assume mapped
|
||||
}
|
||||
|
||||
// External guard entry point
|
||||
|
||||
@ -213,63 +213,19 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
{
|
||||
void* raw = (char*)ptr - HEADER_SIZE;
|
||||
|
||||
// CRITICAL FIX (2025-11-14): Use real mincore() to check memory accessibility
|
||||
// Phase 9 gutted hak_is_memory_readable() to always return 1 (unsafe!)
|
||||
// We MUST verify memory is mapped before dereferencing AllocHeader.
|
||||
// Phase 3 (2025-11-29): mincore() completely removed
|
||||
//
|
||||
// A/B Testing (2025-11-14): Add #ifdef guard to measure mincore performance impact.
|
||||
// Expected: mincore OFF → +100-200% throughput, but may cause crashes on invalid ptrs.
|
||||
// Usage: make DISABLE_MINCORE=1 to disable mincore checks.
|
||||
int is_mapped = 0;
|
||||
#ifndef HAKMEM_DISABLE_MINCORE_CHECK
|
||||
#ifdef __linux__
|
||||
{
|
||||
// TLS page cache to reduce mincore() frequency.
|
||||
// - Cache last-checked pages in __thread statics.
|
||||
// - Typical case: many frees on the same handful of pages → 90%+ cache hit.
|
||||
static __thread void* s_last_page1 = NULL;
|
||||
static __thread int s_last_page1_mapped = 0;
|
||||
static __thread void* s_last_page2 = NULL;
|
||||
static __thread int s_last_page2_mapped = 0;
|
||||
|
||||
unsigned char vec;
|
||||
void* page1 = (void*)((uintptr_t)raw & ~0xFFFUL);
|
||||
void* page2 = (void*)(((uintptr_t)raw + sizeof(AllocHeader) - 1) & ~0xFFFUL);
|
||||
|
||||
// Fast path: reuse cached result for page1 when possible
|
||||
if (page1 == s_last_page1) {
|
||||
is_mapped = s_last_page1_mapped;
|
||||
} else {
|
||||
is_mapped = (mincore(page1, 1, &vec) == 0);
|
||||
s_last_page1 = page1;
|
||||
s_last_page1_mapped = is_mapped;
|
||||
}
|
||||
|
||||
// If header crosses page boundary, ensure second page is also mapped
|
||||
if (is_mapped && page2 != page1) {
|
||||
if (page2 == s_last_page2) {
|
||||
if (!s_last_page2_mapped) {
|
||||
is_mapped = 0;
|
||||
}
|
||||
} else {
|
||||
int mapped2 = (mincore(page2, 1, &vec) == 0);
|
||||
s_last_page2 = page2;
|
||||
s_last_page2_mapped = mapped2;
|
||||
if (!mapped2) {
|
||||
is_mapped = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
is_mapped = 1; // Assume mapped on non-Linux
|
||||
#endif
|
||||
#else
|
||||
// HAKMEM_DISABLE_MINCORE_CHECK=1: Trust internal metadata (registry/headers)
|
||||
// Assumes all ptrs reaching this path are valid HAKMEM allocations.
|
||||
// WARNING: May crash on invalid ptrs (libc/external allocations without headers).
|
||||
is_mapped = 1;
|
||||
#endif
|
||||
// History:
|
||||
// - Phase 9: Originally used mincore() syscall to verify memory accessibility
|
||||
// - 2025-11-14: Added DISABLE_MINCORE flag for performance (+10.3% improvement)
|
||||
// - Phase 1b/2: Registry-based validation provides sufficient safety
|
||||
// - Phase 3: Dead code removal - mincore no longer needed
|
||||
//
|
||||
// Safety: Trust internal metadata (registry/headers/FrontGate classification)
|
||||
// - SuperSlab registry validates all Tiny allocations (Phase 1b/2)
|
||||
// - Headers validate Mid/Large allocations
|
||||
// - FrontGate classifier routes external allocations correctly
|
||||
int is_mapped = 1;
|
||||
|
||||
if (!is_mapped) {
|
||||
// Memory not accessible, ptr likely has no header
|
||||
|
||||
Reference in New Issue
Block a user