Files
hakmem/core/box/tiny_stats_box.h
Moe Charm (CI) 8f18963ad5 Phase 36-37: TinyHotHeap v2 HotBox redesign and C7 current_page policy fixes
- Redefine TinyHotHeap v2 as per-thread Hot Box with clear boundaries
- Add comprehensive OS statistics tracking for SS allocations
- Implement route-based free handling for TinyHeap v2
- Add C6/C7 debugging and statistics improvements
- Update documentation with implementation guidelines and analysis
- Add new box headers for stats, routing, and front-end management
2025-12-08 21:30:21 +09:00

135 lines
4.5 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.

// tiny_stats_box.h - Cold Tiny Stats Box
// 役割:
// - TinyHeap/TinyFront のホットパスから meta->used / ss_active_* 更新を切り出す箱。
// - C7 SAFE の delta flush を「即時適用 or バッチ適用」に切り替える足場。
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdatomic.h>
// 前方宣言(利用側で tiny_heap_page_t を定義済みであることが前提)
typedef struct tiny_heap_page_t tiny_heap_page_t;
typedef struct SuperSlab SuperSlab;
// ENV: HAKMEM_TINY_STATS_BOX=1 で Stats Box 経由の更新を有効化
static inline int tiny_stats_box_enabled(void) {
static int g = -1;
if (__builtin_expect(g == -1, 0)) {
const char* e = getenv("HAKMEM_TINY_STATS_BOX");
g = (e && *e && *e != '0') ? 1 : 0;
}
return g;
}
// ENV: HAKMEM_TINY_STATS_BATCH=1 で meta/active をバッチ適用pending に貯める)
static inline int tiny_stats_batch_enabled(void) {
static int g = -1;
if (__builtin_expect(g == -1, 0)) {
const char* e = getenv("HAKMEM_TINY_STATS_BATCH");
g = (e && *e && *e != '0') ? 1 : 0;
}
return g;
}
typedef struct {
uint32_t alloc_delta;
uint32_t free_delta;
} tiny_stats_accum_t;
// C7 SAFE の pending を扱うための薄い構造体page 内に埋め込まれる想定)
typedef struct {
int32_t used_delta;
int32_t active_delta;
} tiny_stats_pending_t;
// Hot からのイベントを受け取るフック(現状は no-op
static inline void tiny_stats_on_alloc(int class_idx, tiny_heap_page_t* page) {
(void)class_idx;
(void)page;
if (!tiny_stats_box_enabled()) return;
// TODO: ここにクラス別の軽量カウンタを積む余地を残す
}
static inline void tiny_stats_on_free(int class_idx, tiny_heap_page_t* page) {
(void)class_idx;
(void)page;
if (!tiny_stats_box_enabled()) return;
// TODO: ここにクラス別の軽量カウンタを積む余地を残す
}
// Superslab active counters既存 Box の関数をここから呼ぶ)
void ss_active_add(SuperSlab* ss, uint32_t n);
void ss_active_dec_one(SuperSlab* ss);
static inline void tiny_stats_apply_to_meta(tiny_heap_page_t* page, int32_t used_delta, int32_t active_delta) {
if (!page || !page->meta || !page->ss) return;
if (used_delta != 0) {
atomic_fetch_add_explicit(&page->meta->used, used_delta, memory_order_relaxed);
}
if (active_delta != 0) {
if (active_delta > 0) {
ss_active_add(page->ss, (uint32_t)active_delta);
} else {
int32_t n = -active_delta;
for (int32_t i = 0; i < n; i++) {
ss_active_dec_one(page->ss);
}
}
}
}
// バッチの flush 判定force=1 で無条件 flush
static inline void tiny_stats_maybe_flush_for_page(int class_idx, tiny_heap_page_t* page, int force) {
if (!tiny_stats_box_enabled()) return;
if (!tiny_stats_batch_enabled()) return;
if (!page) return;
(void)class_idx;
int32_t ud = page->stats_used_pending;
int32_t ad = page->stats_active_pending;
int32_t abs_ud = (ud >= 0) ? ud : -ud;
int32_t abs_ad = (ad >= 0) ? ad : -ad;
int32_t abs_max = (abs_ud > abs_ad) ? abs_ud : abs_ad;
uint16_t cap = page->capacity;
int32_t th = (cap > 0) ? ((int32_t)cap * 16) : 256;
if (th < 256) th = 256;
if (!force && abs_max < th) {
return;
}
if (ud != 0 || ad != 0) {
tiny_stats_apply_to_meta(page, ud, ad);
page->stats_used_pending = 0;
page->stats_active_pending = 0;
}
}
// flush: delta を Cold Stats 側に渡す(即時 or pending
static inline void tiny_stats_flush_for_page(int class_idx, tiny_heap_page_t* page, int32_t used_delta, int32_t active_delta) {
if (!page) return;
if (!tiny_stats_box_enabled()) {
tiny_stats_apply_to_meta(page, used_delta, active_delta);
return;
}
if (!page->meta || !page->ss) return;
if (used_delta == 0 && active_delta == 0) {
// すでに pending があれば empty 時に flush される
if (tiny_stats_batch_enabled()) {
tiny_stats_maybe_flush_for_page(class_idx, page, page->used == 0);
}
return;
}
if (!tiny_stats_batch_enabled()) {
tiny_stats_apply_to_meta(page, used_delta, active_delta);
return;
}
page->stats_used_pending += used_delta;
page->stats_active_pending += active_delta;
tiny_stats_maybe_flush_for_page(class_idx, page, page->used == 0);
}