MID-V3 Phase 0-2: Design doc, type skeleton, and RegionIdBox API
- MID-V3-0: Create design doc (docs/analysis/MID_POOL_V3_DESIGN.md) - Lane vs Page role clarification - Phase plan and checklist - MID-V3-1: Type skeleton + ENV - MidHotBoxV3, MidLaneV3, MidPageDescV3 structures - ENV controls (HAKMEM_MID_V3_ENABLED, HAKMEM_MID_V3_CLASSES) - Cold interface declarations - MID-V3-2 (V6-HDR-2): RegionIdBox Registration API completion - RegionEntry structure with sorted array storage - Binary search lookup implementation - region_id_register_v6() / region_id_unregister_v6() - REGION_KIND_MID_V3 added to enum 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
110
core/box/mid_cold_iface_v3.h
Normal file
110
core/box/mid_cold_iface_v3.h
Normal file
@ -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 <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
127
core/box/mid_hotbox_v3_box.h
Normal file
127
core/box/mid_hotbox_v3_box.h
Normal file
@ -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 <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
109
core/box/mid_hotbox_v3_env_box.h
Normal file
109
core/box/mid_hotbox_v3_env_box.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// mid_hotbox_v3_env_box.h - ENV gate for Mid/Pool HotBox v3
|
||||||
|
// デフォルト: OFF(研究用に明示 opt-in)
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@ -23,6 +23,7 @@ typedef enum {
|
|||||||
REGION_KIND_POOL_V1, // Pool v1 region
|
REGION_KIND_POOL_V1, // Pool v1 region
|
||||||
REGION_KIND_LARGE, // Large mmap allocation
|
REGION_KIND_LARGE, // Large mmap allocation
|
||||||
REGION_KIND_TINY_LEGACY, // Legacy tiny heap
|
REGION_KIND_TINY_LEGACY, // Legacy tiny heap
|
||||||
|
REGION_KIND_MID_V3, // Mid/Pool v3 page (MID-V3)
|
||||||
REGION_KIND_MAX
|
REGION_KIND_MAX
|
||||||
} region_kind_t;
|
} region_kind_t;
|
||||||
|
|
||||||
|
|||||||
210
core/mid_hotbox_v3.c
Normal file
210
core/mid_hotbox_v3.c
Normal file
@ -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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 {
|
struct RegionIdBox {
|
||||||
uint32_t next_id;
|
uint32_t next_id; // Next available ID
|
||||||
// Stub implementation - full implementation in V6-HDR-2
|
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) {
|
RegionIdBox* region_id_box_get(void) {
|
||||||
return &g_region_id_box;
|
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
|
// Forward declaration from smallsegment_v6.c
|
||||||
@ -138,6 +229,23 @@ RegionLookupV6 region_id_lookup_v6(void* ptr) {
|
|||||||
return result;
|
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)
|
// Legacy fallback (if TLS not registered yet)
|
||||||
SmallPageMetaV6* page = small_page_meta_v6_of(ptr);
|
SmallPageMetaV6* page = small_page_meta_v6_of(ptr);
|
||||||
if (page != NULL) {
|
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) {
|
uint32_t region_id_register_v6(void* base, size_t size, region_kind_t kind, void* metadata) {
|
||||||
(void)base;
|
if (!base || size == 0) {
|
||||||
(void)size;
|
return 0; // Invalid arguments
|
||||||
(void)kind;
|
}
|
||||||
(void)metadata;
|
|
||||||
// V6-HDR-1: Registration is not yet implemented
|
RegionIdBox* box = &g_region_id_box;
|
||||||
// TLS segment is implicitly "registered" by its existence
|
|
||||||
return 1; // Single region for now
|
// 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_unregister_v6(uint32_t region_id) {
|
||||||
(void)region_id;
|
if (region_id == 0 || region_id == 1) {
|
||||||
// V6-HDR-1: No-op
|
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) {
|
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_POOL_V1: return "POOL_V1";
|
||||||
case REGION_KIND_LARGE: return "LARGE";
|
case REGION_KIND_LARGE: return "LARGE";
|
||||||
case REGION_KIND_TINY_LEGACY: return "TINY_LEGACY";
|
case REGION_KIND_TINY_LEGACY: return "TINY_LEGACY";
|
||||||
|
case REGION_KIND_MID_V3: return "MID_V3";
|
||||||
default: return "INVALID";
|
default: return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void region_id_box_dump(void) {
|
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());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
283
docs/analysis/MID_POOL_V3_DESIGN.md
Normal file
283
docs/analysis/MID_POOL_V3_DESIGN.md
Normal file
@ -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 拡張 |
|
||||||
Reference in New Issue
Block a user