251 lines
6.6 KiB
C
251 lines
6.6 KiB
C
|
|
// 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;
|
||
|
|
}
|