Extend v6 architecture to support C5 (129-256B) in addition to C6 (257-512B): - SmallHeapCtxV6: Add tls_freelist_c5[32] and tls_count_c5 for C5 TLS cache - smallsegment_v6_box.h: Add SMALL_V6_C5_CLASS_IDX (5) and C5_BLOCK_SIZE (256) - smallobject_cold_iface_v6.c: Generalize refill_page for both C5 (256 blocks/page) and C6 (128 blocks/page) - smallobject_core_v6.c: Add C5 fast path (alloc/free) with TLS batching Performance (v6 C5 enabled): - C5-heavy: 41.0M ops/s (-23% vs v6 OFF 53.6M) - needs optimization - Mixed: 36.2M ops/s (-18% vs v6 OFF 44.0M) - functional baseline Note: C5 route requires optimization in next phase to match v6-3 performance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
98 lines
2.7 KiB
C
98 lines
2.7 KiB
C
// smallobject_cold_iface_v6.c - SmallObject ColdIface v6 実装(Phase v6-3)
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
#include "box/smallobject_cold_iface_v6.h"
|
||
#include "box/smallsegment_v6_box.h"
|
||
|
||
#ifndef likely
|
||
#define likely(x) __builtin_expect(!!(x), 1)
|
||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||
#endif
|
||
|
||
// Refill page for given class (C6 and C5 in v6-5)
|
||
SmallPageMetaV6* small_cold_v6_refill_page(uint32_t class_idx) {
|
||
// v6-5: Support C5 and C6
|
||
size_t block_size;
|
||
if (class_idx == SMALL_V6_C6_CLASS_IDX) {
|
||
block_size = SMALL_V6_C6_BLOCK_SIZE; // 512
|
||
} else if (class_idx == SMALL_V6_C5_CLASS_IDX) {
|
||
block_size = SMALL_V6_C5_BLOCK_SIZE; // 256
|
||
} else {
|
||
return NULL; // Unsupported class
|
||
}
|
||
|
||
// Get or acquire TLS segment
|
||
SmallSegmentV6* seg = small_segment_v6_acquire_for_thread();
|
||
if (unlikely(!seg)) {
|
||
return NULL;
|
||
}
|
||
|
||
// Find an available page (simple linear scan)
|
||
SmallPageMetaV6* page = NULL;
|
||
for (uint32_t i = 0; i < seg->num_pages; i++) {
|
||
if (seg->page_meta[i].capacity == 0) {
|
||
page = &seg->page_meta[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (unlikely(!page)) {
|
||
return NULL; // All pages in use
|
||
}
|
||
|
||
// Initialize page metadata
|
||
page->class_idx = (uint8_t)class_idx;
|
||
page->capacity = SMALL_PAGE_V6_SIZE / block_size; // C6: 128, C5: 256
|
||
page->used = 0;
|
||
page->flags = 0;
|
||
|
||
// Build freelist for the page
|
||
uintptr_t page_offset = (uintptr_t)page->page_idx * SMALL_PAGE_V6_SIZE;
|
||
uintptr_t page_base = seg->base + page_offset;
|
||
uint8_t* base = (uint8_t*)page_base;
|
||
|
||
// Build intrusive freelist (last to first for cache locality)
|
||
void* freelist = NULL;
|
||
for (int i = (int)page->capacity - 1; i >= 0; i--) {
|
||
uint8_t* block = base + ((size_t)i * block_size);
|
||
|
||
// Build freelist using BASE pointers
|
||
void* next = freelist;
|
||
memcpy(block, &next, sizeof(void*));
|
||
freelist = block;
|
||
}
|
||
|
||
page->free_list = freelist;
|
||
|
||
return page;
|
||
}
|
||
|
||
// Retire page (simple reset for v6-2)
|
||
void small_cold_v6_retire_page(SmallPageMetaV6* page) {
|
||
if (unlikely(!page)) {
|
||
return;
|
||
}
|
||
|
||
// v6-2: Simple reset (no actual deallocation)
|
||
page->free_list = NULL;
|
||
page->used = 0;
|
||
page->capacity = 0;
|
||
page->class_idx = 0;
|
||
page->flags = 0;
|
||
}
|
||
|
||
// Remote operations (dummy for v6-2, C6-heavy is mostly same-thread)
|
||
void small_cold_v6_remote_push(SmallPageMetaV6* page, void* ptr, uint32_t tid) {
|
||
(void)page;
|
||
(void)ptr;
|
||
(void)tid;
|
||
// Not implemented in v6-2
|
||
}
|
||
|
||
void small_cold_v6_remote_drain(SmallHeapCtxV6* ctx) {
|
||
(void)ctx;
|
||
// Not implemented in v6-2
|
||
}
|