Files
hakmem/tests/test_tls_ss_hint.c
Moe Charm (CI) 94f9ea5104 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

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;
}