Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
57 lines
2.2 KiB
C++
57 lines
2.2 KiB
C++
// hakmem_tiny_remote.inc
|
|
// Remote free operations for TinySlab cross-thread deallocation
|
|
|
|
static void tiny_remote_push(struct TinySlab* slab, void* ptr) {
|
|
if (!slab || !ptr) return;
|
|
|
|
// Push to slab's remote freelist using atomic operations
|
|
uintptr_t old_head = atomic_load_explicit(&slab->remote_head, memory_order_relaxed);
|
|
do {
|
|
*(uintptr_t*)ptr = old_head;
|
|
} while (!atomic_compare_exchange_weak_explicit(&slab->remote_head, &old_head, (uintptr_t)ptr,
|
|
memory_order_release,
|
|
memory_order_relaxed));
|
|
atomic_fetch_add_explicit(&slab->remote_count, 1, memory_order_relaxed);
|
|
}
|
|
|
|
static void tiny_remote_drain_locked(struct TinySlab* slab) {
|
|
if (!slab) return;
|
|
|
|
// Drain remote frees (assumes lock held on slab)
|
|
uintptr_t remote = atomic_exchange_explicit(&slab->remote_head, 0, memory_order_acquire);
|
|
uint32_t remote_cnt = atomic_exchange_explicit(&slab->remote_count, 0, memory_order_relaxed);
|
|
|
|
if (!remote || remote_cnt == 0) return;
|
|
|
|
// Process each remote free: mark the block as free in the bitmap
|
|
while (remote && remote_cnt > 0) {
|
|
uintptr_t next = *(uintptr_t*)remote;
|
|
|
|
// Mark block as free in bitmap
|
|
uintptr_t offset = remote - (uintptr_t)slab->base;
|
|
size_t block_size = g_tiny_class_sizes[slab->class_idx];
|
|
size_t block_idx = offset / block_size;
|
|
|
|
if (block_idx < slab->total_count) {
|
|
size_t word_idx = block_idx / 64;
|
|
size_t bit_idx = block_idx % 64;
|
|
slab->bitmap[word_idx] &= ~(1UL << bit_idx); // Clear bit = free
|
|
slab->free_count++;
|
|
}
|
|
|
|
remote = next;
|
|
remote_cnt--;
|
|
}
|
|
}
|
|
|
|
static inline void tiny_remote_drain_owner(struct TinySlab* slab) {
|
|
if (!slab) return;
|
|
if (!pthread_equal(slab->owner_tid, tiny_self_pt())) return;
|
|
if (atomic_load_explicit(&slab->remote_count, memory_order_relaxed) == 0) return;
|
|
|
|
pthread_mutex_t* lock = &g_tiny_class_locks[slab->class_idx].m;
|
|
if (pthread_mutex_trylock(lock) != 0) return;
|
|
tiny_remote_drain_locked(slab);
|
|
pthread_mutex_unlock(lock);
|
|
}
|