diff --git a/core/box/pool_mid_inuse_deferred_stats_box.h b/core/box/pool_mid_inuse_deferred_stats_box.h new file mode 100644 index 00000000..7031556b --- /dev/null +++ b/core/box/pool_mid_inuse_deferred_stats_box.h @@ -0,0 +1,69 @@ +// pool_mid_inuse_deferred_stats_box.h — Box: Deferred inuse_dec Statistics +// +// Purpose: Track deferred inuse_dec performance counters +// Pattern: Atomic counters with destructor dump +// Phase: POOL-MID-DN-BATCH Step 5 +// +// Counters: +// - mid_inuse_deferred_hit: Total deferred decrements (hot path) +// - drain_calls: Number of drain operations (cold path) +// - pages_drained: Total pages processed in drain +// - empty_transitions: Pages that triggered DONTNEED + +#ifndef POOL_MID_INUSE_DEFERRED_STATS_BOX_H +#define POOL_MID_INUSE_DEFERRED_STATS_BOX_H + +#include +#include +#include +#include + +// Statistics structure +typedef struct { + _Atomic uint64_t mid_inuse_deferred_hit; // Total deferred decrements + _Atomic uint64_t drain_calls; // Number of drain calls + _Atomic uint64_t pages_drained; // Total pages drained + _Atomic uint64_t empty_transitions; // Pages that went to 0 +} MidInuseDeferredStats; + +// Global stats instance +static MidInuseDeferredStats g_mid_inuse_deferred_stats; + +// Stats increment macros (inline for hot path) +#define MID_INUSE_DEFERRED_STAT_INC(field) \ + atomic_fetch_add_explicit(&g_mid_inuse_deferred_stats.field, 1, memory_order_relaxed) + +#define MID_INUSE_DEFERRED_STAT_ADD(field, n) \ + atomic_fetch_add_explicit(&g_mid_inuse_deferred_stats.field, (n), memory_order_relaxed) + +// Dump stats on exit (if ENV var set) +static void mid_inuse_deferred_stats_dump(void) { + // Only dump if deferred is enabled + const char* e = getenv("HAKMEM_POOL_MID_INUSE_DEFERRED"); + if (!e || *e != '1') return; + + uint64_t hits = atomic_load_explicit(&g_mid_inuse_deferred_stats.mid_inuse_deferred_hit, memory_order_relaxed); + uint64_t drains = atomic_load_explicit(&g_mid_inuse_deferred_stats.drain_calls, memory_order_relaxed); + uint64_t pages = atomic_load_explicit(&g_mid_inuse_deferred_stats.pages_drained, memory_order_relaxed); + uint64_t empties = atomic_load_explicit(&g_mid_inuse_deferred_stats.empty_transitions, memory_order_relaxed); + + if (hits > 0 || drains > 0) { + fprintf(stderr, "\n=== Mid Inuse Deferred Stats ===\n"); + fprintf(stderr, "Deferred hits: %lu\n", hits); + fprintf(stderr, "Drain calls: %lu\n", drains); + fprintf(stderr, "Pages drained: %lu\n", pages); + fprintf(stderr, "Empty transitions: %lu\n", empties); + if (drains > 0) { + fprintf(stderr, "Avg pages/drain: %.2f\n", (double)pages / (double)drains); + } + fprintf(stderr, "================================\n"); + } +} + +// Register destructor to dump stats on exit +static void mid_inuse_deferred_stats_init(void) __attribute__((constructor)); +static void mid_inuse_deferred_stats_init(void) { + atexit(mid_inuse_deferred_stats_dump); +} + +#endif // POOL_MID_INUSE_DEFERRED_STATS_BOX_H