diff --git a/core/box/mid_cold_iface_v3.h b/core/box/mid_cold_iface_v3.h new file mode 100644 index 00000000..8a9f5a37 --- /dev/null +++ b/core/box/mid_cold_iface_v3.h @@ -0,0 +1,110 @@ +// mid_cold_iface_v3.h - Cold Interface for Mid/Pool v3 +// +// 役割: +// - L1 レベルの refill / retire 操作を定義 +// - Page carve / return +// - RegionIdBox 登録 / 解除 +// - Phase MID-V3-1: インターフェース宣言のみ +#pragma once + +#include +#include +#include + +#include "mid_hotbox_v3_box.h" + +// ============================================================================ +// Cold Interface Function Pointers (for future vtable support) +// ============================================================================ + +typedef MidPageDescV3* (*mid_cold_refill_fn)(MidHotBoxV3* hot, uint32_t class_idx); +typedef void (*mid_cold_retire_fn)(MidHotBoxV3* hot, MidPageDescV3* page); +typedef bool (*mid_cold_remote_push_fn)(MidPageDescV3* page, void* ptr, uint32_t tid); +typedef void (*mid_cold_remote_drain_fn)(MidHotBoxV3* hot); + +typedef struct MidColdIfaceV3 { + mid_cold_refill_fn refill_page; + mid_cold_retire_fn retire_page; + mid_cold_remote_push_fn remote_push; + mid_cold_remote_drain_fn remote_drain; +} MidColdIfaceV3; + +// ============================================================================ +// Default Cold Interface (direct function calls) +// ============================================================================ + +/// Refill: Get a new page from segment/pool +/// @param hot: TLS HotBox context +/// @param class_idx: Size class index +/// @return: New page with freelist, or NULL on failure +MidPageDescV3* mid_cold_v3_refill_page(MidHotBoxV3* hot, uint32_t class_idx); + +/// Retire: Return an empty page to segment/pool +/// @param hot: TLS HotBox context +/// @param page: Page to retire (must be empty) +void mid_cold_v3_retire_page(MidHotBoxV3* hot, MidPageDescV3* page); + +/// Remote push: Push freed block to remote thread's page +/// @param page: Target page (owned by different thread) +/// @param ptr: Block to free +/// @param tid: Caller's thread ID +/// @return: true if push succeeded, false if local handling needed +bool mid_cold_v3_remote_push(MidPageDescV3* page, void* ptr, uint32_t tid); + +/// Remote drain: Process blocks freed by other threads +/// @param hot: TLS HotBox context +void mid_cold_v3_remote_drain(MidHotBoxV3* hot); + +// ============================================================================ +// Segment Operations +// ============================================================================ + +/// Acquire a segment for the given class +/// @param class_idx: Size class index +/// @return: Segment pointer, or NULL on failure +MidSegmentV3* mid_segment_v3_acquire(int class_idx); + +/// Carve a page from segment +/// @param seg: Segment to carve from +/// @param class_idx: Size class index +/// @return: New page descriptor, or NULL if segment exhausted +MidPageDescV3* mid_segment_v3_carve_page(MidSegmentV3* seg, int class_idx); + +/// Return a page to segment +/// @param seg: Owning segment +/// @param page: Page to return +void mid_segment_v3_return_page(MidSegmentV3* seg, MidPageDescV3* page); + +// ============================================================================ +// Lane Operations +// ============================================================================ + +/// Refill lane from page +/// @param lane: TLS lane +/// @param page: Source page +/// @param batch_size: Number of items to transfer +void mid_lane_refill_from_page(MidLaneV3* lane, MidPageDescV3* page, uint32_t batch_size); + +/// Flush lane back to page +/// @param lane: TLS lane +/// @param page: Target page +void mid_lane_flush_to_page(MidLaneV3* lane, MidPageDescV3* page); + +// ============================================================================ +// Page Operations +// ============================================================================ + +/// Build freelist for a page +/// @param page: Page descriptor +/// @return: Freelist head +void* mid_page_build_freelist(MidPageDescV3* page); + +/// Push a block to page's freelist (thread-safe) +/// @param page: Target page +/// @param ptr: Block to push +void mid_page_push_free(MidPageDescV3* page, void* ptr); + +/// Pop a block from page's freelist +/// @param page: Source page +/// @return: Block pointer, or NULL if empty +void* mid_page_pop_free(MidPageDescV3* page); diff --git a/core/box/mid_hotbox_v3_box.h b/core/box/mid_hotbox_v3_box.h new file mode 100644 index 00000000..413e24f2 --- /dev/null +++ b/core/box/mid_hotbox_v3_box.h @@ -0,0 +1,127 @@ +// mid_hotbox_v3_box.h - Mid/Pool HotBox v3 (型スケルトン) +// +// 役割: +// - MID v3 の Lane / Page / TLS コンテキスト型と API 宣言を定義する箱。 +// - RegionIdBox 統合を前提とした設計。 +// - Phase MID-V3-1: 型スケルトンのみ(実装は後続フェーズ) +#pragma once + +#include +#include +#include + +#include "tiny_geometry_box.h" + +#ifndef MID_V3_NUM_CLASSES +#define MID_V3_NUM_CLASSES TINY_NUM_CLASSES +#endif + +// Forward declarations +struct MidSegmentV3; + +// ============================================================================ +// MidPageDescV3: Page metadata for v3 HotBox +// ============================================================================ +// Design note: Lane vs Page 二重管理を回避するため、 +// freelist は Page に authoritative として保持し、 +// Lane は TLS cache として機能する。 + +typedef struct MidPageDescV3 { + uint8_t* base; // Page base address + void* freelist; // Authoritative freelist + uint32_t capacity; // Total slots + uint32_t used; // Used count + uint32_t region_id; // RegionIdBox registration ID (0 = not registered) + uint32_t block_size; // Block size in bytes + uint8_t class_idx; // Size class index + uint8_t flags; // Page state flags + uint16_t reserved; // Alignment padding + void* slab_ref; // Underlying slab/segment reference + struct MidSegmentV3* segment; // Owning segment (NULL if legacy path) + struct MidPageDescV3* next; // Intrusive list linkage +} MidPageDescV3; + +// Page flags +#define MID_PAGE_FLAG_ACTIVE (1u << 0) // Page is in active use +#define MID_PAGE_FLAG_PARTIAL (1u << 1) // Page has free slots +#define MID_PAGE_FLAG_FULL (1u << 2) // Page is exhausted +#define MID_PAGE_FLAG_RETIRED (1u << 3) // Page returned to cold + +// ============================================================================ +// MidLaneV3: TLS lane (per-class freelist cache) +// ============================================================================ +// Design note: Lane は Page への index と freelist snapshot を保持。 +// freelist_head は TLS 内でのみ有効な cache であり、 +// 実際の freelist は MidPageDescV3.freelist にある。 + +typedef struct MidLaneV3 { + uint32_t page_idx; // Current working page index (0 = none) + void* freelist_head; // TLS-local freelist snapshot + uint32_t freelist_count; // Remaining items in cache + uint32_t alloc_count; // Allocation count (stats) + uint32_t free_count; // Free count (stats) +} MidLaneV3; + +// ============================================================================ +// MidHotBoxV3: TLS heap context (per-thread) +// ============================================================================ + +typedef struct MidHotBoxV3 { + MidLaneV3 lanes[MID_V3_NUM_CLASSES]; + uint32_t tid; // Thread ID (for remote free detection) + uint32_t flags; // Context flags +} MidHotBoxV3; + +// Context flags +#define MID_CTX_FLAG_INIT (1u << 0) // Context initialized + +// ============================================================================ +// MidSegmentV3: Segment descriptor (shared across threads) +// ============================================================================ + +typedef struct MidSegmentV3 { + uintptr_t base; // Segment base address + size_t size; // Segment size in bytes + uint32_t magic; // Validation magic number + uint32_t num_pages; // Total pages in segment + uint32_t region_id; // RegionIdBox registration ID + uint8_t class_idx; // Primary class (or 0xFF for mixed) + uint8_t flags; // Segment flags + uint16_t reserved; + // page_meta[] follows (flexible array member) +} MidSegmentV3; + +#define MID_SEGMENT_V3_MAGIC 0xCAFEBABE +#define MID_SEGMENT_V3_SIZE (2 * 1024 * 1024) // 2 MiB default +#define MID_PAGE_V3_SIZE (64 * 1024) // 64 KiB page +#define MID_PAGE_V3_SHIFT 16 // log2(64 KiB) +#define MID_PAGES_PER_SEGMENT (MID_SEGMENT_V3_SIZE / MID_PAGE_V3_SIZE) + +// ============================================================================ +// API Declarations (stubs for MID-V3-1) +// ============================================================================ + +/// Get TLS HotBox context +MidHotBoxV3* mid_hot_box_v3_get(void); + +/// Allocation fast path +void* mid_hot_v3_alloc(MidHotBoxV3* hot, int class_idx); + +/// Free fast path +void mid_hot_v3_free(void* ptr); + +/// Check if v3 can own this pointer +int mid_hotbox_v3_can_own(int class_idx, void* ptr); + +/// Page index conversion helpers +static inline uint32_t mid_page_to_idx(MidPageDescV3* page) { + // Stub: actual implementation depends on segment layout + (void)page; + return 0; +} + +static inline MidPageDescV3* mid_page_from_idx(uint32_t idx) { + // Stub: actual implementation depends on segment layout + (void)idx; + return NULL; +} diff --git a/core/box/mid_hotbox_v3_env_box.h b/core/box/mid_hotbox_v3_env_box.h new file mode 100644 index 00000000..1784b335 --- /dev/null +++ b/core/box/mid_hotbox_v3_env_box.h @@ -0,0 +1,109 @@ +// mid_hotbox_v3_env_box.h - ENV gate for Mid/Pool HotBox v3 +// デフォルト: OFF(研究用に明示 opt-in) +#pragma once + +#include +#include + +#include "../hakmem_tiny_config.h" + +// ============================================================================ +// HAKMEM_MID_V3_ENABLED: Master switch for MID v3 +// ============================================================================ + +static inline int mid_v3_enabled(void) { + static int g_enable = -1; + if (__builtin_expect(g_enable == -1, 0)) { + const char* e = getenv("HAKMEM_MID_V3_ENABLED"); + if (e && *e) { + g_enable = (*e != '0') ? 1 : 0; + } else { + // v3 は研究箱。明示しない限り OFF + g_enable = 0; + } + } + return g_enable; +} + +// ============================================================================ +// HAKMEM_MID_V3_CLASSES: Per-class enable bitmask +// ============================================================================ +// Default: 0x00 (all classes OFF) +// Example: 0xC0 = C6 + C7 enabled + +static inline int mid_v3_class_enabled(uint8_t class_idx) { + static int g_parsed = 0; + static unsigned g_mask = 0; + if (__builtin_expect(!g_parsed, 0)) { + const char* e = getenv("HAKMEM_MID_V3_CLASSES"); + if (e && *e) { + unsigned v = (unsigned)strtoul(e, NULL, 0); + g_mask = v & 0xFFu; + } else { + // デフォルトは全クラス OFF + g_mask = 0; + } + g_parsed = 1; + } + if (!mid_v3_enabled()) return 0; + if (class_idx >= TINY_NUM_CLASSES) return 0; + return (g_mask & (1u << class_idx)) != 0; +} + +// ============================================================================ +// Per-class convenience functions +// ============================================================================ + +static inline int mid_v3_c7_enabled(void) { + return mid_v3_class_enabled(7); +} + +static inline int mid_v3_c6_enabled(void) { + return mid_v3_class_enabled(6); +} + +static inline int mid_v3_c5_enabled(void) { + return mid_v3_class_enabled(5); +} + +static inline int mid_v3_c4_enabled(void) { + return mid_v3_class_enabled(4); +} + +// ============================================================================ +// HAKMEM_MID_V3_DEBUG: Debug logging +// ============================================================================ + +static inline int mid_v3_debug_enabled(void) { + static int g_debug = -1; + if (__builtin_expect(g_debug == -1, 0)) { + const char* e = getenv("HAKMEM_MID_V3_DEBUG"); + if (e && *e) { + g_debug = (*e != '0') ? 1 : 0; + } else { + g_debug = 0; + } + } + return g_debug; +} + +// ============================================================================ +// HAKMEM_MID_V3_LANE_BATCH: Lane refill batch size +// ============================================================================ +// How many items to transfer from page to lane on refill + +static inline uint32_t mid_v3_lane_batch_size(void) { + static int g_parsed = 0; + static uint32_t g_batch = 0; + if (__builtin_expect(!g_parsed, 0)) { + const char* e = getenv("HAKMEM_MID_V3_LANE_BATCH"); + if (e && *e) { + g_batch = (uint32_t)strtoul(e, NULL, 0); + } else { + // Default: 16 items per batch + g_batch = 16; + } + g_parsed = 1; + } + return g_batch; +} diff --git a/core/box/region_id_v6_box.h b/core/box/region_id_v6_box.h index 1753f5da..9c81804a 100644 --- a/core/box/region_id_v6_box.h +++ b/core/box/region_id_v6_box.h @@ -23,6 +23,7 @@ typedef enum { REGION_KIND_POOL_V1, // Pool v1 region REGION_KIND_LARGE, // Large mmap allocation REGION_KIND_TINY_LEGACY, // Legacy tiny heap + REGION_KIND_MID_V3, // Mid/Pool v3 page (MID-V3) REGION_KIND_MAX } region_kind_t; diff --git a/core/mid_hotbox_v3.c b/core/mid_hotbox_v3.c new file mode 100644 index 00000000..53f7e6aa --- /dev/null +++ b/core/mid_hotbox_v3.c @@ -0,0 +1,210 @@ +// mid_hotbox_v3.c - Mid/Pool HotBox v3 Implementation +// +// Phase MID-V3-1: Stub implementation (skeleton only) +// Phase MID-V3-4/5: Full implementation + +#include +#include +#include + +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#include "box/mid_hotbox_v3_box.h" +#include "box/mid_hotbox_v3_env_box.h" +#include "box/mid_cold_iface_v3.h" +#include "box/region_id_v6_box.h" + +// ============================================================================ +// TLS Context +// ============================================================================ + +static __thread MidHotBoxV3 g_mid_hot_ctx_v3; +static __thread int g_mid_hot_ctx_v3_init = 0; + +MidHotBoxV3* mid_hot_box_v3_get(void) { + if (unlikely(!g_mid_hot_ctx_v3_init)) { + memset(&g_mid_hot_ctx_v3, 0, sizeof(g_mid_hot_ctx_v3)); + g_mid_hot_ctx_v3.flags = MID_CTX_FLAG_INIT; + g_mid_hot_ctx_v3_init = 1; + } + return &g_mid_hot_ctx_v3; +} + +// ============================================================================ +// Allocation Fast Path (MID-V3-4 stub) +// ============================================================================ + +void* mid_hot_v3_alloc(MidHotBoxV3* hot, int class_idx) { + if (unlikely(!mid_v3_class_enabled((uint8_t)class_idx))) { + return NULL; // Class not enabled + } + + if (!hot) { + hot = mid_hot_box_v3_get(); + } + + MidLaneV3* lane = &hot->lanes[class_idx]; + + // L0: TLS freelist cache hit + if (likely(lane->freelist_head)) { + void* blk = lane->freelist_head; + void* next = NULL; + memcpy(&next, blk, sizeof(void*)); + lane->freelist_head = next; + lane->freelist_count--; + lane->alloc_count++; + return blk; + } + + // L0 miss: slow path + return NULL; // Stub: MID-V3-4 will implement slow path +} + +// ============================================================================ +// Free Fast Path (MID-V3-5 stub) +// ============================================================================ + +void mid_hot_v3_free(void* ptr) { + if (unlikely(!ptr)) return; + if (unlikely(!mid_v3_enabled())) return; + + // RegionIdBox lookup + RegionLookupV6 lk = region_id_lookup_cached_v6(ptr); + + // Stub: MID-V3-5 will implement full free path + (void)lk; +} + +// ============================================================================ +// Ownership Check +// ============================================================================ + +int mid_hotbox_v3_can_own(int class_idx, void* ptr) { + if (unlikely(!mid_v3_class_enabled((uint8_t)class_idx))) { + return 0; + } + if (!ptr) return 0; + + // RegionIdBox lookup + RegionLookupV6 lk = region_id_lookup_v6(ptr); + + // Check if this is a MID v3 region + // Stub: For now, always return 0 until MID-V3-3 implements registration + (void)lk; + return 0; +} + +// ============================================================================ +// Cold Interface Stubs (MID-V3-4/5) +// ============================================================================ + +MidPageDescV3* mid_cold_v3_refill_page(MidHotBoxV3* hot, uint32_t class_idx) { + (void)hot; + (void)class_idx; + // Stub: MID-V3-4 will implement + return NULL; +} + +void mid_cold_v3_retire_page(MidHotBoxV3* hot, MidPageDescV3* page) { + (void)hot; + (void)page; + // Stub: MID-V3-5 will implement +} + +bool mid_cold_v3_remote_push(MidPageDescV3* page, void* ptr, uint32_t tid) { + (void)page; + (void)ptr; + (void)tid; + // Stub: MID-V3-5 will implement + return false; +} + +void mid_cold_v3_remote_drain(MidHotBoxV3* hot) { + (void)hot; + // Stub: MID-V3-5 will implement +} + +// ============================================================================ +// Segment Operations Stubs +// ============================================================================ + +MidSegmentV3* mid_segment_v3_acquire(int class_idx) { + (void)class_idx; + // Stub: MID-V3-4 will implement + return NULL; +} + +MidPageDescV3* mid_segment_v3_carve_page(MidSegmentV3* seg, int class_idx) { + (void)seg; + (void)class_idx; + // Stub: MID-V3-4 will implement + return NULL; +} + +void mid_segment_v3_return_page(MidSegmentV3* seg, MidPageDescV3* page) { + (void)seg; + (void)page; + // Stub: MID-V3-5 will implement +} + +// ============================================================================ +// Lane Operations Stubs +// ============================================================================ + +void mid_lane_refill_from_page(MidLaneV3* lane, MidPageDescV3* page, uint32_t batch_size) { + (void)lane; + (void)page; + (void)batch_size; + // Stub: MID-V3-4 will implement +} + +void mid_lane_flush_to_page(MidLaneV3* lane, MidPageDescV3* page) { + (void)lane; + (void)page; + // Stub: MID-V3-5 will implement +} + +// ============================================================================ +// Page Operations Stubs +// ============================================================================ + +void* mid_page_build_freelist(MidPageDescV3* page) { + (void)page; + // Stub: MID-V3-4 will implement + return NULL; +} + +void mid_page_push_free(MidPageDescV3* page, void* ptr) { + (void)page; + (void)ptr; + // Stub: MID-V3-5 will implement +} + +void* mid_page_pop_free(MidPageDescV3* page) { + (void)page; + // Stub: MID-V3-4 will implement + return NULL; +} + +// ============================================================================ +// Debug +// ============================================================================ + +void mid_hot_v3_dump_stats(void) { + if (!mid_v3_debug_enabled()) return; + + MidHotBoxV3* hot = mid_hot_box_v3_get(); + fprintf(stderr, "[MID_V3] HotBox stats:\n"); + + for (int i = 0; i < MID_V3_NUM_CLASSES; i++) { + if (!mid_v3_class_enabled((uint8_t)i)) continue; + + MidLaneV3* lane = &hot->lanes[i]; + fprintf(stderr, " C%d: page_idx=%u freelist_count=%u alloc=%u free=%u\n", + i, lane->page_idx, lane->freelist_count, + lane->alloc_count, lane->free_count); + } +} diff --git a/core/region_id_v6.c b/core/region_id_v6.c index 11f7eebd..3c6a7178 100644 --- a/core/region_id_v6.c +++ b/core/region_id_v6.c @@ -68,23 +68,114 @@ void region_id_register_v6_segment(SmallSegmentV6* seg) { } // ============================================================================ -// Global RegionIdBox (stub for now) +// Global RegionIdBox (V6-HDR-2: Full implementation) // ============================================================================ -// Define the opaque RegionIdBox structure +// Maximum number of registered regions +#define REGION_MAX_ENTRIES 256 + +// RegionEntry: Single registered region +typedef struct RegionEntry { + uintptr_t base; // Region base address + uintptr_t end; // Region end address (exclusive) + region_kind_t kind; // Region type + void* metadata; // Kind-specific metadata (e.g., page_meta) + uint32_t id; // Unique region ID + uint8_t active; // 1 = active, 0 = free slot + uint8_t reserved[3]; // Padding +} RegionEntry; + +// RegionIdBox: Region registry struct RegionIdBox { - uint32_t next_id; - // Stub implementation - full implementation in V6-HDR-2 + uint32_t next_id; // Next available ID + uint32_t count; // Number of active entries + RegionEntry entries[REGION_MAX_ENTRIES]; // Sorted by base address + // Note: entries are kept sorted by base for binary search lookup }; -static struct RegionIdBox g_region_id_box; +static struct RegionIdBox g_region_id_box = { + .next_id = 2, // Start from 2 (1 is reserved for TLS segment) + .count = 0 +}; RegionIdBox* region_id_box_get(void) { return &g_region_id_box; } +// Binary search helper: find entry containing address +static RegionEntry* region_entry_find(uintptr_t addr) { + RegionIdBox* box = &g_region_id_box; + if (box->count == 0) return NULL; + + // Binary search for entry where base <= addr < end + uint32_t lo = 0, hi = box->count; + while (lo < hi) { + uint32_t mid = lo + (hi - lo) / 2; + RegionEntry* e = &box->entries[mid]; + if (!e->active) { + // Skip inactive entries (shouldn't happen in sorted array) + lo = mid + 1; + continue; + } + if (addr < e->base) { + hi = mid; + } else if (addr >= e->end) { + lo = mid + 1; + } else { + // addr is in range [base, end) + return e; + } + } + return NULL; +} + +// Insert entry maintaining sorted order +static int region_entry_insert(RegionEntry* entry) { + RegionIdBox* box = &g_region_id_box; + if (box->count >= REGION_MAX_ENTRIES) { + return -1; // Registry full + } + + // Find insertion point (binary search) + uint32_t pos = 0; + for (uint32_t i = 0; i < box->count; i++) { + if (box->entries[i].base > entry->base) { + pos = i; + break; + } + pos = i + 1; + } + + // Shift entries to make room + for (uint32_t i = box->count; i > pos; i--) { + box->entries[i] = box->entries[i - 1]; + } + + // Insert new entry + box->entries[pos] = *entry; + box->count++; + return 0; +} + +// Remove entry by ID +static int region_entry_remove(uint32_t id) { + RegionIdBox* box = &g_region_id_box; + + for (uint32_t i = 0; i < box->count; i++) { + if (box->entries[i].id == id && box->entries[i].active) { + // Shift entries to fill gap + for (uint32_t j = i; j < box->count - 1; j++) { + box->entries[j] = box->entries[j + 1]; + } + box->count--; + return 0; + } + } + return -1; // Not found +} + // ============================================================================ -// Lookup Implementation (V6-HDR-1: TLS segment only) +// Lookup Implementation (V6-HDR-2: TLS + Registry) // ============================================================================ // Forward declaration from smallsegment_v6.c @@ -138,6 +229,23 @@ RegionLookupV6 region_id_lookup_v6(void* ptr) { return result; } + // V6-HDR-2: Check registered regions (binary search) + RegionEntry* entry = region_entry_find(addr); + if (entry) { + result.kind = entry->kind; + result.region_id = entry->id; + result.page_meta = entry->metadata; + + // Update TLS cache for segment-level caching + RegionIdTlsCache* cache = region_id_tls_cache_get(); + cache->last_base = entry->base; + cache->last_end = entry->end; + cache->last_result = result; + // Note: page-level cache not applicable for arbitrary registered regions + + return result; + } + // Legacy fallback (if TLS not registered yet) SmallPageMetaV6* page = small_page_meta_v6_of(ptr); if (page != NULL) { @@ -196,26 +304,61 @@ RegionLookupV6 region_id_lookup_cached_v6(void* ptr) { } // ============================================================================ -// Registration API (Stub for V6-HDR-1) +// Registration API (V6-HDR-2: Full implementation) // ============================================================================ uint32_t region_id_register_v6(void* base, size_t size, region_kind_t kind, void* metadata) { - (void)base; - (void)size; - (void)kind; - (void)metadata; - // V6-HDR-1: Registration is not yet implemented - // TLS segment is implicitly "registered" by its existence - return 1; // Single region for now + if (!base || size == 0) { + return 0; // Invalid arguments + } + + RegionIdBox* box = &g_region_id_box; + + // Create new entry + RegionEntry entry = { + .base = (uintptr_t)base, + .end = (uintptr_t)base + size, + .kind = kind, + .metadata = metadata, + .id = box->next_id, + .active = 1 + }; + + // Insert into registry + if (region_entry_insert(&entry) != 0) { + return 0; // Registry full + } + + uint32_t id = box->next_id++; + + // OBSERVE mode logging + region_id_observe_register(base, size, kind, id); + + return id; } void region_id_unregister_v6(uint32_t region_id) { - (void)region_id; - // V6-HDR-1: No-op + if (region_id == 0 || region_id == 1) { + return; // Invalid or reserved ID + } + + // OBSERVE mode logging + region_id_observe_unregister(region_id); + + region_entry_remove(region_id); } bool region_id_is_valid_v6(uint32_t region_id) { - return region_id == 1; // Only TLS segment is "registered" + if (region_id == 0) return false; + if (region_id == 1) return true; // Reserved for TLS segment + + RegionIdBox* box = &g_region_id_box; + for (uint32_t i = 0; i < box->count; i++) { + if (box->entries[i].id == region_id && box->entries[i].active) { + return true; + } + } + return false; } // ============================================================================ @@ -230,13 +373,33 @@ const char* region_kind_to_string(region_kind_t kind) { case REGION_KIND_POOL_V1: return "POOL_V1"; case REGION_KIND_LARGE: return "LARGE"; case REGION_KIND_TINY_LEGACY: return "TINY_LEGACY"; + case REGION_KIND_MID_V3: return "MID_V3"; default: return "INVALID"; } } void region_id_box_dump(void) { - fprintf(stderr, "[REGION_ID_BOX] V6-HDR-1: TLS segment lookup only\n"); + fprintf(stderr, "[REGION_ID_BOX] V6-HDR-2: TLS segment + Registry\n"); fprintf(stderr, "[REGION_ID_BOX] observe=%d\n", region_id_observe_enabled()); + + RegionIdBox* box = &g_region_id_box; + fprintf(stderr, "[REGION_ID_BOX] next_id=%u count=%u\n", box->next_id, box->count); + + // Dump TLS segment info + if (g_v6_segment_registered) { + fprintf(stderr, "[REGION_ID_BOX] TLS segment: base=%p end=%p (reserved id=1)\n", + (void*)g_v6_segment_base, (void*)g_v6_segment_end); + } + + // Dump registered regions + for (uint32_t i = 0; i < box->count; i++) { + RegionEntry* e = &box->entries[i]; + if (e->active) { + fprintf(stderr, "[REGION_ID_BOX] [%u] id=%u kind=%s base=%p end=%p meta=%p\n", + i, e->id, region_kind_to_string(e->kind), + (void*)e->base, (void*)e->end, e->metadata); + } + } } // ============================================================================ diff --git a/docs/analysis/MID_POOL_V3_DESIGN.md b/docs/analysis/MID_POOL_V3_DESIGN.md new file mode 100644 index 00000000..d0f3e9a8 --- /dev/null +++ b/docs/analysis/MID_POOL_V3_DESIGN.md @@ -0,0 +1,283 @@ +# MID_POOL_V3 設計書 + +## 概要 + +Mid/Pool v3 は既存の SmallObject v4 (MF2) を発展させ、RegionIdBox による ptr→page_meta O(1) lookup を統合した次世代アーキテクチャ。 + +## Phase Plan + +| Phase | 内容 | 依存 | +|-------|------|------| +| MID-V3-0 | 設計 doc (本文書) | - | +| MID-V3-1 | 型スケルトン + ENV | MID-V3-0 | +| MID-V3-2 | RegionIdBox Registration API 完成 (V6-HDR-2) | MID-V3-1 | +| MID-V3-3 | RegionId 統合 (page registration at carve) | MID-V3-2 | +| MID-V3-4 | Allocation fast path 実装 | MID-V3-3 | +| MID-V3-5 | Free/cold path 実装 | MID-V3-4 | + +## 設計課題: Lane vs Page 二重管理問題 + +### 問題点 (Task Review で指摘) + +当初の設計案では Lane と Page の両方で freelist を管理することを想定していたが、 +既存 v4 MF2 では per-page freelist が既に機能しており、 +Lane を追加すると管理責任が二重化する。 + +### 既存 v4 MF2 構造 + +```c +// core/smallobject_hotbox_v4.c +typedef struct small_page_v4 { + uint8_t class_idx; + uint16_t capacity; + uint16_t used; + uint32_t block_size; + uint8_t* base; + void* freelist; // ← Per-page freelist + void* slab_ref; + void* segment; + struct small_page_v4* next; + uint16_t flags; +} small_page_v4; + +typedef struct small_class_heap_v4 { + small_page_v4* current; // Current working page + small_page_v4* partial_head; // Partial pages list + uint32_t partial_count; + small_page_v4* full_head; // Full pages list +} small_class_heap_v4; +``` + +### 解決策: Lane = Page Index Cache + +Lane を独立した freelist 管理単位としてではなく、 +**TLS が現在作業中の page への index/cache** として再定義する。 + +``` +┌──────────────────────────────────────────────────────┐ +│ MidHotBoxV3 (L0 TLS) │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ lane[class] = { page_idx, freelist_cache } │ │ +│ │ ↓ │ │ +│ │ page_idx → MidPageDesc (via RegionIdBox) │ │ +│ └─────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────┘ + ↓ refill/retire +┌──────────────────────────────────────────────────────┐ +│ MidColdIfaceV3 (L1) │ +│ - page carve (segment → page) │ +│ - page return (page → segment) │ +│ - RegionIdBox registration │ +└──────────────────────────────────────────────────────┘ +``` + +### Lane 構造 (Revised) + +```c +typedef struct MidLaneV3 { + uint32_t page_idx; // Current working page index + void* freelist_head; // TLS-local freelist snapshot (fast path) + uint32_t freelist_count; // Remaining items in freelist + // Note: 実際の freelist は MidPageDesc にあり、 + // lane は TLS cache として機能 +} MidLaneV3; +``` + +### Page 構造 + +```c +typedef struct MidPageDescV3 { + uint8_t* base; // Page base address + uint32_t capacity; // Total slots + uint32_t used; // Used count + void* freelist; // Actual freelist (authoritative) + uint32_t region_id; // RegionIdBox registration ID + uint8_t class_idx; // Size class + uint8_t flags; // Page state flags +} MidPageDescV3; +``` + +## RegionIdBox 統合 + +### 現状 (V6-HDR-1) + +`region_id_register_v6()` は stub 状態: + +```c +// core/region_id_v6.c:202 +uint32_t region_id_register_v6(void* base, size_t size, region_kind_t kind, void* metadata) { + (void)base; + (void)size; + (void)kind; + (void)metadata; + return 1; // Single region for now +} +``` + +### V6-HDR-2: Registration API 完成 (MID-V3-2) + +```c +// 必要な機能: +// 1. Region entry array (固定サイズ or 動的) +// 2. ptr → region_entry lookup (radix tree or sorted array) +// 3. Thread-safe registration/unregistration + +typedef struct RegionEntry { + uintptr_t base; + uintptr_t end; + region_kind_t kind; + void* metadata; // MidPageDescV3* for SMALL_V4 + uint32_t id; +} RegionEntry; + +// API +uint32_t region_id_register_v6(void* base, size_t size, region_kind_t kind, void* metadata); +void region_id_unregister_v6(uint32_t region_id); +RegionLookupV6 region_id_lookup_v6(void* ptr); +``` + +### MID-V3-3: Page Registration at Carve + +```c +// Page carve 時に RegionIdBox に登録 +MidPageDescV3* mid_cold_v3_carve_page(MidSegmentV3* seg, int class_idx) { + MidPageDescV3* page = /* ... carve from segment ... */; + + // RegionIdBox に登録 + page->region_id = region_id_register_v6( + page->base, + page->capacity * stride_for_class(class_idx), + REGION_KIND_SMALL_V4, // or new REGION_KIND_MID_V3 + page + ); + + return page; +} + +// Page return 時に登録解除 +void mid_cold_v3_return_page(MidPageDescV3* page) { + region_id_unregister_v6(page->region_id); + /* ... return to segment ... */ +} +``` + +## Allocation Fast Path (MID-V3-4) + +```c +void* mid_hot_v3_alloc(MidHotBoxV3* hot, int class_idx) { + MidLaneV3* lane = &hot->lanes[class_idx]; + + // L0: TLS freelist cache hit + if (likely(lane->freelist_head)) { + void* blk = lane->freelist_head; + lane->freelist_head = *(void**)blk; + lane->freelist_count--; + return blk; + } + + // L0 miss: Refill from page or cold path + return mid_hot_v3_alloc_slow(hot, class_idx); +} + +static void* mid_hot_v3_alloc_slow(MidHotBoxV3* hot, int class_idx) { + MidLaneV3* lane = &hot->lanes[class_idx]; + + // Try to refill from current page + if (lane->page_idx != 0) { + MidPageDescV3* page = mid_page_from_idx(lane->page_idx); + if (page && page->freelist) { + // Batch transfer from page to lane + mid_lane_refill_from_page(lane, page); + return mid_hot_v3_alloc(hot, class_idx); + } + } + + // Cold path: Get new page + MidPageDescV3* new_page = mid_cold_v3_refill_page(hot, class_idx); + if (!new_page) return NULL; + + lane->page_idx = mid_page_to_idx(new_page); + mid_lane_refill_from_page(lane, new_page); + return mid_hot_v3_alloc(hot, class_idx); +} +``` + +## Free Path (MID-V3-5) + +```c +void mid_hot_v3_free(void* ptr) { + // RegionIdBox lookup (O(1) via TLS cache) + RegionLookupV6 lk = region_id_lookup_cached_v6(ptr); + + if (lk.kind != REGION_KIND_MID_V3) { + // Not our allocation, delegate + return; + } + + MidPageDescV3* page = (MidPageDescV3*)lk.page_meta; + + // Check if local thread owns this page + MidHotBoxV3* hot = mid_hot_box_v3_get(); + MidLaneV3* lane = &hot->lanes[page->class_idx]; + + if (lane->page_idx == mid_page_to_idx(page)) { + // Local page: direct push to lane freelist + *(void**)ptr = lane->freelist_head; + lane->freelist_head = ptr; + lane->freelist_count++; + return; + } + + // Remote page: push to page freelist (atomic if needed) + mid_page_push_free(page, ptr); +} +``` + +## ENV Controls + +``` +HAKMEM_MID_V3_ENABLED=1 # Enable MID v3 (default: 0) +HAKMEM_MID_V3_CLASSES=0xFF # Class bitmask (default: 0xFF = all) +HAKMEM_MID_V3_DEBUG=1 # Debug logging (default: 0) +``` + +## Checklist + +- [ ] MID-V3-1: 型スケルトン + ENV + - [ ] MidHotBoxV3 structure + - [ ] MidLaneV3 structure + - [ ] MidPageDescV3 structure + - [ ] MidColdIfaceV3 interface + - [ ] ENV parsing + +- [ ] MID-V3-2: RegionIdBox Registration API (V6-HDR-2) + - [ ] RegionEntry structure + - [ ] region_id_register_v6() implementation + - [ ] region_id_unregister_v6() implementation + - [ ] Lookup integration (ptr → page_meta) + +- [ ] MID-V3-3: RegionId 統合 + - [ ] Page carve time registration + - [ ] Page return time unregistration + - [ ] TLS segment auto-registration + +- [ ] MID-V3-4: Allocation fast path + - [ ] Lane freelist fast path + - [ ] Page refill slow path + - [ ] Cold refill integration + +- [ ] MID-V3-5: Free/cold path + - [ ] RegionIdBox lookup in free + - [ ] Local page fast free + - [ ] Remote page handling + +## 参考: 既存コードとの関係 + +| 既存 | v3 対応 | +|------|---------| +| smallobject_hotbox_v4.c | mid_hotbox_v3.c (新規) | +| small_page_v4 | MidPageDescV3 | +| small_class_heap_v4 | MidLaneV3 | +| cold_refill_page_v4() | mid_cold_v3_refill_page() | +| cold_retire_page_v4() | mid_cold_v3_retire_page() | +| region_id_v6.c | RegionIdBox API 拡張 |