209 lines
7.0 KiB
C
209 lines
7.0 KiB
C
|
|
// smallobject_stats_mid_v3.c
|
||
|
|
// Phase v11a-2: Stats collection for MID v3.5 page lifetime tracking
|
||
|
|
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include "box/smallobject_stats_mid_v3_box.h"
|
||
|
|
#include "box/smallobject_learner_v2_box.h"
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Helper: Get timestamp
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
static inline uint64_t get_timestamp_ns(void) {
|
||
|
|
struct timespec ts;
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||
|
|
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline uint64_t get_timestamp_ms(void) {
|
||
|
|
return get_timestamp_ns() / 1000000ULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Stats Context
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
SmallPageStatsPublished_MID_v3 history[SMALL_STATS_HISTORY_SIZE];
|
||
|
|
uint64_t total_published;
|
||
|
|
uint32_t current_idx;
|
||
|
|
uint32_t eval_interval;
|
||
|
|
bool enabled;
|
||
|
|
} SmallStatsContext_MID_v3;
|
||
|
|
|
||
|
|
static SmallStatsContext_MID_v3 g_stats_ctx = {
|
||
|
|
.total_published = 0,
|
||
|
|
.current_idx = 0,
|
||
|
|
.eval_interval = SMALL_STATS_EVAL_INTERVAL,
|
||
|
|
.enabled = true
|
||
|
|
};
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Stats Publishing
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void small_stats_mid_v3_publish(const SmallPageStatsMID_v3 *stat) {
|
||
|
|
if (!stat || !g_stats_ctx.enabled) return;
|
||
|
|
|
||
|
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||
|
|
|
||
|
|
// Create published event
|
||
|
|
SmallPageStatsPublished_MID_v3 pub = {
|
||
|
|
.stat = *stat,
|
||
|
|
.page_ptr = NULL,
|
||
|
|
.retire_timestamp_ns = get_timestamp_ns(),
|
||
|
|
.sequence_number = ctx->total_published
|
||
|
|
};
|
||
|
|
|
||
|
|
// Store in history (circular buffer)
|
||
|
|
uint32_t idx = ctx->current_idx % SMALL_STATS_HISTORY_SIZE;
|
||
|
|
ctx->history[idx] = pub;
|
||
|
|
ctx->current_idx++;
|
||
|
|
ctx->total_published++;
|
||
|
|
|
||
|
|
// Periodic aggregation: notify Learner
|
||
|
|
if (ctx->total_published % ctx->eval_interval == 0) {
|
||
|
|
// Call Learner v2 to record this page stats
|
||
|
|
small_learner_v2_record_page_stats(stat);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const SmallPageStatsPublished_MID_v3* small_stats_mid_v3_latest(void) {
|
||
|
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||
|
|
|
||
|
|
if (ctx->total_published == 0) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t idx = (ctx->current_idx - 1) % SMALL_STATS_HISTORY_SIZE;
|
||
|
|
return &ctx->history[idx];
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t small_stats_mid_v3_published_count(void) {
|
||
|
|
return g_stats_ctx.total_published;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Periodic Aggregation
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void small_stats_mid_v3_aggregate(SmallPageStatsAggregate_MID_v3 *out) {
|
||
|
|
if (!out) return;
|
||
|
|
|
||
|
|
memset(out, 0, sizeof(*out));
|
||
|
|
out->aggregate_timestamp_ns = get_timestamp_ns();
|
||
|
|
|
||
|
|
SmallStatsContext_MID_v3 *ctx = &g_stats_ctx;
|
||
|
|
|
||
|
|
// Aggregate from history (simple approach: aggregate last N events)
|
||
|
|
uint32_t count = ctx->total_published < SMALL_STATS_HISTORY_SIZE
|
||
|
|
? ctx->total_published
|
||
|
|
: SMALL_STATS_HISTORY_SIZE;
|
||
|
|
|
||
|
|
for (uint32_t i = 0; i < count; i++) {
|
||
|
|
SmallPageStatsPublished_MID_v3 *pub = &ctx->history[i];
|
||
|
|
SmallPageStatsMID_v3 *stat = &pub->stat;
|
||
|
|
|
||
|
|
if (stat->class_idx < 8) {
|
||
|
|
out->class_allocations[stat->class_idx] += stat->total_allocations;
|
||
|
|
out->class_frees[stat->class_idx] += stat->total_frees;
|
||
|
|
out->class_retire_count[stat->class_idx]++;
|
||
|
|
|
||
|
|
// Weighted average for free hit ratio
|
||
|
|
uint64_t weight = stat->total_allocations;
|
||
|
|
if (weight > 0) {
|
||
|
|
out->class_avg_free_hit_bps[stat->class_idx] +=
|
||
|
|
(stat->free_hit_ratio_bps * weight);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
out->total_allocations += stat->total_allocations;
|
||
|
|
out->total_frees += stat->total_frees;
|
||
|
|
out->total_pages_retired++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Normalize weighted averages
|
||
|
|
for (int i = 0; i < 8; i++) {
|
||
|
|
if (out->class_allocations[i] > 0) {
|
||
|
|
out->class_avg_free_hit_bps[i] /= out->class_allocations[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (out->total_allocations > 0) {
|
||
|
|
out->global_avg_free_hit_bps =
|
||
|
|
(out->total_frees * 10000) / out->total_allocations;
|
||
|
|
}
|
||
|
|
|
||
|
|
out->eval_count = ctx->total_published / ctx->eval_interval;
|
||
|
|
}
|
||
|
|
|
||
|
|
const SmallPageStatsAggregate_MID_v3* small_stats_mid_v3_aggregate_snapshot(void) {
|
||
|
|
static SmallPageStatsAggregate_MID_v3 snapshot;
|
||
|
|
small_stats_mid_v3_aggregate(&snapshot);
|
||
|
|
return &snapshot;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Configuration
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void small_stats_mid_v3_set_eval_interval(uint32_t interval) {
|
||
|
|
g_stats_ctx.eval_interval = interval > 0 ? interval : SMALL_STATS_EVAL_INTERVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t small_stats_mid_v3_get_eval_interval(void) {
|
||
|
|
return g_stats_ctx.eval_interval;
|
||
|
|
}
|
||
|
|
|
||
|
|
void small_stats_mid_v3_set_enabled(bool enabled) {
|
||
|
|
g_stats_ctx.enabled = enabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
void small_stats_mid_v3_reset(void) {
|
||
|
|
memset(&g_stats_ctx, 0, sizeof(g_stats_ctx));
|
||
|
|
g_stats_ctx.eval_interval = SMALL_STATS_EVAL_INTERVAL;
|
||
|
|
g_stats_ctx.enabled = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Debugging & Monitoring
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void small_stats_mid_v3_print_latest(void) {
|
||
|
|
const SmallPageStatsPublished_MID_v3 *pub = small_stats_mid_v3_latest();
|
||
|
|
|
||
|
|
if (!pub) {
|
||
|
|
fprintf(stderr, "[MID_v3_Stats] No stats published yet\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const SmallPageStatsMID_v3 *stat = &pub->stat;
|
||
|
|
fprintf(stderr, "[MID_v3_Stats] Latest (seq=%lu):\n", pub->sequence_number);
|
||
|
|
fprintf(stderr, " class_idx=%u allocs=%lu frees=%lu capacity=%u\n",
|
||
|
|
stat->class_idx, stat->total_allocations, stat->total_frees,
|
||
|
|
stat->page_alloc_count);
|
||
|
|
fprintf(stderr, " free_hit_ratio=%u bps (%.2f%%)\n",
|
||
|
|
stat->free_hit_ratio_bps, stat->free_hit_ratio_bps / 100.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void small_stats_mid_v3_print_aggregate(void) {
|
||
|
|
const SmallPageStatsAggregate_MID_v3 *agg = small_stats_mid_v3_aggregate_snapshot();
|
||
|
|
|
||
|
|
fprintf(stderr, "[MID_v3_Stats] Aggregate:\n");
|
||
|
|
fprintf(stderr, " total_allocations=%lu total_frees=%lu total_retires=%u\n",
|
||
|
|
agg->total_allocations, agg->total_frees, agg->total_pages_retired);
|
||
|
|
fprintf(stderr, " global_avg_free_hit=%u bps (%.2f%%)\n",
|
||
|
|
agg->global_avg_free_hit_bps, agg->global_avg_free_hit_bps / 100.0);
|
||
|
|
|
||
|
|
for (int i = 0; i < 8; i++) {
|
||
|
|
if (agg->class_retire_count[i] > 0) {
|
||
|
|
fprintf(stderr, " C%d: allocs=%lu frees=%lu retires=%u avg_hit=%u bps\n",
|
||
|
|
i, agg->class_allocations[i], agg->class_frees[i],
|
||
|
|
agg->class_retire_count[i], agg->class_avg_free_hit_bps[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|