Files
hakmem/tests/test_tls_ss_hint.c

251 lines
6.6 KiB
C
Raw Normal View History

Implement Phase 1: TLS SuperSlab Hint Box for Headerless performance Design: Cache recently-used SuperSlab references in TLS to accelerate ptr→SuperSlab resolution in Headerless mode free() path. ## Implementation ### New Box: core/box/tls_ss_hint_box.h - Header-only Box (4-slot FIFO cache per thread) - Functions: tls_ss_hint_init(), tls_ss_hint_update(), tls_ss_hint_lookup(), tls_ss_hint_clear() - Memory overhead: 112 bytes per thread (negligible) - Statistics API for debug builds (hit/miss counters) ### Integration Points 1. **Free path** (core/hakmem_tiny_free.inc): - Lines 477-481: Fast path hint lookup before hak_super_lookup() - Lines 550-555: Second lookup location (fallback path) - Expected savings: 10-50 cycles → 2-5 cycles on cache hit 2. **Allocation path** (core/tiny_superslab_alloc.inc.h): - Lines 115-122: Linear allocation return path - Lines 179-186: Freelist allocation return path - Cache update on successful allocation 3. **TLS variable** (core/hakmem_tiny_tls_state_box.inc): - `__thread TlsSsHintCache g_tls_ss_hint = {0};` ### Build System - **Build flag** (core/hakmem_build_flags.h): - HAKMEM_TINY_SS_TLS_HINT (default: 0, disabled) - Validation: requires HAKMEM_TINY_HEADERLESS=1 - **Makefile**: - Removed old ss_tls_hint_box.o (conflicting implementation) - Header-only design eliminates compiled object files ### Testing - **Unit tests** (tests/test_tls_ss_hint.c): - 6 test functions covering init, lookup, FIFO rotation, duplicates, clear, stats - All tests PASSING - **Build validation**: - ✅ Compiles with hint disabled (default) - ✅ Compiles with hint enabled (HAKMEM_TINY_SS_TLS_HINT=1) ### Documentation - **Benchmark report** (docs/PHASE1_TLS_HINT_BENCHMARK.md): - Implementation summary - Build validation results - Benchmark methodology (to be executed) - Performance analysis framework ## Expected Performance - **Hit rate**: 85-95% (single-threaded), 70-85% (multi-threaded) - **Cycle savings**: 80-95% on cache hit (10-50 cycles → 2-5 cycles) - **Target improvement**: 15-20% throughput increase vs Headerless baseline - **Memory overhead**: 112 bytes per thread ## Box Theory **Mission**: Cache hot SuperSlabs to avoid global registry lookup **Boundary**: ptr → SuperSlab* or NULL (miss) **Invariant**: hint.base ≤ ptr < hint.end → hit is valid **Fallback**: Always safe to miss (triggers hak_super_lookup) **Thread Safety**: TLS storage, no synchronization required **Risk**: Low (read-only cache, fail-safe fallback, magic validation) ## Next Steps 1. Run full benchmark suite (sh8bench, cfrac, larson) 2. Measure actual hit rate with stats enabled 3. If performance target met (15-20% improvement), enable by default 4. Consider increasing cache slots if hit rate < 80% 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 18:06:24 +09:00
// test_tls_ss_hint.c - Unit tests for TLS SuperSlab Hint Box
//
// Purpose: Validate TLS hint cache behavior (init, update, lookup, FIFO rotation)
// Build: gcc -o test_tls_ss_hint test_tls_ss_hint.c -I../core -DHAKMEM_TINY_SS_TLS_HINT=1
// Run: ./test_tls_ss_hint
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
// Define build flags for test compilation
#ifndef HAKMEM_BUILD_RELEASE
#define HAKMEM_BUILD_RELEASE 0
#endif
#ifndef HAKMEM_TINY_SS_TLS_HINT
#define HAKMEM_TINY_SS_TLS_HINT 1
#endif
// Include the hint box header
#include "box/tls_ss_hint_box.h"
// Mock SuperSlab for testing
#define SUPERSLAB_MAGIC 0x5353504C // 'SSPL'
typedef struct SuperSlab {
uint32_t magic;
uint8_t lg_size;
uint8_t _pad[3];
} SuperSlab;
// Define the TLS variable (normally in hakmem_tiny_tls_state_box.inc)
__thread TlsSsHintCache g_tls_ss_hint = {0};
// ============================================================================
// Test Functions
// ============================================================================
void test_hint_init(void) {
printf("test_hint_init...\n");
tls_ss_hint_init();
// Verify cache is empty
assert(g_tls_ss_hint.count == 0);
assert(g_tls_ss_hint.next_slot == 0);
#if !HAKMEM_BUILD_RELEASE
assert(g_tls_ss_hint.hits == 0);
assert(g_tls_ss_hint.misses == 0);
#endif
printf(" PASS\n");
}
void test_hint_basic(void) {
printf("test_hint_basic...\n");
tls_ss_hint_init();
// Mock SuperSlab
SuperSlab ss = {
.magic = SUPERSLAB_MAGIC,
.lg_size = 21, // 2MB
};
void* ss_base = (void*)0x1000000;
size_t ss_size = 2 * 1024 * 1024; // 2MB
// Update hint
tls_ss_hint_update(&ss, ss_base, ss_size);
// Verify cache entry
assert(g_tls_ss_hint.count == 1);
assert(g_tls_ss_hint.entries[0].base == ss_base);
assert(g_tls_ss_hint.entries[0].ss == &ss);
// Lookup should hit (within range)
SuperSlab* out = NULL;
assert(tls_ss_hint_lookup((void*)0x1000100, &out) == true);
assert(out == &ss);
// Lookup at base should hit
assert(tls_ss_hint_lookup((void*)0x1000000, &out) == true);
assert(out == &ss);
// Lookup at end-1 should hit
assert(tls_ss_hint_lookup((void*)0x11FFFFF, &out) == true);
assert(out == &ss);
// Lookup at end should miss (exclusive boundary)
assert(tls_ss_hint_lookup((void*)0x1200000, &out) == false);
// Lookup outside range should miss
assert(tls_ss_hint_lookup((void*)0x3000000, &out) == false);
printf(" PASS\n");
}
void test_hint_fifo_rotation(void) {
printf("test_hint_fifo_rotation...\n");
tls_ss_hint_init();
// Create 6 mock SuperSlabs (cache has 4 slots)
SuperSlab ss[6];
for (int i = 0; i < 6; i++) {
ss[i].magic = SUPERSLAB_MAGIC;
ss[i].lg_size = 21; // 2MB
void* base = (void*)(uintptr_t)(0x1000000 + i * 0x200000); // 2MB apart
size_t size = 2 * 1024 * 1024;
tls_ss_hint_update(&ss[i], base, size);
}
// Cache should be full (4 slots)
assert(g_tls_ss_hint.count == TLS_SS_HINT_SLOTS);
// First 2 SuperSlabs should be evicted (FIFO)
SuperSlab* out = NULL;
assert(tls_ss_hint_lookup((void*)0x1000100, &out) == false); // ss[0] evicted
assert(tls_ss_hint_lookup((void*)0x1200100, &out) == false); // ss[1] evicted
// Last 4 SuperSlabs should be cached
assert(tls_ss_hint_lookup((void*)0x1400100, &out) == true); // ss[2]
assert(out == &ss[2]);
assert(tls_ss_hint_lookup((void*)0x1600100, &out) == true); // ss[3]
assert(out == &ss[3]);
assert(tls_ss_hint_lookup((void*)0x1800100, &out) == true); // ss[4]
assert(out == &ss[4]);
assert(tls_ss_hint_lookup((void*)0x1A00100, &out) == true); // ss[5]
assert(out == &ss[5]);
printf(" PASS\n");
}
void test_hint_duplicate_detection(void) {
printf("test_hint_duplicate_detection...\n");
tls_ss_hint_init();
// Mock SuperSlab
SuperSlab ss = {
.magic = SUPERSLAB_MAGIC,
.lg_size = 21, // 2MB
};
void* ss_base = (void*)0x1000000;
size_t ss_size = 2 * 1024 * 1024;
// Update hint 3 times with same SuperSlab
tls_ss_hint_update(&ss, ss_base, ss_size);
tls_ss_hint_update(&ss, ss_base, ss_size);
tls_ss_hint_update(&ss, ss_base, ss_size);
// Cache should have only 1 entry (duplicates ignored)
assert(g_tls_ss_hint.count == 1);
assert(g_tls_ss_hint.entries[0].ss == &ss);
printf(" PASS\n");
}
void test_hint_clear(void) {
printf("test_hint_clear...\n");
tls_ss_hint_init();
// Add some entries
SuperSlab ss = {
.magic = SUPERSLAB_MAGIC,
.lg_size = 21, // 2MB
};
void* ss_base = (void*)0x1000000;
size_t ss_size = 2 * 1024 * 1024;
tls_ss_hint_update(&ss, ss_base, ss_size);
assert(g_tls_ss_hint.count == 1);
// Clear cache
tls_ss_hint_clear();
// Cache should be empty
assert(g_tls_ss_hint.count == 0);
assert(g_tls_ss_hint.next_slot == 0);
// Lookup should miss
SuperSlab* out = NULL;
assert(tls_ss_hint_lookup((void*)0x1000100, &out) == false);
printf(" PASS\n");
}
#if !HAKMEM_BUILD_RELEASE
void test_hint_stats(void) {
printf("test_hint_stats...\n");
tls_ss_hint_init();
// Add entry
SuperSlab ss = {
.magic = SUPERSLAB_MAGIC,
.lg_size = 21, // 2MB
};
void* ss_base = (void*)0x1000000;
size_t ss_size = 2 * 1024 * 1024;
tls_ss_hint_update(&ss, ss_base, ss_size);
// Perform lookups
SuperSlab* out = NULL;
tls_ss_hint_lookup((void*)0x1000100, &out); // Hit
tls_ss_hint_lookup((void*)0x1000200, &out); // Hit
tls_ss_hint_lookup((void*)0x3000000, &out); // Miss
// Check stats
uint64_t hits = 0, misses = 0;
tls_ss_hint_stats(&hits, &misses);
assert(hits == 2);
assert(misses == 1);
printf(" PASS\n");
}
#endif
// ============================================================================
// Main Test Runner
// ============================================================================
int main(void) {
printf("===========================================\n");
printf("TLS SuperSlab Hint Box - Unit Tests\n");
printf("===========================================\n\n");
test_hint_init();
test_hint_basic();
test_hint_fifo_rotation();
test_hint_duplicate_detection();
test_hint_clear();
#if !HAKMEM_BUILD_RELEASE
test_hint_stats();
#endif
printf("\n===========================================\n");
printf("All tests PASSED!\n");
printf("===========================================\n");
return 0;
}