Files
hakmem/core/hakmem_ace_metrics.c

220 lines
6.7 KiB
C
Raw Normal View History

/* hakmem_ace_metrics.c - ACE Learning Layer Metrics Collection */
#include "hakmem_ace_metrics.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
/* グローバルカウンタatomicで高速更新 */
_Atomic uint64_t g_ace_alloc_count = 0;
_Atomic uint64_t g_ace_free_count = 0;
_Atomic uint64_t g_ace_mutex_wait_ns = 0;
/* 前回収集時のカウンタdelta計算用 */
static uint64_t s_prev_alloc_count = 0;
static uint64_t s_prev_free_count = 0;
static uint64_t s_prev_timestamp_ms = 0;
/* LLC miss monitoring用 */
static bool s_llc_available = false;
/* ========== 初期化・破棄 ========== */
void hkm_ace_metrics_init(void) {
/* カウンタリセット */
atomic_store_explicit(&g_ace_alloc_count, 0, memory_order_relaxed);
atomic_store_explicit(&g_ace_free_count, 0, memory_order_relaxed);
atomic_store_explicit(&g_ace_mutex_wait_ns, 0, memory_order_relaxed);
s_prev_alloc_count = 0;
s_prev_free_count = 0;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
s_prev_timestamp_ms = (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL;
/* LLC miss監視が利用可能かチェック */
s_llc_available = hkm_ace_llc_available();
}
void hkm_ace_metrics_destroy(void) {
/* 特に何もしない */
}
/* ========== 現在時刻取得(ミリ秒) ========== */
static inline uint64_t get_monotonic_ms(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL;
}
/* ========== スループット計算 ========== */
static void collect_throughput(struct hkm_ace_metrics *out) {
uint64_t now_ms = get_monotonic_ms();
uint64_t elapsed_ms = (now_ms > s_prev_timestamp_ms) ? (now_ms - s_prev_timestamp_ms) : 1;
uint64_t curr_alloc = atomic_load_explicit(&g_ace_alloc_count, memory_order_relaxed);
uint64_t curr_free = atomic_load_explicit(&g_ace_free_count, memory_order_relaxed);
uint64_t delta_alloc = curr_alloc - s_prev_alloc_count;
uint64_t delta_free = curr_free - s_prev_free_count;
uint64_t delta_ops = delta_alloc + delta_free;
/* ops/sec = delta_ops / (elapsed_ms / 1000.0) */
out->throughput_ops = (delta_ops * 1000ULL) / elapsed_ms;
/* 次回用に保存 */
s_prev_alloc_count = curr_alloc;
s_prev_free_count = curr_free;
s_prev_timestamp_ms = now_ms;
out->timestamp_ms = now_ms;
}
/* ========== LLC miss rate 計算 ========== */
static void collect_llc_miss_rate(struct hkm_ace_metrics *out) {
if (!s_llc_available) {
out->llc_miss_rate = 0.0;
return;
}
uint64_t misses = 0, references = 0;
hkm_ace_llc_read(&misses, &references);
if (references > 0) {
out->llc_miss_rate = (double)misses / (double)references;
} else {
out->llc_miss_rate = 0.0;
}
}
/* ========== Mutex contention 計算 ========== */
static void collect_mutex_wait(struct hkm_ace_metrics *out) {
uint64_t total_wait_ns = atomic_load_explicit(&g_ace_mutex_wait_ns, memory_order_relaxed);
out->mutex_wait_ns = total_wait_ns;
/* リセット(次の窓用) */
atomic_store_explicit(&g_ace_mutex_wait_ns, 0, memory_order_relaxed);
}
/* ========== Remote free backlog 読み取り ========== */
extern uint32_t hkm_tiny_get_remote_backlog(uint8_t class_idx); /* tiny poolから取得 */
static void collect_remote_backlog(struct hkm_ace_metrics *out) {
for (int c = 0; c < 8; c++) {
/* TODO: tiny poolの実装に合わせて調整 */
out->remote_free_backlog[c] = 0; /* プレースホルダー */
}
}
/* ========== Fragmentation ratio 計算(/proc/self/status読み取り ========== */
static void collect_fragmentation_and_rss(struct hkm_ace_metrics *out) {
FILE *fp = fopen("/proc/self/status", "r");
if (!fp) {
out->fragmentation_ratio = 1.0;
out->rss_mb = 0;
return;
}
uint64_t vm_size_kb = 0;
uint64_t vm_rss_kb = 0;
char line[256];
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, "VmSize:", 7) == 0) {
sscanf(line + 7, "%lu", &vm_size_kb);
} else if (strncmp(line, "VmRSS:", 6) == 0) {
sscanf(line + 6, "%lu", &vm_rss_kb);
}
}
fclose(fp);
/* Fragmentation ratio = RSS / VmSize */
if (vm_size_kb > 0) {
out->fragmentation_ratio = (double)vm_rss_kb / (double)vm_size_kb;
} else {
out->fragmentation_ratio = 1.0;
}
/* RSS in MB */
out->rss_mb = vm_rss_kb / 1024;
}
/* ========== Fast metrics 収集0.5-1s間隔 ========== */
void hkm_ace_metrics_collect_fast(struct hkm_ace_metrics *out) {
memset(out, 0, sizeof(*out));
collect_throughput(out);
collect_llc_miss_rate(out);
collect_mutex_wait(out);
collect_remote_backlog(out);
}
/* ========== Slow metrics 収集30-60s間隔 ========== */
void hkm_ace_metrics_collect_slow(struct hkm_ace_metrics *out) {
collect_fragmentation_and_rss(out);
}
/* ========== Full metrics 収集 ========== */
void hkm_ace_metrics_collect(struct hkm_ace_metrics *out) {
hkm_ace_metrics_collect_fast(out);
hkm_ace_metrics_collect_slow(out);
}
/* ========== LLC miss monitoring (rdpmc wrapper) ========== */
/* rdpmc利用可能性チェック
* : Linux kernelで CONFIG_PERF_EVENTS=y
* /proc/sys/kernel/perf_event_paranoid <= 1
*/
bool hkm_ace_llc_available(void) {
/* 簡易チェック: /proc/sys/kernel/perf_event_paranoid を読む */
FILE *fp = fopen("/proc/sys/kernel/perf_event_paranoid", "r");
if (!fp) {
return false;
}
int paranoid = 2; /* デフォルト値 */
int ret = fscanf(fp, "%d", &paranoid);
fclose(fp);
(void)ret; /* Suppress unused warning */
/* paranoid <= 1 なら rdpmc 使用可能 */
return (paranoid <= 1);
}
/* LLC miss/reference カウンタ読み取り
* : Phase 10
* Phase 3perf_event_open()使
*/
void hkm_ace_llc_read(uint64_t *misses, uint64_t *references) {
/* Phase 1: プレースホルダー実装 */
*misses = 0;
*references = 1; /* 0除算回避 */
/* TODO Phase 3: perf_event_open() + rdpmc() 実装
*
* struct perf_event_attr attr;
* memset(&attr, 0, sizeof(attr));
* attr.type = PERF_TYPE_HARDWARE;
* attr.config = PERF_COUNT_HW_CACHE_MISSES;
* int fd_miss = perf_event_open(&attr, 0, -1, -1, 0);
*
* attr.config = PERF_COUNT_HW_CACHE_REFERENCES;
* int fd_ref = perf_event_open(&attr, 0, -1, -1, 0);
*
* read(fd_miss, misses, sizeof(uint64_t));
* read(fd_ref, references, sizeof(uint64_t));
*/
}