// 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 #include #include #include // 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; }