Files
hakmem/core/hakmem_tiny_stats.c
Moe Charm (CI) 9b0d746407 Phase 3d-B: TLS Cache Merge - Unified g_tls_sll[] structure (+12-18% expected)
Merge separate g_tls_sll_head[] and g_tls_sll_count[] arrays into unified
TinyTLSSLL struct to improve L1D cache locality. Expected performance gain:
+12-18% from reducing cache line splits (2 loads → 1 load per operation).

Changes:
- core/hakmem_tiny.h: Add TinyTLSSLL type (16B aligned, head+count+pad)
- core/hakmem_tiny.c: Replace separate arrays with g_tls_sll[8]
- core/box/tls_sll_box.h: Update Box API (13 sites) for unified access
- Updated 32+ files: All g_tls_sll_head[i] → g_tls_sll[i].head
- Updated 32+ files: All g_tls_sll_count[i] → g_tls_sll[i].count
- core/hakmem_tiny_integrity.h: Unified canary guards
- core/box/integrity_box.c: Simplified canary validation
- Makefile: Added core/box/tiny_sizeclass_hist_box.o to link

Build:  PASS (10K ops sanity test)
Warnings: Only pre-existing LTO type mismatches (unrelated)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 07:32:30 +09:00

831 lines
38 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// hakmem_tiny_stats.c
// Phase 2, Module 1: Statistics and Debug Functions
// Extracted from hakmem_tiny.c (lines 4348-4728, non-contiguous)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include "hakmem_tiny.h"
#include "hakmem_tiny_config.h" // extern g_tiny_class_sizes
#include "hakmem_tiny_stats_api.h"
#include <signal.h>
static int g_dump_atexit_only = -1; // env: HAKMEM_TINY_DUMP_ATEXIT_ONLY=1
// Forward declaration of local dump (defined later in this file)
static void hak_tiny_refill_counters_dump(void);
static void hak_tiny_stats_init_flags(void) {
if (g_dump_atexit_only == -1) {
const char* e = getenv("HAKMEM_TINY_DUMP_ATEXIT_ONLY");
g_dump_atexit_only = (e && atoi(e) != 0) ? 1 : 0;
}
}
void hak_tiny_dump_all_counters_now(void) {
// Dump both minimal and extended (if compiled)
hak_tiny_refill_counters_dump();
hak_tiny_debug_counters_dump();
}
_Atomic int g_tiny_sukesuke_pending = 0;
_Atomic int g_tiny_sukesuke_dumping = 0;
static void hak_tiny_sig_handler(int signo) {
(void)signo;
atomic_store_explicit(&g_tiny_sukesuke_pending, 1, memory_order_release);
static const char msg[] = "[SUKESUKE] dump requested\n";
ssize_t written = write(STDERR_FILENO, msg, sizeof(msg) - 1);
(void)written;
}
void hak_tiny_stats_handle_signal(void) {
int pending = atomic_exchange_explicit(&g_tiny_sukesuke_pending, 0, memory_order_acq_rel);
if (!pending) return;
if (atomic_exchange_explicit(&g_tiny_sukesuke_dumping, 1, memory_order_acq_rel) != 0) {
// Another thread is already dumping; restore request for later.
atomic_store_explicit(&g_tiny_sukesuke_pending, 1, memory_order_release);
return;
}
hak_tiny_dump_all_counters_now();
atomic_store_explicit(&g_tiny_sukesuke_dumping, 0, memory_order_release);
}
void hak_tiny_enable_signal_dump(void) {
const char* s = getenv("HAKMEM_TINY_SUKESUKE");
if (!(s && atoi(s) != 0)) return;
struct sigaction sa;
sa.sa_handler = hak_tiny_sig_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, NULL);
fprintf(stderr, "[SUKESUKE] SIGUSR1 dump enabled\n");
}
__attribute__((constructor))
static void hak_tiny_signal_dump_ctor(void) {
// Early install to catch signals before tiny init
const char* s = getenv("HAKMEM_TINY_SUKESUKE");
if (s && atoi(s) != 0) {
hak_tiny_enable_signal_dump();
}
}
#include "hakmem_tiny_superslab.h"
#include "hakmem_config.h"
#include "hakmem_tiny_stats.h"
// ============================================================================
// Phase 8.1: Public Statistics API (lines 4348-4415)
// ============================================================================
void hak_tiny_get_stats(uint64_t* alloc_count, uint64_t* free_count, uint64_t* slab_count) {
if (!g_tiny_initialized) return;
#ifdef HAKMEM_ENABLE_STATS
// Flush TLS batches to global counters for accurate stats
stats_flush_all();
#endif
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
if (alloc_count) alloc_count[i] = g_tiny_pool.alloc_count[i];
if (free_count) free_count[i] = g_tiny_pool.free_count[i];
if (slab_count) slab_count[i] = g_tiny_pool.slab_count[i];
}
}
void hak_tiny_print_stats(void) {
if (!g_tiny_initialized) {
printf("Tiny Pool not initialized\n");
return;
}
printf("\n");
printf("Tiny Pool Statistics\n");
printf("========================================\n");
printf("Class | Size | Allocs | Frees | Slabs\n");
printf("------|--------|---------|---------|-------\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
printf(" %d | %4zuB | %7lu | %7lu | %5lu\n",
i,
g_tiny_class_sizes[i],
(unsigned long)g_tiny_pool.alloc_count[i],
(unsigned long)g_tiny_pool.free_count[i],
(unsigned long)g_tiny_pool.slab_count[i]);
}
printf("========================================\n");
printf("\n");
#if HAKMEM_BUILD_DEBUG
printf("TLS Debug Counters (hit/miss/spill) per class\n");
printf("---------------------------------------------\n");
printf("Class | Hit | Miss | SpillSS | SpillOwner | SpillMag | SpillReq\n");
printf("------+-----------+-----------+-----------+-----------+-----------+-----------\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
printf(" %d | %9llu | %9llu | %9llu | %9llu | %9llu | %9llu\n",
i,
(unsigned long long)g_tls_hit_count[i],
(unsigned long long)g_tls_miss_count[i],
(unsigned long long)g_tls_spill_ss_count[i],
(unsigned long long)g_tls_spill_owner_count[i],
(unsigned long long)g_tls_spill_mag_count[i],
(unsigned long long)g_tls_spill_requeue_count[i]);
}
printf("---------------------------------------------\n\n");
// Observation snapshot (disabled unless Tiny obs is explicitly enabled)
#ifdef HAKMEM_TINY_OBS_ENABLE
extern unsigned long long g_obs_epoch;
extern unsigned int g_obs_interval;
typedef struct {
unsigned long long hit, miss, spill_ss, spill_owner, spill_mag, spill_requeue;
} TinyObsStats;
extern TinyObsStats g_obs_stats[TINY_NUM_CLASSES];
printf("Observation Snapshot (epoch %llu, interval %u events)\n",
(unsigned long long)g_obs_epoch,
g_obs_interval);
printf("Class | dHit | dMiss | dSpSS | dSpOwn | dSpMag | dSpReq\n");
printf("------+-----------+-----------+-----------+-----------+-----------+-----------\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
TinyObsStats* st = &g_obs_stats[i];
printf(" %d | %9llu | %9llu | %9llu | %9llu | %9llu | %9llu\n",
i,
(unsigned long long)st->hit,
(unsigned long long)st->miss,
(unsigned long long)st->spill_ss,
(unsigned long long)st->spill_owner,
(unsigned long long)st->spill_mag,
(unsigned long long)st->spill_requeue);
}
printf("---------------------------------------------\n\n");
#else
printf("Observation Snapshot: disabled (build-time)\n\n");
#endif
#endif
}
// ============================================================================
// Phase 8.2: Memory Profiling Debug (toggle with HAKMEM_DEBUG_MEMORY)
// ============================================================================
#ifdef HAKMEM_DEBUG_MEMORY
// NOTE: count_active_superslabs and hak_tiny_print_memory_profile are currently disabled
// due to missing type definitions (SUPER_REG_SIZE, TinyMagItem, etc.)
// Uncomment when these types are properly defined
#if 0 // Temporarily disabled
// Count active SuperSlabs by scanning the registry
static int count_active_superslabs(void) {
int count = 0;
for (int i = 0; i < SUPER_REG_SIZE; i++) {
if (g_super_reg[i].base != 0) {
count++;
}
}
return count;
}
// Print detailed memory breakdown by component
void hak_tiny_print_memory_profile_disabled(void) {
fprintf(stderr, "\n");
fprintf(stderr, "========================================\n");
fprintf(stderr, "HAKMEM Memory Profile (Phase 8.2)\n");
fprintf(stderr, "========================================\n");
// 1. TLS Magazine memory (per-thread)
size_t tls_mag_item_mem = sizeof(TinyMagItem) * TINY_TLS_MAG_CAP * TINY_NUM_CLASSES;
size_t tls_mag_meta = (sizeof(int) * 2) * TINY_NUM_CLASSES; // top + cap per class
size_t tls_mag_empty = sizeof(uint32_t) * TINY_NUM_CLASSES;
size_t tls_active_slabs = sizeof(TinySlab*) * TINY_NUM_CLASSES * 2; // a + b
size_t tls_total = tls_mag_item_mem + tls_mag_meta + tls_mag_empty + tls_active_slabs;
fprintf(stderr, "\n[TLS Magazine] (per thread)\n");
fprintf(stderr, " Items: %6zu KB (%d classes × %d cap × %zu bytes)\n",
tls_mag_item_mem / 1024, TINY_NUM_CLASSES, TINY_TLS_MAG_CAP, sizeof(TinyMagItem));
fprintf(stderr, " Metadata: %6zu B (top/cap counters)\n", tls_mag_meta);
fprintf(stderr, " Other TLS: %6zu B (empty flags + active slabs)\n",
tls_mag_empty + tls_active_slabs);
fprintf(stderr, " TLS Total: %6zu KB per thread\n", tls_total / 1024);
// 2. SuperSlab allocations
int superslab_count = count_active_superslabs();
size_t superslab_total = (size_t)superslab_count * SUPERSLAB_SIZE;
fprintf(stderr, "\n[SuperSlab] (global)\n");
fprintf(stderr, " Active: %6d blocks\n", superslab_count);
fprintf(stderr, " Size: %6zu KB each (2 MB)\n", SUPERSLAB_SIZE / 1024);
fprintf(stderr, " Total: %6zu KB (%d × 2 MB)\n",
superslab_total / 1024, superslab_count);
// 3. SuperSlab Registry
size_t registry_size = sizeof(SuperRegEntry) * SUPER_REG_SIZE;
fprintf(stderr, "\n[SuperSlab Registry] (global)\n");
fprintf(stderr, " Entries: %6d slots\n", SUPER_REG_SIZE);
fprintf(stderr, " Used: %6d slots\n", superslab_count);
fprintf(stderr, " Total: %6zu KB (%zu bytes/entry)\n",
registry_size / 1024, sizeof(SuperRegEntry));
// 4. Slab Registry (legacy hash table)
size_t slab_registry_size = sizeof(SlabRegistryEntry) * SLAB_REGISTRY_SIZE;
fprintf(stderr, "\n[Slab Registry] (global, legacy)\n");
fprintf(stderr, " Entries: %6d slots\n", SLAB_REGISTRY_SIZE);
fprintf(stderr, " Total: %6zu KB (%zu bytes/entry)\n",
slab_registry_size / 1024, sizeof(SlabRegistryEntry));
// 5. Other metadata
size_t locks_size = sizeof(PaddedLock) * TINY_NUM_CLASSES;
fprintf(stderr, "\n[Other Metadata] (global)\n");
fprintf(stderr, " Class locks: %6zu KB (%d classes × %zu bytes)\n",
locks_size / 1024, TINY_NUM_CLASSES, sizeof(PaddedLock));
// 6. Total overhead estimate (single-threaded)
size_t total_overhead = tls_total + superslab_total + registry_size +
slab_registry_size + locks_size;
fprintf(stderr, "\n========================================\n");
fprintf(stderr, "[Total Memory Overhead] (1 thread)\n");
fprintf(stderr, " TLS: %6zu KB\n", tls_total / 1024);
fprintf(stderr, " SuperSlabs: %6zu KB (%d active)\n",
superslab_total / 1024, superslab_count);
fprintf(stderr, " Registries: %6zu KB\n", (registry_size + slab_registry_size) / 1024);
fprintf(stderr, " Locks/Meta: %6zu KB\n", locks_size / 1024);
fprintf(stderr, " -------------\n");
fprintf(stderr, " TOTAL: %6zu KB (%.2f MB)\n",
total_overhead / 1024, total_overhead / (1024.0 * 1024.0));
fprintf(stderr, "========================================\n");
fprintf(stderr, "\n");
}
#endif // Temporarily disabled
#else
// Stub function when debug is disabled
void hak_tiny_print_memory_profile(void) {
// No-op in release builds
}
#endif // HAKMEM_DEBUG_MEMORY
// ============================================================================
// Debug Print Functions (always available, gated by HAKMEM_DEBUG_COUNTERS)
// ============================================================================
// Debug print for Ultra Tiny counters
#if HAKMEM_DEBUG_COUNTERS
void hak_tiny_ultra_debug_dump(void) {
// NOTE: Ultra Tiny counters (pop_hits, refills, resets, sll_count) are currently not tracked
// Uncomment when these variables are implemented
/*
fprintf(stderr, "\n[Ultra Tiny Debug]\n");
fprintf(stderr, "class, pop_hits, refills, resets, sll_count\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%u\n",
i,
(unsigned long long)g_ultra_pop_hits[i],
(unsigned long long)g_ultra_refill_calls[i],
(unsigned long long)g_ultra_resets[i],
(unsigned)g_tls_sll[i].count);
}
*/
}
#else
void hak_tiny_ultra_debug_dump(void) { /* no-op in release builds */ }
#endif
// Debug print for normal path counters (SLL/MAG/FRONT/SUPER)
void hak_tiny_path_debug_dump(void) {
#if HAKMEM_DEBUG_COUNTERS
const char* on = getenv("HAKMEM_TINY_PATH_DEBUG");
if (!(on && atoi(on) != 0)) return;
// NOTE: Path debug counters (sll_pop, mag_pop, etc.) are currently not tracked
// Uncomment when these variables are implemented
/*
fprintf(stderr, "\n[Tiny Path Debug]\n");
fprintf(stderr, "class, sll_pop, mag_pop, front_pop, superslab, refills\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu\n",
i,
(unsigned long long)g_path_sll_pop[i],
(unsigned long long)g_path_mag_pop[i],
(unsigned long long)g_path_front_pop[i],
(unsigned long long)g_path_superslab[i],
(unsigned long long)g_path_refill_calls[i]);
}
*/
(void)on;
#else
(void)getenv; // suppress unused warnings when compiled out
#endif
}
// Debug print for extended counters (slow/bin/bump/spec)
void hak_tiny_debug_counters_dump(void) {
#if HAKMEM_DEBUG_COUNTERS
const char* on = getenv("HAKMEM_TINY_COUNTERS_DUMP");
if (!(on && atoi(on) != 0)) return;
// NOTE: Extended counters (alloc_slow, bitmap_scans, etc.) are currently not tracked
// Uncomment when these variables are implemented
/*
fprintf(stderr, "\n[Tiny Extended Counters]\n");
fprintf(stderr, "class, alloc_slow, ss_refill, bitmap_scans, bin_pops, bump_hits, bump_arms, spec_calls, spec_hits\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
i,
(unsigned long long)g_alloc_slow_calls[i],
(unsigned long long)g_superslab_refill_calls_dbg[i],
(unsigned long long)g_bitmap_scan_calls[i],
(unsigned long long)g_bgbin_pops[i],
(unsigned long long)g_bump_hits[i],
(unsigned long long)g_bump_arms[i],
(unsigned long long)g_spec_calls[i],
(unsigned long long)g_spec_hits[i]);
}
*/
// SuperSlab adopt/publish debug
extern unsigned long long g_ss_publish_dbg[];
extern unsigned long long g_ss_adopt_dbg[];
fprintf(stderr, "\n[SS Adopt/Publish Counters]\n");
fprintf(stderr, "class, ss_publish, ss_adopt\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu\n", i,
(unsigned long long)g_ss_publish_dbg[i],
(unsigned long long)g_ss_adopt_dbg[i]);
}
// Refill-stage counters
extern unsigned long long g_rf_total_calls[];
extern unsigned long long g_rf_hit_bench[];
extern unsigned long long g_rf_hit_hot[];
extern unsigned long long g_rf_hit_ready[];
extern unsigned long long g_rf_hit_slab[];
extern unsigned long long g_rf_hit_ss[];
extern unsigned long long g_rf_hit_reg[];
extern unsigned long long g_rf_mmap_calls[];
fprintf(stderr, "\n[Refill Stage Counters]\n");
fprintf(stderr, "class, total, ready, bench, hot, slab, ss, reg, mmap\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_total_calls[i],
(unsigned long long)g_rf_hit_ready[i],
(unsigned long long)g_rf_hit_bench[i],
(unsigned long long)g_rf_hit_hot[i],
(unsigned long long)g_rf_hit_slab[i],
(unsigned long long)g_rf_hit_ss[i],
(unsigned long long)g_rf_hit_reg[i],
(unsigned long long)g_rf_mmap_calls[i]);
}
// Refill item sources (freelist vs carve)
extern unsigned long long g_rf_freelist_items[];
extern unsigned long long g_rf_carve_items[];
fprintf(stderr, "\n[Refill Item Sources]\n");
fprintf(stderr, "class, freelist_items, carve_items\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu\n", i,
(unsigned long long)g_rf_freelist_items[i],
(unsigned long long)g_rf_carve_items[i]);
}
// Refill item sources (freelist vs carve)
extern unsigned long long g_rf_freelist_items[];
extern unsigned long long g_rf_carve_items[];
fprintf(stderr, "\n[Refill Item Sources]\n");
fprintf(stderr, "class, freelist_items, carve_items\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu\n", i,
(unsigned long long)g_rf_freelist_items[i],
(unsigned long long)g_rf_carve_items[i]);
}
// Diagnostic: refill early return counters
extern unsigned long long g_rf_early_no_ss[];
extern unsigned long long g_rf_early_no_meta[];
extern unsigned long long g_rf_early_no_room[];
extern unsigned long long g_rf_early_want_zero[];
fprintf(stderr, "\n[Refill Early Returns - Diagnostic]\n");
fprintf(stderr, "class, no_ss, no_meta, no_room, want_zero\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_early_no_ss[i],
(unsigned long long)g_rf_early_no_meta[i],
(unsigned long long)g_rf_early_no_room[i],
(unsigned long long)g_rf_early_want_zero[i]);
}
// Slab-ring counters
extern unsigned long long g_slab_publish_dbg[];
extern unsigned long long g_slab_adopt_dbg[];
extern unsigned long long g_slab_requeue_dbg[];
extern unsigned long long g_slab_miss_dbg[];
fprintf(stderr, "\n[Slab Adopt/Publish Counters]\n");
fprintf(stderr, "class, slab_publish, slab_adopt, slab_requeue, slab_miss\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_slab_publish_dbg[i],
(unsigned long long)g_slab_adopt_dbg[i],
(unsigned long long)g_slab_requeue_dbg[i],
(unsigned long long)g_slab_miss_dbg[i]);
}
// Publish-side counters
extern unsigned long long g_pub_bench_hits[];
extern unsigned long long g_pub_hot_hits[];
extern unsigned long long g_pub_mail_hits[];
fprintf(stderr, "\n[Publish Hits]\n");
fprintf(stderr, "class, pub_mail, pub_bench, pub_hot\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu\n", i,
(unsigned long long)g_pub_mail_hits[i],
(unsigned long long)g_pub_bench_hits[i],
(unsigned long long)g_pub_hot_hits[i]);
}
// Front Gate Breakdown (SFC/SLL/Quick/Mag)
extern unsigned long long g_front_sfc_hit[];
extern unsigned long long g_front_sll_hit[];
extern unsigned long long g_front_quick_hit[];
extern unsigned long long g_front_mag_hit[];
fprintf(stderr, "\n[Front Gate Breakdown]\n");
fprintf(stderr, "class, sfc_hit, sll_hit, quick_hit, mag_hit\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_front_sfc_hit[i],
(unsigned long long)g_front_sll_hit[i],
(unsigned long long)g_front_quick_hit[i],
(unsigned long long)g_front_mag_hit[i]);
}
// Free Triggers (first-free / remote transition)
extern unsigned long long g_first_free_transitions[];
extern unsigned long long g_remote_free_transitions[];
fprintf(stderr, "\n[Free Triggers]\n");
fprintf(stderr, "class, first_free, remote_transition\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu\n", i,
(unsigned long long)g_first_free_transitions[i],
(unsigned long long)g_remote_free_transitions[i]);
}
// Adopt/Registry Gate
extern unsigned long long g_adopt_gate_calls[];
extern unsigned long long g_adopt_gate_success[];
extern unsigned long long g_reg_scan_attempts[];
extern unsigned long long g_reg_scan_hits[];
fprintf(stderr, "\n[Adopt/Registry Gate]\n");
fprintf(stderr, "class, adopt_calls, adopt_success, reg_scans, reg_hits\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_adopt_gate_calls[i],
(unsigned long long)g_adopt_gate_success[i],
(unsigned long long)g_reg_scan_attempts[i],
(unsigned long long)g_reg_scan_hits[i]);
}
// SuperSlab Registry (per-class sizes)
extern int g_super_reg_class_size[];
fprintf(stderr, "\n[SuperSlab Registry]\n");
fprintf(stderr, "class, reg_size\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%d\n", i, g_super_reg_class_size[i]);
}
extern unsigned long long g_fast_push_hits[];
extern unsigned long long g_fast_push_full[];
extern unsigned long long g_fast_push_disabled[];
extern unsigned long long g_fast_push_zero_cap[];
extern unsigned long long g_fast_push_gate_disabled[];
extern unsigned long long g_fast_push_gate_zero_cap[];
extern unsigned long long g_fast_spare_attempts[];
extern unsigned long long g_fast_spare_disabled[];
extern unsigned long long g_fast_spare_empty[];
extern unsigned long long g_fast_spare_lookup_fail[];
extern unsigned long long g_fast_spare_bad_index[];
extern unsigned long long g_fast_lookup_ss[];
extern unsigned long long g_fast_lookup_slab[];
extern unsigned long long g_fast_lookup_none;
fprintf(stderr, "\n[Fast Cache Debug]\n");
fprintf(stderr, "class, push_hits, push_full, push_disabled, push_zero_cap, gate_disabled, gate_zero_cap, spare_attempts, spare_disabled, spare_empty, spare_lookup_fail, spare_bad_index, lookup_ss, lookup_slab\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_fast_push_hits[i],
(unsigned long long)g_fast_push_full[i],
(unsigned long long)g_fast_push_disabled[i],
(unsigned long long)g_fast_push_zero_cap[i],
(unsigned long long)g_fast_push_gate_disabled[i],
(unsigned long long)g_fast_push_gate_zero_cap[i],
(unsigned long long)g_fast_spare_attempts[i],
(unsigned long long)g_fast_spare_disabled[i],
(unsigned long long)g_fast_spare_empty[i],
(unsigned long long)g_fast_spare_lookup_fail[i],
(unsigned long long)g_fast_spare_bad_index[i],
(unsigned long long)g_fast_lookup_ss[i],
(unsigned long long)g_fast_lookup_slab[i]);
}
fprintf(stderr, "lookup_none,%llu\n", (unsigned long long)g_fast_lookup_none);
extern uint64_t g_ss_cache_hits[];
extern uint64_t g_ss_cache_misses[];
extern uint64_t g_ss_cache_puts[];
extern uint64_t g_ss_cache_drops[];
extern uint64_t g_ss_cache_precharged[];
extern uint64_t g_superslabs_reused;
extern uint64_t g_superslabs_cached;
fprintf(stderr, "\n[SS Cache Stats]\n");
fprintf(stderr, "class, cache_hits, cache_misses, cache_puts, cache_drops, precharged\n");
for (int i = 0; i < 8; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_ss_cache_hits[i],
(unsigned long long)g_ss_cache_misses[i],
(unsigned long long)g_ss_cache_puts[i],
(unsigned long long)g_ss_cache_drops[i],
(unsigned long long)g_ss_cache_precharged[i]);
}
fprintf(stderr, "cache_reused=%llu cache_cached=%llu\n",
(unsigned long long)g_superslabs_reused,
(unsigned long long)g_superslabs_cached);
// Free pipeline
extern unsigned long long g_free_via_ss_local[];
extern unsigned long long g_free_via_ss_remote[];
extern unsigned long long g_free_via_tls_sll[];
extern unsigned long long g_free_via_mag[];
extern unsigned long long g_free_via_fast_tls[];
extern unsigned long long g_free_via_fastcache[];
extern unsigned long long g_fast_spare_flush[];
fprintf(stderr, "\n[Free Pipeline]\n");
fprintf(stderr, "class, ss_local, ss_remote, fast_tls, fast_cache, tls_sll, magazine, fast_spare_flush\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_free_via_ss_local[i],
(unsigned long long)g_free_via_ss_remote[i],
(unsigned long long)g_free_via_fast_tls[i],
(unsigned long long)g_free_via_fastcache[i],
(unsigned long long)g_free_via_tls_sll[i],
(unsigned long long)g_free_via_mag[i],
(unsigned long long)g_fast_spare_flush[i]);
}
// Publish pipeline
extern unsigned long long g_pub_notify_calls[];
extern unsigned long long g_pub_same_empty[];
extern unsigned long long g_remote_transitions[];
extern unsigned long long g_mailbox_register_calls[];
extern unsigned long long g_mailbox_slow_discoveries[];
fprintf(stderr, "\n[Publish Pipeline]\n");
fprintf(stderr, "class, notify_calls, same_empty_pubs, remote_transitions, mailbox_reg_calls, mailbox_slow_disc\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_pub_notify_calls[i],
(unsigned long long)g_pub_same_empty[i],
(unsigned long long)g_remote_transitions[i],
(unsigned long long)g_mailbox_register_calls[i],
(unsigned long long)g_mailbox_slow_discoveries[i]);
}
extern unsigned long long g_fast_push_hits[];
extern unsigned long long g_fast_push_full[];
extern unsigned long long g_fast_push_disabled[];
extern unsigned long long g_fast_push_zero_cap[];
extern unsigned long long g_fast_push_gate_disabled[];
extern unsigned long long g_fast_push_gate_zero_cap[];
extern unsigned long long g_fast_spare_attempts[];
extern unsigned long long g_fast_spare_disabled[];
extern unsigned long long g_fast_spare_empty[];
extern unsigned long long g_fast_spare_lookup_fail[];
extern unsigned long long g_fast_spare_bad_index[];
extern unsigned long long g_fast_lookup_ss[];
extern unsigned long long g_fast_lookup_slab[];
extern unsigned long long g_fast_lookup_none;
fprintf(stderr, "\n[Fast Cache Debug]\n");
fprintf(stderr, "class, push_hits, push_full, push_disabled, push_zero_cap, gate_disabled, gate_zero_cap, spare_attempts, spare_disabled, spare_empty, spare_lookup_fail, spare_bad_index, lookup_ss, lookup_slab\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_fast_push_hits[i],
(unsigned long long)g_fast_push_full[i],
(unsigned long long)g_fast_push_disabled[i],
(unsigned long long)g_fast_push_zero_cap[i],
(unsigned long long)g_fast_push_gate_disabled[i],
(unsigned long long)g_fast_push_gate_zero_cap[i],
(unsigned long long)g_fast_spare_attempts[i],
(unsigned long long)g_fast_spare_disabled[i],
(unsigned long long)g_fast_spare_empty[i],
(unsigned long long)g_fast_spare_lookup_fail[i],
(unsigned long long)g_fast_spare_bad_index[i],
(unsigned long long)g_fast_lookup_ss[i],
(unsigned long long)g_fast_lookup_slab[i]);
}
fprintf(stderr, "lookup_none,%llu\n", (unsigned long long)g_fast_lookup_none);
// Refill timing (ns)
extern unsigned long long g_rf_time_total_ns[];
extern unsigned long long g_rf_time_hot_ns[];
extern unsigned long long g_rf_time_bench_ns[];
extern unsigned long long g_rf_time_mail_ns[];
extern unsigned long long g_rf_time_slab_ns[];
extern unsigned long long g_rf_time_ss_ns[];
extern unsigned long long g_rf_time_reg_ns[];
extern unsigned long long g_rf_time_mmap_ns[];
fprintf(stderr, "\n[Refill Time (ns)]\n");
fprintf(stderr, "class, total, hot, bench, mail, slab, ss, reg, mmap\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_time_total_ns[i],
(unsigned long long)g_rf_time_hot_ns[i],
(unsigned long long)g_rf_time_bench_ns[i],
(unsigned long long)g_rf_time_mail_ns[i],
(unsigned long long)g_rf_time_slab_ns[i],
(unsigned long long)g_rf_time_ss_ns[i],
(unsigned long long)g_rf_time_reg_ns[i],
(unsigned long long)g_rf_time_mmap_ns[i]);
}
(void)on;
#endif
}
// Always-available: Refill stage counters dump (env: HAKMEM_TINY_REFILL_DUMP=1 or reuse HAKMEM_TINY_COUNTERS_DUMP)
static void hak_tiny_refill_counters_dump(void) {
hak_tiny_stats_init_flags();
const char* on1 = getenv("HAKMEM_TINY_REFILL_DUMP");
const char* on2 = getenv("HAKMEM_TINY_COUNTERS_DUMP");
if (!((on1 && atoi(on1)!=0) || (on2 && atoi(on2)!=0))) return;
extern unsigned long long g_rf_total_calls[];
extern unsigned long long g_rf_hit_bench[];
extern unsigned long long g_rf_hit_hot[];
extern unsigned long long g_rf_hit_mail[];
extern unsigned long long g_rf_hit_slab[];
extern unsigned long long g_rf_hit_ss[];
extern unsigned long long g_rf_hit_reg[];
extern unsigned long long g_rf_mmap_calls[];
fprintf(stderr, "\n[Refill Stage Counters]\n");
fprintf(stderr, "class, total, mail, bench, hot, slab, ss, reg, mmap\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_total_calls[i],
(unsigned long long)g_rf_hit_mail[i],
(unsigned long long)g_rf_hit_bench[i],
(unsigned long long)g_rf_hit_hot[i],
(unsigned long long)g_rf_hit_slab[i],
(unsigned long long)g_rf_hit_ss[i],
(unsigned long long)g_rf_hit_reg[i],
(unsigned long long)g_rf_mmap_calls[i]);
}
// Diagnostic: refill early return counters
extern unsigned long long g_rf_early_no_ss[];
extern unsigned long long g_rf_early_no_meta[];
extern unsigned long long g_rf_early_no_room[];
extern unsigned long long g_rf_early_want_zero[];
fprintf(stderr, "\n[Refill Early Returns - Diagnostic]\n");
fprintf(stderr, "class, no_ss, no_meta, no_room, want_zero\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_early_no_ss[i],
(unsigned long long)g_rf_early_no_meta[i],
(unsigned long long)g_rf_early_no_room[i],
(unsigned long long)g_rf_early_want_zero[i]);
}
// Publish-side counters (always available)
extern unsigned long long g_pub_bench_hits[];
extern unsigned long long g_pub_hot_hits[];
extern unsigned long long g_pub_mail_hits[];
fprintf(stderr, "\n[Publish Hits]\n");
fprintf(stderr, "class, pub_mail, pub_bench, pub_hot\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu\n", i,
(unsigned long long)g_pub_mail_hits[i],
(unsigned long long)g_pub_bench_hits[i],
(unsigned long long)g_pub_hot_hits[i]);
}
extern uint64_t g_ss_cache_hits[];
extern uint64_t g_ss_cache_misses[];
extern uint64_t g_ss_cache_puts[];
extern uint64_t g_ss_cache_drops[];
extern uint64_t g_ss_cache_precharged[];
extern uint64_t g_superslabs_reused;
extern uint64_t g_superslabs_cached;
fprintf(stderr, "\n[SS Cache Stats]\n");
fprintf(stderr, "class, cache_hits, cache_misses, cache_puts, cache_drops, precharged\n");
for (int i = 0; i < 8; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_ss_cache_hits[i],
(unsigned long long)g_ss_cache_misses[i],
(unsigned long long)g_ss_cache_puts[i],
(unsigned long long)g_ss_cache_drops[i],
(unsigned long long)g_ss_cache_precharged[i]);
}
fprintf(stderr, "cache_reused=%llu cache_cached=%llu\n",
(unsigned long long)g_superslabs_reused,
(unsigned long long)g_superslabs_cached);
// Free pipeline
extern unsigned long long g_free_via_ss_local[];
extern unsigned long long g_free_via_ss_remote[];
extern unsigned long long g_free_via_tls_sll[];
extern unsigned long long g_free_via_mag[];
extern unsigned long long g_free_via_fast_tls[];
extern unsigned long long g_free_via_fastcache[];
extern unsigned long long g_fast_spare_flush[];
fprintf(stderr, "\n[Free Pipeline]\n");
fprintf(stderr, "class, ss_local, ss_remote, fast_tls, fast_cache, tls_sll, magazine, fast_spare_flush\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_free_via_ss_local[i],
(unsigned long long)g_free_via_ss_remote[i],
(unsigned long long)g_free_via_fast_tls[i],
(unsigned long long)g_free_via_fastcache[i],
(unsigned long long)g_free_via_tls_sll[i],
(unsigned long long)g_free_via_mag[i],
(unsigned long long)g_fast_spare_flush[i]);
}
// Publish pipeline
extern unsigned long long g_pub_notify_calls[];
extern unsigned long long g_pub_same_empty[];
extern unsigned long long g_remote_transitions[];
extern unsigned long long g_mailbox_register_calls[];
extern unsigned long long g_mailbox_slow_discoveries[];
fprintf(stderr, "\n[Publish Pipeline]\n");
fprintf(stderr, "class, notify_calls, same_empty_pubs, remote_transitions, mailbox_reg_calls, mailbox_slow_disc\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_pub_notify_calls[i],
(unsigned long long)g_pub_same_empty[i],
(unsigned long long)g_remote_transitions[i],
(unsigned long long)g_mailbox_register_calls[i],
(unsigned long long)g_mailbox_slow_discoveries[i]);
}
extern unsigned long long g_fast_push_hits[];
extern unsigned long long g_fast_push_full[];
extern unsigned long long g_fast_push_disabled[];
extern unsigned long long g_fast_push_zero_cap[];
extern unsigned long long g_fast_push_gate_disabled[];
extern unsigned long long g_fast_push_gate_zero_cap[];
extern unsigned long long g_fast_spare_attempts[];
extern unsigned long long g_fast_spare_disabled[];
extern unsigned long long g_fast_spare_empty[];
extern unsigned long long g_fast_spare_lookup_fail[];
extern unsigned long long g_fast_spare_bad_index[];
extern unsigned long long g_fast_lookup_ss[];
extern unsigned long long g_fast_lookup_slab[];
extern unsigned long long g_fast_lookup_none;
fprintf(stderr, "\n[Fast Cache Debug]\n");
fprintf(stderr, "class, push_hits, push_full, push_disabled, push_zero_cap, gate_disabled, gate_zero_cap, spare_attempts, spare_disabled, spare_empty, spare_lookup_fail, spare_bad_index, lookup_ss, lookup_slab\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_fast_push_hits[i],
(unsigned long long)g_fast_push_full[i],
(unsigned long long)g_fast_push_disabled[i],
(unsigned long long)g_fast_push_zero_cap[i],
(unsigned long long)g_fast_push_gate_disabled[i],
(unsigned long long)g_fast_push_gate_zero_cap[i],
(unsigned long long)g_fast_spare_attempts[i],
(unsigned long long)g_fast_spare_disabled[i],
(unsigned long long)g_fast_spare_empty[i],
(unsigned long long)g_fast_spare_lookup_fail[i],
(unsigned long long)g_fast_spare_bad_index[i],
(unsigned long long)g_fast_lookup_ss[i],
(unsigned long long)g_fast_lookup_slab[i]);
}
fprintf(stderr, "lookup_none,%llu\n", (unsigned long long)g_fast_lookup_none);
// Refill timing (ns)
extern unsigned long long g_rf_time_total_ns[];
extern unsigned long long g_rf_time_hot_ns[];
extern unsigned long long g_rf_time_bench_ns[];
extern unsigned long long g_rf_time_mail_ns[];
extern unsigned long long g_rf_time_slab_ns[];
extern unsigned long long g_rf_time_ss_ns[];
extern unsigned long long g_rf_time_reg_ns[];
extern unsigned long long g_rf_time_mmap_ns[];
fprintf(stderr, "\n[Refill Time (ns)]\n");
fprintf(stderr, "class, total, hot, bench, mail, slab, ss, reg, mmap\n");
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
fprintf(stderr, "%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i,
(unsigned long long)g_rf_time_total_ns[i],
(unsigned long long)g_rf_time_hot_ns[i],
(unsigned long long)g_rf_time_bench_ns[i],
(unsigned long long)g_rf_time_mail_ns[i],
(unsigned long long)g_rf_time_slab_ns[i],
(unsigned long long)g_rf_time_ss_ns[i],
(unsigned long long)g_rf_time_reg_ns[i],
(unsigned long long)g_rf_time_mmap_ns[i]);
}
}
__attribute__((destructor))
static void hak_tiny_stats_auto_dump(void) {
// Dump at exit if enabled or atexit-only requested
hak_tiny_stats_init_flags();
if (g_dump_atexit_only) {
// Force dump regardless of HAKMEM_TINY_COUNTERS_DUMP when atexit-only
// Temporarily set env flag behavior by direct call to minimal + extended
hak_tiny_dump_all_counters_now();
} else {
hak_tiny_refill_counters_dump();
}
}