- Add C5 (256B blocks) support alongside C6 (512B blocks) - Same segment shared between C5/C6 (page_meta.class_idx distinguishes) - SMALL_V7_CLASS_SUPPORTED() macro for class validation - Extend small_v7_block_size() for C5 (switch statement) A/B Result: C6-only v7 avg 7.64M ops/s → C5+C6 v7 avg 7.97M ops/s (+4.3%) Criteria: C6 protected ✅, C5 net positive ✅, TLS bloat none ✅ ENV: HAKMEM_SMALL_HEAP_V7_CLASSES=0x60 (bit5+bit6) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
167 lines
6.9 KiB
C
167 lines
6.9 KiB
C
// smallsegment_v7_box.h - SmallSegment v7 (Phase v7-2: C6-only implementation)
|
|
//
|
|
// Purpose:
|
|
// - SmallObject v7 segment structure with 2MiB/64KiB geometry
|
|
// - Supports free_page stack for page management
|
|
// - RegionIdBox integration via REGION_KIND_SMALL_V7
|
|
|
|
#ifndef HAKMEM_SMALLSEGMENT_V7_BOX_H
|
|
#define HAKMEM_SMALLSEGMENT_V7_BOX_H
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
// ============================================================================
|
|
// Segment Constants (same geometry as V6/ULTRA)
|
|
// ============================================================================
|
|
|
|
#define SMALL_SEGMENT_V7_SIZE (2u * 1024u * 1024u) // 2 MiB
|
|
#define SMALL_PAGE_V7_SIZE (64u * 1024u) // 64 KiB
|
|
#define SMALL_PAGES_PER_SEG_V7 (SMALL_SEGMENT_V7_SIZE / SMALL_PAGE_V7_SIZE) // 32
|
|
#define SMALL_PAGE_V7_SHIFT 16 // log2(64KiB)
|
|
#define SMALL_SEGMENT_V7_MAGIC 0xC07E57u // C0(re) v7
|
|
|
|
// ============================================================================
|
|
// Class Configuration (v7-5b: C5+C6)
|
|
// ============================================================================
|
|
|
|
// C6: 513-768B → 512B blocks
|
|
#define SMALL_V7_C6_CLASS_IDX 6
|
|
#define SMALL_V7_C6_BLOCK_SIZE 512
|
|
|
|
// C5: 257-512B → 256B blocks (v7-5b)
|
|
#define SMALL_V7_C5_CLASS_IDX 5
|
|
#define SMALL_V7_C5_BLOCK_SIZE 256
|
|
|
|
// v7-5b: Class support check macro
|
|
#define SMALL_V7_CLASS_SUPPORTED(ci) ((ci) == 5 || (ci) == 6)
|
|
|
|
// ============================================================================
|
|
// Page Index Calculation
|
|
// ============================================================================
|
|
|
|
#define SMALL_V7_PAGE_IDX(seg, addr) (((uintptr_t)(addr) - (seg)->base) >> SMALL_PAGE_V7_SHIFT)
|
|
|
|
// ============================================================================
|
|
// Forward Declarations
|
|
// ============================================================================
|
|
|
|
typedef struct SmallSegment_v7 SmallSegment_v7;
|
|
typedef struct SmallPageMeta_v7 SmallPageMeta_v7;
|
|
|
|
// ============================================================================
|
|
// SmallPageMeta_v7 - Page metadata (per-page hot/cold fields)
|
|
// ============================================================================
|
|
|
|
typedef struct SmallPageMeta_v7 {
|
|
// ---- Hot fields (cache line 0, accessed in alloc/free) ----
|
|
void* free_list; // LIFO freelist: block -> next
|
|
uint32_t used; // Current used slot count
|
|
uint32_t capacity; // Total block slots in this page
|
|
|
|
uint16_t class_idx; // Size class (C0..C7)
|
|
uint16_t flags; // HOT/PARTIAL/FULL/REMOTE_PENDING
|
|
uint16_t page_idx; // Index within segment (0..31)
|
|
uint16_t reserved0; // Alignment padding
|
|
|
|
SmallSegment_v7* segment; // Back pointer to owning segment
|
|
|
|
// Intrusive list pointer for partial pages (optional)
|
|
SmallPageMeta_v7* segment_next_partial;
|
|
|
|
// ---- Cold fields (Stats/Policy, cache line 1+) ----
|
|
uint64_t alloc_count; // Cumulative alloc count
|
|
uint64_t free_count; // Cumulative free count
|
|
uint64_t remote_free_count; // Cumulative remote free count
|
|
|
|
uint16_t live_current; // Current live objects
|
|
uint16_t peak_live; // Lifetime peak live
|
|
uint16_t remote_burst_max; // Max remote drain in one pass
|
|
uint16_t reserved1;
|
|
|
|
uint32_t epoch_first_alloc; // Coarse epoch (for L3/Learner)
|
|
uint32_t epoch_last_free; // Coarse epoch (for L3/Learner)
|
|
} SmallPageMeta_v7;
|
|
|
|
// ============================================================================
|
|
// SmallSegment_v7 - 2MiB segment with page metadata
|
|
// ============================================================================
|
|
|
|
typedef struct SmallSegment_v7 {
|
|
uintptr_t base; // Segment base address (2MiB aligned)
|
|
uint32_t num_pages; // Number of pages (32)
|
|
uint32_t owner_tid; // Owner thread ID
|
|
|
|
uint32_t flags; // SEGMENT_IN_USE / RETIRED etc.
|
|
uint32_t magic; // SMALL_SEGMENT_V7_MAGIC
|
|
uint32_t region_kind; // REGION_KIND_SMALL_V7
|
|
uint32_t segment_idx; // RegionIdBox index
|
|
|
|
uint32_t free_page_head; // Free page stack head (page_idx, 0xFFFFFFFF = empty)
|
|
uint32_t free_page_count; // Number of free pages
|
|
|
|
SmallPageMeta_v7 page_meta[SMALL_PAGES_PER_SEG_V7];
|
|
} SmallSegment_v7;
|
|
|
|
// ============================================================================
|
|
// Inline Helper Functions
|
|
// ============================================================================
|
|
|
|
/// Check if page is valid and active
|
|
static inline int small_page_v7_valid(SmallPageMeta_v7* page) {
|
|
return page != NULL && page->capacity > 0;
|
|
}
|
|
|
|
/// Check if pointer is within segment bounds
|
|
static inline int small_ptr_in_segment_v7(SmallSegment_v7* seg, void* ptr) {
|
|
uintptr_t addr = (uintptr_t)ptr;
|
|
return addr >= seg->base && addr < seg->base + SMALL_SEGMENT_V7_SIZE;
|
|
}
|
|
|
|
/// Check if segment is valid and initialized
|
|
static inline int small_segment_v7_valid(SmallSegment_v7* seg) {
|
|
return seg != NULL && seg->magic == SMALL_SEGMENT_V7_MAGIC;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Segment API (Cold Path)
|
|
// ============================================================================
|
|
|
|
/// Allocate a new segment for thread
|
|
/// @param owner_tid: Thread ID of owner
|
|
/// @return: Segment pointer on success, NULL on failure
|
|
SmallSegment_v7* small_segment_alloc_v7(uint32_t owner_tid);
|
|
|
|
/// Free a segment and unmap memory
|
|
/// @param seg: Segment to free
|
|
void small_segment_free_v7(SmallSegment_v7* seg);
|
|
|
|
// ============================================================================
|
|
// Page API (Cold Path - called from ColdIface)
|
|
// ============================================================================
|
|
|
|
/// Take a page from segment's free stack
|
|
/// @param seg: Segment to take page from
|
|
/// @param class_idx: Size class for the page
|
|
/// @return: Page metadata pointer on success, NULL if no free pages
|
|
SmallPageMeta_v7* small_segment_take_page_v7(SmallSegment_v7* seg, uint32_t class_idx);
|
|
|
|
/// Release a page back to segment's free stack
|
|
/// @param seg: Segment owning the page
|
|
/// @param page: Page to release
|
|
void small_segment_release_page_v7(SmallSegment_v7* seg, SmallPageMeta_v7* page);
|
|
|
|
// ============================================================================
|
|
// TLS Segment Access
|
|
// ============================================================================
|
|
|
|
/// Get or acquire TLS segment for current thread
|
|
SmallSegment_v7* small_segment_v7_get_tls(void);
|
|
|
|
/// Get page metadata for a pointer (O(1) via TLS segment)
|
|
/// @param ptr: Pointer to lookup (USER or BASE pointer)
|
|
/// @return: Page metadata if ptr is in v7 segment, NULL otherwise
|
|
SmallPageMeta_v7* small_page_meta_v7_of(void* ptr);
|
|
|
|
#endif // HAKMEM_SMALLSEGMENT_V7_BOX_H
|