C7 v2: add lease helpers and v2 page reset
This commit is contained in:
@ -23,11 +23,14 @@
|
||||
#include "tiny_debug_ring.h"
|
||||
#include "tiny_route.h"
|
||||
#include "front/tiny_heap_v2.h"
|
||||
#include "box/tiny_front_stats_box.h"
|
||||
#include "tiny_tls_guard.h"
|
||||
#include "tiny_ready.h"
|
||||
#include "box/c7_meta_used_counter_box.h"
|
||||
#include "box/tiny_c7_hotbox.h"
|
||||
#include "box/tiny_heap_box.h"
|
||||
#include "box/tiny_hotheap_v2_box.h"
|
||||
#include "box/tiny_route_env_box.h"
|
||||
#include "box/super_reg_box.h"
|
||||
#include "hakmem_tiny_tls_list.h"
|
||||
#include "hakmem_tiny_remote_target.h" // Phase 2C-1: Remote target queue
|
||||
@ -49,47 +52,240 @@ extern uint64_t g_bytes_allocated; // from hakmem_tiny_superslab.c
|
||||
__thread hak_base_ptr_t s_tls_sll_last_push[TINY_NUM_CLASSES] = {0};
|
||||
__thread tiny_heap_ctx_t g_tiny_heap_ctx;
|
||||
__thread int g_tiny_heap_ctx_init = 0;
|
||||
TinyC7HeapStats g_c7_heap_stats = {0};
|
||||
__thread tiny_hotheap_ctx_v2* g_tiny_hotheap_ctx_v2 = NULL;
|
||||
TinyHeapClassStats g_tiny_heap_stats[TINY_NUM_CLASSES] = {0};
|
||||
TinyC7PageStats g_c7_page_stats = {0};
|
||||
tiny_route_kind_t g_tiny_route_class[TINY_NUM_CLASSES] = {0};
|
||||
int g_tiny_route_snapshot_done = 0;
|
||||
_Atomic uint64_t g_tiny_front_alloc_class[TINY_NUM_CLASSES] = {0};
|
||||
_Atomic uint64_t g_tiny_front_free_class[TINY_NUM_CLASSES] = {0};
|
||||
|
||||
static int tiny_c7_heap_stats_dump_enabled(void) {
|
||||
static int tiny_heap_stats_dump_enabled(void) {
|
||||
static int g = -1;
|
||||
if (__builtin_expect(g == -1, 0)) {
|
||||
const char* eh = getenv("HAKMEM_TINY_HEAP_STATS_DUMP");
|
||||
const char* e = getenv("HAKMEM_TINY_C7_HEAP_STATS_DUMP");
|
||||
g = (e && *e && *e != '0') ? 1 : 0;
|
||||
g = ((eh && *eh && *eh != '0') || (e && *e && *e != '0')) ? 1 : 0;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void tiny_c7_heap_stats_dump(void) {
|
||||
if (!tiny_c7_heap_stats_enabled() || !tiny_c7_heap_stats_dump_enabled()) {
|
||||
static void tiny_heap_stats_dump(void) {
|
||||
if (!tiny_heap_stats_enabled() || !tiny_heap_stats_dump_enabled()) {
|
||||
return;
|
||||
}
|
||||
TinyC7HeapStats snap = {
|
||||
.alloc_fast_current = atomic_load_explicit(&g_c7_heap_stats.alloc_fast_current, memory_order_relaxed),
|
||||
.alloc_slow_prepare = atomic_load_explicit(&g_c7_heap_stats.alloc_slow_prepare, memory_order_relaxed),
|
||||
.free_fast_local = atomic_load_explicit(&g_c7_heap_stats.free_fast_local, memory_order_relaxed),
|
||||
.free_slow_fallback = atomic_load_explicit(&g_c7_heap_stats.free_slow_fallback, memory_order_relaxed),
|
||||
.alloc_prepare_fail = atomic_load_explicit(&g_c7_heap_stats.alloc_prepare_fail, memory_order_relaxed),
|
||||
.alloc_fail = atomic_load_explicit(&g_c7_heap_stats.alloc_fail, memory_order_relaxed),
|
||||
for (int cls = 0; cls < TINY_NUM_CLASSES; cls++) {
|
||||
TinyHeapClassStats snap = {
|
||||
.alloc_fast_current = atomic_load_explicit(&g_tiny_heap_stats[cls].alloc_fast_current, memory_order_relaxed),
|
||||
.alloc_slow_prepare = atomic_load_explicit(&g_tiny_heap_stats[cls].alloc_slow_prepare, memory_order_relaxed),
|
||||
.free_fast_local = atomic_load_explicit(&g_tiny_heap_stats[cls].free_fast_local, memory_order_relaxed),
|
||||
.free_slow_fallback = atomic_load_explicit(&g_tiny_heap_stats[cls].free_slow_fallback, memory_order_relaxed),
|
||||
.alloc_prepare_fail = atomic_load_explicit(&g_tiny_heap_stats[cls].alloc_prepare_fail, memory_order_relaxed),
|
||||
.alloc_fail = atomic_load_explicit(&g_tiny_heap_stats[cls].alloc_fail, memory_order_relaxed),
|
||||
};
|
||||
if (snap.alloc_fast_current == 0 && snap.alloc_slow_prepare == 0 &&
|
||||
snap.free_fast_local == 0 && snap.free_slow_fallback == 0 &&
|
||||
snap.alloc_prepare_fail == 0 && snap.alloc_fail == 0) {
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"[HEAP_STATS cls=%d] alloc_fast_current=%llu alloc_slow_prepare=%llu free_fast_local=%llu free_slow_fallback=%llu alloc_prepare_fail=%llu alloc_fail=%llu\n",
|
||||
cls,
|
||||
(unsigned long long)snap.alloc_fast_current,
|
||||
(unsigned long long)snap.alloc_slow_prepare,
|
||||
(unsigned long long)snap.free_fast_local,
|
||||
(unsigned long long)snap.free_slow_fallback,
|
||||
(unsigned long long)snap.alloc_prepare_fail,
|
||||
(unsigned long long)snap.alloc_fail);
|
||||
}
|
||||
TinyC7PageStats ps = {
|
||||
.prepare_calls = atomic_load_explicit(&g_c7_page_stats.prepare_calls, memory_order_relaxed),
|
||||
.prepare_with_current_null = atomic_load_explicit(&g_c7_page_stats.prepare_with_current_null, memory_order_relaxed),
|
||||
.prepare_from_partial = atomic_load_explicit(&g_c7_page_stats.prepare_from_partial, memory_order_relaxed),
|
||||
.current_set_from_free = atomic_load_explicit(&g_c7_page_stats.current_set_from_free, memory_order_relaxed),
|
||||
.current_dropped_to_partial = atomic_load_explicit(&g_c7_page_stats.current_dropped_to_partial, memory_order_relaxed),
|
||||
};
|
||||
fprintf(stderr,
|
||||
"[C7_HEAP_STATS] alloc_fast_current=%llu alloc_slow_prepare=%llu free_fast_local=%llu free_slow_fallback=%llu alloc_prepare_fail=%llu alloc_fail=%llu\n",
|
||||
(unsigned long long)snap.alloc_fast_current,
|
||||
(unsigned long long)snap.alloc_slow_prepare,
|
||||
(unsigned long long)snap.free_fast_local,
|
||||
(unsigned long long)snap.free_slow_fallback,
|
||||
(unsigned long long)snap.alloc_prepare_fail,
|
||||
(unsigned long long)snap.alloc_fail);
|
||||
fflush(stderr);
|
||||
if (ps.prepare_calls || ps.prepare_with_current_null || ps.prepare_from_partial ||
|
||||
ps.current_set_from_free || ps.current_dropped_to_partial) {
|
||||
fprintf(stderr,
|
||||
"[C7_PAGE_STATS] prepare_calls=%llu prepare_with_current_null=%llu prepare_from_partial=%llu current_set_from_free=%llu current_dropped_to_partial=%llu\n",
|
||||
(unsigned long long)ps.prepare_calls,
|
||||
(unsigned long long)ps.prepare_with_current_null,
|
||||
(unsigned long long)ps.prepare_from_partial,
|
||||
(unsigned long long)ps.current_set_from_free,
|
||||
(unsigned long long)ps.current_dropped_to_partial);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void tiny_front_class_stats_dump(void) {
|
||||
if (!tiny_front_class_stats_dump_enabled()) {
|
||||
return;
|
||||
}
|
||||
for (int cls = 0; cls < TINY_NUM_CLASSES; cls++) {
|
||||
uint64_t a = atomic_load_explicit(&g_tiny_front_alloc_class[cls], memory_order_relaxed);
|
||||
uint64_t f = atomic_load_explicit(&g_tiny_front_free_class[cls], memory_order_relaxed);
|
||||
if (a == 0 && f == 0) {
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "[FRONT_CLASS cls=%d] alloc=%llu free=%llu\n",
|
||||
cls, (unsigned long long)a, (unsigned long long)f);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void tiny_c7_delta_debug_destructor(void) {
|
||||
if (!tiny_c7_meta_light_enabled() || !tiny_c7_delta_debug_enabled()) {
|
||||
if (tiny_c7_meta_light_enabled() && tiny_c7_delta_debug_enabled()) {
|
||||
tiny_c7_heap_debug_dump_deltas();
|
||||
}
|
||||
if (tiny_heap_meta_light_enabled_for_class(6) && tiny_c6_delta_debug_enabled()) {
|
||||
tiny_c6_heap_debug_dump_deltas();
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// TinyHotHeap v2 (Phase30/31 wiring). Currently C7-only thin wrapper.
|
||||
// =============================================================================
|
||||
static _Atomic uint64_t g_tiny_hotheap_v2_c7_alloc = 0;
|
||||
static _Atomic uint64_t g_tiny_hotheap_v2_c7_free = 0;
|
||||
static _Atomic uint64_t g_tiny_hotheap_v2_c7_alloc_fallback = 0;
|
||||
static _Atomic uint64_t g_tiny_hotheap_v2_c7_free_fallback = 0;
|
||||
tiny_hotheap_ctx_v2* tiny_hotheap_v2_tls_get(void) {
|
||||
tiny_hotheap_ctx_v2* ctx = g_tiny_hotheap_ctx_v2;
|
||||
if (__builtin_expect(ctx == NULL, 0)) {
|
||||
ctx = (tiny_hotheap_ctx_v2*)calloc(1, sizeof(tiny_hotheap_ctx_v2));
|
||||
if (__builtin_expect(ctx == NULL, 0)) {
|
||||
fprintf(stderr, "[TinyHotHeapV2] TLS alloc failed (OOM)\n");
|
||||
abort();
|
||||
}
|
||||
g_tiny_hotheap_ctx_v2 = ctx;
|
||||
// C7 用 stride を最初にだけ設定(他クラスは未使用のまま)
|
||||
ctx->cls[7].stride = (uint16_t)tiny_stride_for_class(7);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void* tiny_hotheap_v2_alloc(uint8_t class_idx) {
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_alloc, 1, memory_order_relaxed);
|
||||
if (__builtin_expect(class_idx != 7, 0)) {
|
||||
return NULL; // いまは C7 専用
|
||||
}
|
||||
|
||||
tiny_hotheap_ctx_v2* v2ctx = tiny_hotheap_v2_tls_get();
|
||||
tiny_hotheap_class_v2* vhcls = &v2ctx->cls[7];
|
||||
tiny_hotheap_page_v2* v2page = vhcls ? vhcls->current_page : NULL;
|
||||
if (!v2page && vhcls) {
|
||||
v2page = &vhcls->storage_page;
|
||||
tiny_hotheap_v2_page_reset(v2page);
|
||||
vhcls->current_page = v2page;
|
||||
}
|
||||
|
||||
tiny_heap_ctx_t* v1ctx = tiny_heap_ctx_for_thread();
|
||||
tiny_heap_class_t* v1hcls = tiny_heap_class(v1ctx, 7);
|
||||
TinyHeapClassStats* stats = tiny_heap_stats_for_class(7);
|
||||
|
||||
// Hot path: current_page の lease をそのまま使う
|
||||
if (v2page && v2page->lease_page && v1hcls) {
|
||||
tiny_heap_page_t* ipage = v2page->lease_page;
|
||||
if (ipage->free_list || ipage->used < ipage->capacity) {
|
||||
void* user = tiny_heap_page_pop(v1hcls, 7, ipage);
|
||||
if (user) {
|
||||
if (ipage->used >= ipage->capacity && ipage->free_list == NULL) {
|
||||
tiny_heap_page_mark_full(v1hcls, ipage);
|
||||
}
|
||||
if (__builtin_expect(stats != NULL, 0)) {
|
||||
atomic_fetch_add_explicit(&stats->alloc_fast_current, 1, memory_order_relaxed);
|
||||
}
|
||||
v2page->freelist = ipage->free_list;
|
||||
v2page->used = ipage->used;
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (__builtin_expect(stats != NULL, 0)) {
|
||||
atomic_fetch_add_explicit(&stats->alloc_slow_prepare, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Lease a page from v1 (C7 SAFE) and wrap it
|
||||
TinyHeapPageLease lease = tiny_heap_c7_lease_page_for_v2();
|
||||
if (!lease.page || !vhcls || !v1hcls) {
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_alloc_fallback, 1, memory_order_relaxed);
|
||||
size_t size = vhcls ? (vhcls->stride ? vhcls->stride : tiny_stride_for_class(7)) : tiny_stride_for_class(7);
|
||||
return tiny_c7_alloc_fast(size); // safety fallback to v1
|
||||
}
|
||||
|
||||
if (!v2page) {
|
||||
v2page = &vhcls->storage_page;
|
||||
tiny_hotheap_v2_page_reset(v2page);
|
||||
vhcls->current_page = v2page;
|
||||
}
|
||||
|
||||
v2page->lease_page = lease.page;
|
||||
v2page->meta = lease.meta;
|
||||
v2page->ss = lease.ss;
|
||||
v2page->base = lease.base;
|
||||
v2page->capacity = lease.capacity;
|
||||
v2page->slab_idx = lease.slab_idx;
|
||||
v2page->freelist = lease.freelist;
|
||||
v2page->used = lease.page->used;
|
||||
|
||||
if (lease.page->free_list || lease.page->used < lease.page->capacity) {
|
||||
void* user = tiny_heap_page_pop(v1hcls, 7, lease.page);
|
||||
if (user) {
|
||||
if (lease.page->used >= lease.page->capacity && lease.page->free_list == NULL) {
|
||||
tiny_heap_page_mark_full(v1hcls, lease.page);
|
||||
}
|
||||
if (__builtin_expect(stats != NULL, 0)) {
|
||||
atomic_fetch_add_explicit(&stats->alloc_fast_current, 1, memory_order_relaxed);
|
||||
}
|
||||
v2page->freelist = lease.page->free_list;
|
||||
v2page->used = lease.page->used;
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
// Lease 取得後でも pop できなければ v1 に委譲
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_alloc_fallback, 1, memory_order_relaxed);
|
||||
size_t size = vhcls ? (vhcls->stride ? vhcls->stride : tiny_stride_for_class(7)) : tiny_stride_for_class(7);
|
||||
return tiny_c7_alloc_fast(size);
|
||||
}
|
||||
|
||||
void tiny_hotheap_v2_free(uint8_t class_idx, void* p, void* meta) {
|
||||
if (__builtin_expect(class_idx != 7, 0)) {
|
||||
return;
|
||||
}
|
||||
tiny_c7_heap_debug_dump_deltas();
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_free, 1, memory_order_relaxed);
|
||||
tiny_hotheap_ctx_v2* v2ctx = tiny_hotheap_v2_tls_get();
|
||||
tiny_hotheap_class_v2* vhcls = v2ctx ? &v2ctx->cls[7] : NULL;
|
||||
tiny_hotheap_page_v2* v2page = vhcls ? vhcls->current_page : NULL;
|
||||
TinySlabMeta* meta_ptr = (TinySlabMeta*)meta;
|
||||
|
||||
tiny_heap_ctx_t* v1ctx = tiny_heap_ctx_for_thread();
|
||||
tiny_heap_class_t* v1hcls = tiny_heap_class(v1ctx, 7);
|
||||
|
||||
if (v2page && v2page->lease_page && meta_ptr && v1hcls &&
|
||||
v2page->meta == meta_ptr && tiny_heap_ptr_in_page_range(v2page->lease_page, p)) {
|
||||
tiny_heap_page_free_local(v1ctx, 7, v2page->lease_page, p);
|
||||
v2page->freelist = v2page->lease_page->free_list;
|
||||
v2page->used = v2page->lease_page->used;
|
||||
vhcls->current_page = v2page; // keep pinned
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: mimic v1 free path
|
||||
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_free_fallback, 1, memory_order_relaxed);
|
||||
SuperSlab* ss = hak_super_lookup(p);
|
||||
if (ss && ss->magic == SUPERSLAB_MAGIC) {
|
||||
int slab_idx = slab_index_for(ss, p);
|
||||
if (slab_idx >= 0 && slab_idx < ss_slabs_capacity(ss)) {
|
||||
tiny_c7_free_fast_with_meta(ss, slab_idx, p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
tiny_c7_free_fast(p);
|
||||
}
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
|
||||
Reference in New Issue
Block a user