Implements header write optimization for C6 v5 allocator by moving header initialization from per-alloc time to carve time (during page refill). This eliminates redundant header writes on the hot path. Implementation: - Added HAKMEM_SMALL_HEAP_V5_HEADER_MODE ENV (full|light, default: full) - Added header_mode field to SmallHeapCtxV5 (cached per-thread) - Modified alloc fast/slow paths to skip header write in light mode - Modified refill to write headers during carve in light mode - Free path unchanged (header validation still works) Benchmark Results (2M iterations, ws=400): C6-HEAVY (257-768B): - Baseline (v5 OFF): 47.95 Mops/s - v5 full mode: 38.97 Mops/s (-18.7% vs baseline) - v5 light mode: 39.25 Mops/s (-18.1% vs baseline, +0.7% vs full) MIXED 16-1024B: - v5 OFF: 43.59 Mops/s - v5 full mode: 36.53 Mops/s (-16.2% vs OFF) - v5 light mode: 38.04 Mops/s (-12.7% vs OFF, +4.1% vs full) Analysis: - Light mode shows modest improvement over full (+0.7-4.1%) - C6 v5 performance gap vs baseline (-18%) indicates need for further optimization beyond header writes - Mixed workload benefits more from light mode (+4.1% vs full) - No regressions in safety/correctness observed Research findings: - Header write optimization alone insufficient to close v5 gap - Need to investigate other hot path costs (freelist ops, metadata access) - Light mode validates the carve-time header concept 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
141 lines
4.7 KiB
C
141 lines
4.7 KiB
C
// smallobject_v5_env_box.h - SmallObject v5 環境ゲート(Phase v5-0)
|
||
//
|
||
// ENV ベース: HAKMEM_SMALL_HEAP_V5_ENABLED, HAKMEM_SMALL_HEAP_V5_CLASSES
|
||
|
||
#ifndef HAKMEM_SMALLOBJECT_V5_ENV_BOX_H
|
||
#define HAKMEM_SMALLOBJECT_V5_ENV_BOX_H
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdint.h>
|
||
|
||
// ENV sentinel values
|
||
#define ENV_UNINIT (-1)
|
||
#define ENV_ENABLED (1)
|
||
#define ENV_DISABLED (0)
|
||
|
||
// route priority enum
|
||
enum small_route_priority {
|
||
ROUTE_PRIORITY_V4 = 0,
|
||
ROUTE_PRIORITY_V5 = 1,
|
||
ROUTE_PRIORITY_AUTO = 2,
|
||
};
|
||
|
||
// small_heap_v5_enabled() - グローバル v5 enable check
|
||
static inline int small_heap_v5_enabled(void) {
|
||
static int g_enabled = ENV_UNINIT;
|
||
if (__builtin_expect(g_enabled == ENV_UNINIT, 0)) {
|
||
const char* e = getenv("HAKMEM_SMALL_HEAP_V5_ENABLED");
|
||
g_enabled = (e && *e && *e != '0') ? ENV_ENABLED : ENV_DISABLED;
|
||
}
|
||
return (g_enabled == ENV_ENABLED);
|
||
}
|
||
|
||
// small_heap_v5_class_mask() - v5 対象クラスのビットマスク
|
||
static inline uint32_t small_heap_v5_class_mask(void) {
|
||
static int g_mask = ENV_UNINIT; // sentinel
|
||
if (__builtin_expect(g_mask == ENV_UNINIT, 0)) {
|
||
const char* e = getenv("HAKMEM_SMALL_HEAP_V5_CLASSES");
|
||
if (e && *e) {
|
||
g_mask = (int)strtoul(e, NULL, 0);
|
||
} else {
|
||
g_mask = 0x0; // default: OFF
|
||
}
|
||
}
|
||
return (uint32_t)g_mask;
|
||
}
|
||
|
||
// small_heap_v5_class_enabled() - 指定クラスが v5 有効か
|
||
static inline int small_heap_v5_class_enabled(uint32_t class_idx) {
|
||
if (class_idx >= 8) return 0;
|
||
if (!small_heap_v5_enabled()) return 0;
|
||
uint32_t mask = small_heap_v5_class_mask();
|
||
return (mask & (1u << class_idx)) ? 1 : 0;
|
||
}
|
||
|
||
// 便利関数
|
||
static inline int small_heap_v5_c6_enabled(void) {
|
||
return small_heap_v5_class_enabled(6);
|
||
}
|
||
|
||
static inline int small_heap_v5_c5_enabled(void) {
|
||
return small_heap_v5_class_enabled(5);
|
||
}
|
||
|
||
static inline int small_heap_v5_c7_enabled(void) {
|
||
return small_heap_v5_class_enabled(7);
|
||
}
|
||
|
||
// small_route_priority() - route priority (v4/v5/auto)
|
||
// ENV: HAKMEM_ROUTE_PRIORITY={v4|v5|auto}, default: v4
|
||
static inline int small_route_priority(void) {
|
||
static int g_priority = ENV_UNINIT;
|
||
if (__builtin_expect(g_priority == ENV_UNINIT, 0)) {
|
||
const char* e = getenv("HAKMEM_ROUTE_PRIORITY");
|
||
if (e && *e) {
|
||
if (strcmp(e, "v5") == 0) {
|
||
g_priority = ROUTE_PRIORITY_V5;
|
||
} else if (strcmp(e, "auto") == 0) {
|
||
g_priority = ROUTE_PRIORITY_AUTO;
|
||
} else {
|
||
g_priority = ROUTE_PRIORITY_V4; // default or "v4"
|
||
}
|
||
} else {
|
||
g_priority = ROUTE_PRIORITY_V4; // default
|
||
}
|
||
}
|
||
return g_priority;
|
||
}
|
||
|
||
// small_heap_v5_segment_size() - segment size override
|
||
// ENV: HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE, default: 2MiB (2*1024*1024)
|
||
static inline size_t small_heap_v5_segment_size(void) {
|
||
static int g_size = ENV_UNINIT;
|
||
if (__builtin_expect(g_size == ENV_UNINIT, 0)) {
|
||
const char* e = getenv("HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE");
|
||
if (e && *e) {
|
||
size_t sz = (size_t)strtoul(e, NULL, 0);
|
||
// validate: must be power of 2, >= 64KiB
|
||
if (sz >= (64 * 1024) && (sz & (sz - 1)) == 0) {
|
||
g_size = (int)sz;
|
||
} else {
|
||
g_size = (2 * 1024 * 1024); // fallback to default
|
||
}
|
||
} else {
|
||
g_size = (2 * 1024 * 1024); // default: 2MiB
|
||
}
|
||
}
|
||
return (size_t)g_size;
|
||
}
|
||
|
||
// ============================================================================
|
||
// Phase v5-4: Header mode configuration
|
||
// ============================================================================
|
||
|
||
// Header mode enum
|
||
#define SMALL_HEAP_V5_HEADER_MODE_FULL 0
|
||
#define SMALL_HEAP_V5_HEADER_MODE_LIGHT 1
|
||
|
||
// small_heap_v5_header_mode() - header write mode (default: full)
|
||
// ENV: HAKMEM_SMALL_HEAP_V5_HEADER_MODE={full|light}, default: full
|
||
// - full: write header on every alloc (safe, standard)
|
||
// - light: write header once during carve, skip on alloc (research mode, +2-4% perf)
|
||
static inline int small_heap_v5_header_mode(void) {
|
||
static int g_header_mode = ENV_UNINIT;
|
||
if (__builtin_expect(g_header_mode == ENV_UNINIT, 0)) {
|
||
const char* e = getenv("HAKMEM_SMALL_HEAP_V5_HEADER_MODE");
|
||
if (e && *e) {
|
||
if (strcmp(e, "light") == 0 || strcmp(e, "LIGHT") == 0 || *e == '1') {
|
||
g_header_mode = SMALL_HEAP_V5_HEADER_MODE_LIGHT;
|
||
} else {
|
||
g_header_mode = SMALL_HEAP_V5_HEADER_MODE_FULL; // default or "full"
|
||
}
|
||
} else {
|
||
g_header_mode = SMALL_HEAP_V5_HEADER_MODE_FULL; // default: full
|
||
}
|
||
}
|
||
return g_header_mode;
|
||
}
|
||
|
||
#endif // HAKMEM_SMALLOBJECT_V5_ENV_BOX_H
|