204 lines
6.5 KiB
C
204 lines
6.5 KiB
C
|
|
#include "tiny_ultra_heap.h"
|
|||
|
|
|
|||
|
|
#if HAKMEM_TINY_ULTRA_HEAP
|
|||
|
|
|
|||
|
|
// TinyTLS slab 配列は既存 Tiny 層の「page/local slab ビュー」
|
|||
|
|
// UltraHeap ではこれを Box 経由で見るだけに留める(挙動はまだ変えない)。
|
|||
|
|
extern __thread TinyTLSSlab g_tls_slabs[TINY_NUM_CLASSES];
|
|||
|
|
|
|||
|
|
// Unified front removed (A/B test: OFF is faster)
|
|||
|
|
// #include "../front/tiny_unified_cache.h"
|
|||
|
|
#include "../tiny_region_id.h"
|
|||
|
|
#include "../hakmem_tiny_unified_stats.h"
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
|
|||
|
|
__thread TinyUltraHeap g_tiny_ultra_heap = {0};
|
|||
|
|
|
|||
|
|
// UltraHeap L0 キャッシュ制御 (ENV: HAKMEM_TINY_ULTRA_L0)
|
|||
|
|
static inline int tiny_ultra_l0_enabled(void)
|
|||
|
|
{
|
|||
|
|
static int g_enable = -1;
|
|||
|
|
if (__builtin_expect(g_enable == -1, 0)) {
|
|||
|
|
const char* e = getenv("HAKMEM_TINY_ULTRA_L0");
|
|||
|
|
// デフォルト: 無効(0)。明示的に 1 を指定した場合のみ有効化。
|
|||
|
|
g_enable = (e && *e && *e != '0') ? 1 : 0;
|
|||
|
|
}
|
|||
|
|
return g_enable;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// L0 から 1 ブロック取得(BASE を返す)
|
|||
|
|
static inline void*
|
|||
|
|
tiny_ultra_heap_l0_pop(TinyUltraHeap* heap, int class_idx)
|
|||
|
|
{
|
|||
|
|
if (!tiny_ultra_l0_enabled()) {
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
TinyUltraL0* l0 = &heap->l0[class_idx];
|
|||
|
|
if (l0->count == 0) {
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
return l0->slots[--l0->count];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// L0 を Unified Cache から補充(BASE を複数取り出して slots[] に積む)
|
|||
|
|
// DELETED (A/B test: Unified Cache OFF is faster)
|
|||
|
|
static inline void
|
|||
|
|
tiny_ultra_heap_l0_refill_from_unified(TinyUltraHeap* heap, int class_idx)
|
|||
|
|
{
|
|||
|
|
// Unified Cache removed - no refill possible
|
|||
|
|
(void)heap;
|
|||
|
|
(void)class_idx;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Box UH-1: size → class の境界を 1 箇所に集約
|
|||
|
|
static inline int
|
|||
|
|
tiny_ultra_heap_class_for_size(size_t size)
|
|||
|
|
{
|
|||
|
|
if (__builtin_expect(size == 0 || size > tiny_get_max_size(), 0)) {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int class_idx = hak_tiny_size_to_class(size);
|
|||
|
|
if (__builtin_expect(class_idx < 0 || class_idx >= TINY_NUM_CLASSES, 0)) {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return class_idx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Box UH-2: Unified front 統合の境界
|
|||
|
|
// - hit/miss 判定と統計更新、header 書き込みまでを 1 箇所に閉じ込める。
|
|||
|
|
// DELETED (A/B test: Unified Cache OFF is faster)
|
|||
|
|
static inline void*
|
|||
|
|
tiny_ultra_heap_try_unified(TinyUltraHeap* heap, int class_idx)
|
|||
|
|
{
|
|||
|
|
// Unified Cache removed - always return NULL
|
|||
|
|
(void)heap;
|
|||
|
|
(void)class_idx;
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void tiny_ultra_heap_init(void)
|
|||
|
|
{
|
|||
|
|
if (__builtin_expect(g_tiny_ultra_heap.initialized, 1)) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Box 1: TinyUltraHeap 自体の init
|
|||
|
|
g_tiny_ultra_heap.initialized = 1;
|
|||
|
|
|
|||
|
|
// Box 2: PageLocal ビューの初期化(g_tls_slabs を alias するだけ)
|
|||
|
|
for (int cls = 0; cls < TINY_NUM_CLASSES; cls++) {
|
|||
|
|
g_tiny_ultra_heap.page[cls].tls = &g_tls_slabs[cls];
|
|||
|
|
g_tiny_ultra_heap.page[cls].cls = (uint8_t)cls;
|
|||
|
|
g_tiny_ultra_heap.alloc_unified_hit[cls] = 0;
|
|||
|
|
g_tiny_ultra_heap.alloc_unified_refill[cls] = 0;
|
|||
|
|
g_tiny_ultra_heap.alloc_fallback_ultrafront[cls] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void* tiny_ultra_heap_alloc(size_t size)
|
|||
|
|
{
|
|||
|
|
tiny_ultra_heap_init();
|
|||
|
|
|
|||
|
|
// Box UH-1: size→class 変換
|
|||
|
|
int class_idx = tiny_ultra_heap_class_for_size(size);
|
|||
|
|
if (__builtin_expect(class_idx < 0, 0)) {
|
|||
|
|
// UltraHeap は Tiny 範囲のみ担当。範囲外は NULL で Fail-Fast。
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TinyUltraHeap* heap = &g_tiny_ultra_heap;
|
|||
|
|
|
|||
|
|
// UltraHeap L0 (実験用): ホットクラス (例: C2/C3) だけを対象に、
|
|||
|
|
// Unified Cache に到達する前にローカル L0 からの供給を試す。
|
|||
|
|
if (tiny_ultra_l0_enabled() && (class_idx == 2 || class_idx == 3)) {
|
|||
|
|
void* base = tiny_ultra_heap_l0_pop(heap, class_idx);
|
|||
|
|
if (!base) {
|
|||
|
|
tiny_ultra_heap_l0_refill_from_unified(heap, class_idx);
|
|||
|
|
base = tiny_ultra_heap_l0_pop(heap, class_idx);
|
|||
|
|
}
|
|||
|
|
if (base) {
|
|||
|
|
#if HAKMEM_TINY_HEADER_CLASSIDX
|
|||
|
|
return tiny_region_id_write_header(base, class_idx);
|
|||
|
|
#else
|
|||
|
|
return base;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Unified Cache removed (A/B test: OFF is faster)
|
|||
|
|
// Always use UltraFront fallback
|
|||
|
|
void* fallback = tiny_ultrafront_malloc(size);
|
|||
|
|
if (fallback) {
|
|||
|
|
heap->alloc_fallback_ultrafront[class_idx]++;
|
|||
|
|
}
|
|||
|
|
return fallback;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int tiny_ultra_heap_free(void* ptr)
|
|||
|
|
{
|
|||
|
|
tiny_ultra_heap_init();
|
|||
|
|
|
|||
|
|
// Free については現状の UltraFront free(Unified push)に完全委譲。
|
|||
|
|
// 将来、PageLocal の freelist 連携や page 返却をここに追加する。
|
|||
|
|
return tiny_ultrafront_free(ptr);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void tiny_ultra_heap_stats_snapshot(uint64_t hit[TINY_NUM_CLASSES],
|
|||
|
|
uint64_t refill[TINY_NUM_CLASSES],
|
|||
|
|
uint64_t fallback[TINY_NUM_CLASSES],
|
|||
|
|
int reset)
|
|||
|
|
{
|
|||
|
|
tiny_ultra_heap_init();
|
|||
|
|
if (!hit || !refill || !fallback) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int cls = 0; cls < TINY_NUM_CLASSES; cls++) {
|
|||
|
|
hit[cls] = g_tiny_ultra_heap.alloc_unified_hit[cls];
|
|||
|
|
refill[cls] = g_tiny_ultra_heap.alloc_unified_refill[cls];
|
|||
|
|
fallback[cls] = g_tiny_ultra_heap.alloc_fallback_ultrafront[cls];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (reset) {
|
|||
|
|
for (int cls = 0; cls < TINY_NUM_CLASSES; cls++) {
|
|||
|
|
g_tiny_ultra_heap.alloc_unified_hit[cls] = 0;
|
|||
|
|
g_tiny_ultra_heap.alloc_unified_refill[cls] = 0;
|
|||
|
|
g_tiny_ultra_heap.alloc_fallback_ultrafront[cls] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// オプション: プロセス終了時に UltraHeap front 統計を 1 回だけダンプ(ENV で制御)
|
|||
|
|
// ENV: HAKMEM_TINY_ULTRA_HEAP_DUMP=1 で有効化(デフォルト: 無効)
|
|||
|
|
static void tiny_ultra_heap_dump_stats(void) __attribute__((destructor));
|
|||
|
|
static void tiny_ultra_heap_dump_stats(void)
|
|||
|
|
{
|
|||
|
|
const char* dump = getenv("HAKMEM_TINY_ULTRA_HEAP_DUMP");
|
|||
|
|
if (!dump || !*dump || *dump == '0') {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint64_t hit[TINY_NUM_CLASSES] = {0};
|
|||
|
|
uint64_t refill[TINY_NUM_CLASSES] = {0};
|
|||
|
|
uint64_t fallback[TINY_NUM_CLASSES] = {0};
|
|||
|
|
|
|||
|
|
tiny_ultra_heap_stats_snapshot(hit, refill, fallback, 0);
|
|||
|
|
|
|||
|
|
fprintf(stderr, "[ULTRA_HEAP_STATS] class hit refill fallback\n");
|
|||
|
|
for (int c = 0; c < TINY_NUM_CLASSES; c++) {
|
|||
|
|
if (hit[c] || refill[c] || fallback[c]) {
|
|||
|
|
fprintf(stderr, " C%d: %llu %llu %llu\n",
|
|||
|
|
c,
|
|||
|
|
(unsigned long long)hit[c],
|
|||
|
|
(unsigned long long)refill[c],
|
|||
|
|
(unsigned long long)fallback[c]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif // HAKMEM_TINY_ULTRA_HEAP
|