Files
hakmem/core/tiny_c7_ultra.c
2025-12-10 22:19:32 +09:00

175 lines
4.9 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_c7_ultra.c - UF-2: C7 ULTRA TLS freelist (coldは既存 v3 を使用)
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "box/tiny_c7_ultra_box.h"
#include "box/smallobject_hotbox_v3_box.h"
#include "box/tiny_geometry_box.h"
#include "tiny_region_id.h"
#include "box/tiny_c7_ultra_segment_box.h"
static __thread tiny_c7_ultra_tls_t g_tiny_c7_ultra_tls;
static inline void tiny_c7_ultra_clear(tiny_c7_ultra_tls_t* tls) {
tls->page_base = NULL;
tls->block_size = 0;
tls->capacity = 0;
tls->used = 0;
tls->freelist = NULL;
tls->page_idx = 0;
tls->page_meta = NULL;
}
tiny_c7_ultra_tls_t* tiny_c7_ultra_tls_get(void) {
return &g_tiny_c7_ultra_tls;
}
// セグメントから C7 ページを 1 枚借りて自前で carve する
static bool tiny_c7_ultra_lease_page(tiny_c7_ultra_tls_t* tls) {
tiny_c7_ultra_segment_t* seg = tls->seg;
if (!seg) {
seg = tiny_c7_ultra_segment_acquire();
if (!seg) return false;
tls->seg = seg;
}
size_t block_sz = tls->block_size ? tls->block_size
: (size_t)tiny_stride_for_class(7);
if (block_sz == 0) return false;
uint32_t capacity = (uint32_t)(seg->page_size / block_sz);
if (capacity == 0) return false;
// 空きページを 1 枚だけ拾うUF-3 では最初の空きを線形探索)
uint32_t chosen = seg->num_pages;
for (uint32_t i = 0; i < seg->num_pages; i++) {
tiny_c7_ultra_page_meta_t* pm = &seg->pages[i];
if (pm->capacity == 0 || pm->used == 0) {
chosen = i;
break;
}
}
if (chosen == seg->num_pages) {
return false;
}
tiny_c7_ultra_page_meta_t* page = &seg->pages[chosen];
uint8_t* base = (uint8_t*)seg->base + ((size_t)chosen * seg->page_size);
// freelist を自前で carve
void* head = NULL;
for (int i = (int)capacity - 1; i >= 0; i--) {
uint8_t* blk = base + ((size_t)i * block_sz);
*(void**)blk = head;
head = blk;
}
if (!head) {
return false;
}
page->freelist = head;
page->capacity = capacity;
page->used = 0;
tls->page_base = base;
tls->block_size = block_sz;
tls->capacity = capacity;
tls->used = 0;
tls->freelist = head;
tls->page_idx = chosen;
tls->page_meta = page;
return true;
}
void* tiny_c7_ultra_alloc(size_t size) {
(void)size; // C7 専用のため未使用
tiny_c7_ultra_tls_t* tls = tiny_c7_ultra_tls_get();
// 1) freelist hit
void* p = tls->freelist;
if (__builtin_expect(p != NULL, 1)) {
void* next = *(void**)p;
tls->freelist = next;
if (tls->page_meta) {
tls->page_meta->freelist = next;
if (tls->page_meta->used < tls->page_meta->capacity) {
tls->page_meta->used++;
}
}
if (tls->used < tls->capacity) {
tls->used++;
}
return tiny_region_id_write_header(p, 7);
}
// 2) lease page from existing v3 cold path
if (!tiny_c7_ultra_lease_page(tls)) {
// safety fallback to v3
return so_alloc(7);
}
p = tls->freelist;
if (__builtin_expect(p == NULL, 0)) {
return so_alloc(7);
}
void* next = *(void**)p;
tls->freelist = next;
if (tls->page_meta) {
tls->page_meta->freelist = next;
if (tls->page_meta->used < tls->page_meta->capacity) {
tls->page_meta->used++;
}
}
if (tls->used < tls->capacity) {
tls->used++;
}
return tiny_region_id_write_header(p, 7);
}
void tiny_c7_ultra_free(void* ptr) {
tiny_c7_ultra_tls_t* tls = tiny_c7_ultra_tls_get();
if (!ptr) {
so_free(7, ptr);
return;
}
tiny_c7_ultra_segment_t* seg = tiny_c7_ultra_segment_from_ptr(ptr);
if (!seg) {
so_free(7, ptr);
return;
}
uint32_t page_idx = 0;
tiny_c7_ultra_page_meta_t* page = tiny_c7_ultra_page_of(ptr, &seg, &page_idx);
if (!page) {
so_free(7, ptr);
return;
}
const size_t block_sz = tls->block_size ? tls->block_size
: (size_t)tiny_stride_for_class(7);
const uint32_t cap = page->capacity ? page->capacity
: (uint32_t)(seg->page_size / block_sz);
uintptr_t base = (uintptr_t)seg->base + ((size_t)page_idx * seg->page_size);
uintptr_t paddr = (uintptr_t)ptr;
size_t span = block_sz * (size_t)cap;
if (paddr < base || paddr >= base + span || ((paddr - base) % block_sz) != 0) {
so_free(7, ptr);
return;
}
*(void**)ptr = page->freelist;
page->freelist = ptr;
if (page->used > 0) {
page->used--;
}
tls->page_meta = page;
tls->page_idx = page_idx;
tls->page_base = (void*)base;
tls->capacity = cap;
tls->block_size = block_sz;
tls->freelist = page->freelist;
tls->used = page->used;
}