## Summary - ChatGPT により bench_profile.h の setenv segfault を修正(RTLD_NEXT 経由に切り替え) - core/box/pool_zero_mode_box.h 新設:ENV キャッシュ経由で ZERO_MODE を統一管理 - core/hakmem_pool.c で zero mode に応じた memset 制御(FULL/header/off) - A/B テスト結果:ZERO_MODE=header で +15.34% improvement(1M iterations, C6-heavy) ## Files Modified - core/box/pool_api.inc.h: pool_zero_mode_box.h include - core/bench_profile.h: glibc setenv → malloc+putenv(segfault 回避) - core/hakmem_pool.c: zero mode 参照・制御ロジック - core/box/pool_zero_mode_box.h (新設): enum/getter - CURRENT_TASK.md: Phase ML1 結果記載 ## Test Results | Iterations | ZERO_MODE=full | ZERO_MODE=header | Improvement | |-----------|----------------|-----------------|------------| | 10K | 3.06 M ops/s | 3.17 M ops/s | +3.65% | | 1M | 23.71 M ops/s | 27.34 M ops/s | **+15.34%** | 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
263 lines
7.4 KiB
C
263 lines
7.4 KiB
C
// ss_addr_map_box.c - Phase 9-1: SuperSlab Address Map Implementation
|
|
// Purpose: O(1) hash table for address → SuperSlab* mapping
|
|
|
|
#include "ss_addr_map_box.h"
|
|
#include "../hakmem_tiny_superslab.h"
|
|
#include "../hakmem_tiny_superslab_constants.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// ============================================================================
|
|
// Global Instance
|
|
// ============================================================================
|
|
|
|
SSAddrMap g_ss_addr_map = {0};
|
|
|
|
// ============================================================================
|
|
// Internal Helpers
|
|
// ============================================================================
|
|
|
|
// Allocate entry (use libc to avoid recursion)
|
|
static SSMapEntry* alloc_entry(void) {
|
|
extern void* __libc_malloc(size_t);
|
|
return (SSMapEntry*)__libc_malloc(sizeof(SSMapEntry));
|
|
}
|
|
|
|
// Free entry (use libc to match allocation)
|
|
static void free_entry(SSMapEntry* entry) {
|
|
extern void __libc_free(void*);
|
|
__libc_free(entry);
|
|
}
|
|
|
|
// Get SuperSlab base address from any pointer within it
|
|
// Strategy: Mask lower bits based on SuperSlab size
|
|
// Note: SuperSlab can be 512KB, 1MB, or 2MB
|
|
// Solution: Try each alignment until we find a valid SuperSlab
|
|
static __attribute__((unused)) void* get_superslab_base(void* ptr, struct SuperSlab* ss) {
|
|
// SuperSlab stores its own size in header
|
|
// For now, use conservative approach: align to minimum size (512KB)
|
|
// Phase 9-1-2: Optimize with actual size from SuperSlab header
|
|
uintptr_t addr = (uintptr_t)ptr;
|
|
uintptr_t mask = ~((1UL << SUPERSLAB_LG_MIN) - 1); // 512KB mask
|
|
(void)ss;
|
|
return (void*)(addr & mask);
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Implementation
|
|
// ============================================================================
|
|
|
|
void ss_map_init(SSAddrMap* map) {
|
|
memset(map, 0, sizeof(SSAddrMap));
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
if (getenv("HAKMEM_SS_MAP_TRACE")) {
|
|
fprintf(stderr, "[SS_MAP_INIT] Initialized with %d buckets\n", SS_MAP_HASH_SIZE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ss_map_insert(SSAddrMap* map, void* base, struct SuperSlab* ss) {
|
|
if (!map || !base || !ss) {
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
fprintf(stderr, "[SS_MAP_INSERT] ERROR: NULL parameter (map=%p base=%p ss=%p)\n",
|
|
(void*)map, base, (void*)ss);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// Hash to bucket
|
|
size_t bucket_idx = ss_map_hash(base);
|
|
|
|
// Check for duplicate (should not happen, but defensive)
|
|
SSMapEntry* entry = map->buckets[bucket_idx];
|
|
while (entry) {
|
|
if (entry->base == base) {
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
fprintf(stderr, "[SS_MAP_INSERT] WARNING: Duplicate base=%p (overwriting)\n", base);
|
|
#endif
|
|
entry->ss = ss;
|
|
return;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
|
|
// Allocate new entry
|
|
SSMapEntry* new_entry = alloc_entry();
|
|
if (!new_entry) {
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
fprintf(stderr, "[SS_MAP_INSERT] ERROR: Failed to allocate entry\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// Initialize entry
|
|
new_entry->base = base;
|
|
new_entry->ss = ss;
|
|
new_entry->next = map->buckets[bucket_idx];
|
|
|
|
// Insert at head of chain
|
|
map->buckets[bucket_idx] = new_entry;
|
|
map->count++;
|
|
|
|
// Track collisions (for statistics)
|
|
if (new_entry->next != NULL) {
|
|
map->collisions++;
|
|
}
|
|
}
|
|
|
|
struct SuperSlab* ss_map_lookup(SSAddrMap* map, void* ptr) {
|
|
if (!map || !ptr) {
|
|
return NULL;
|
|
}
|
|
|
|
// Try each possible SuperSlab alignment (512KB, 1MB, 2MB)
|
|
// Start with most common (512KB)
|
|
for (int lg = SUPERSLAB_LG_MIN; lg <= SUPERSLAB_LG_MAX; lg++) {
|
|
uintptr_t addr = (uintptr_t)ptr;
|
|
uintptr_t mask = ~((1UL << lg) - 1);
|
|
void* base = (void*)(addr & mask);
|
|
|
|
// Hash to bucket
|
|
size_t bucket_idx = ss_map_hash(base);
|
|
|
|
// Search chain
|
|
SSMapEntry* entry = map->buckets[bucket_idx];
|
|
while (entry) {
|
|
if (entry->base == base) {
|
|
// Found! Verify pointer is within SuperSlab range
|
|
// Phase 9-1-2: Add range check for safety
|
|
return entry->ss;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
}
|
|
|
|
// Not found
|
|
return NULL;
|
|
}
|
|
|
|
void ss_map_remove(SSAddrMap* map, void* base) {
|
|
if (!map || !base) {
|
|
return;
|
|
}
|
|
|
|
// Hash to bucket
|
|
size_t bucket_idx = ss_map_hash(base);
|
|
|
|
// Search and remove
|
|
SSMapEntry** prev_next = &map->buckets[bucket_idx];
|
|
SSMapEntry* entry = map->buckets[bucket_idx];
|
|
|
|
while (entry) {
|
|
if (entry->base == base) {
|
|
// Found - remove from chain
|
|
*prev_next = entry->next;
|
|
map->count--;
|
|
|
|
// Free entry
|
|
free_entry(entry);
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
if (getenv("HAKMEM_SS_MAP_TRACE")) {
|
|
fprintf(stderr, "[SS_MAP_REMOVE] Removed base=%p\n", base);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
prev_next = &entry->next;
|
|
entry = entry->next;
|
|
}
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
fprintf(stderr, "[SS_MAP_REMOVE] WARNING: base=%p not found\n", base);
|
|
#endif
|
|
}
|
|
|
|
void ss_map_shutdown(SSAddrMap* map) {
|
|
if (!map) {
|
|
return;
|
|
}
|
|
|
|
// Free all entries
|
|
for (size_t i = 0; i < SS_MAP_HASH_SIZE; i++) {
|
|
SSMapEntry* entry = map->buckets[i];
|
|
while (entry) {
|
|
SSMapEntry* next = entry->next;
|
|
free_entry(entry);
|
|
entry = next;
|
|
}
|
|
map->buckets[i] = NULL;
|
|
}
|
|
|
|
map->count = 0;
|
|
map->collisions = 0;
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
if (getenv("HAKMEM_SS_MAP_TRACE")) {
|
|
fprintf(stderr, "[SS_MAP_SHUTDOWN] All entries freed\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ============================================================================
|
|
// Statistics (Debug builds only)
|
|
// ============================================================================
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
void ss_map_print_stats(SSAddrMap* map) {
|
|
if (!map) {
|
|
return;
|
|
}
|
|
|
|
fprintf(stderr, "\n[SS_MAP_STATS] SuperSlab Address Map Statistics:\n");
|
|
fprintf(stderr, " Total entries: %zu\n", map->count);
|
|
fprintf(stderr, " Hash buckets: %d\n", SS_MAP_HASH_SIZE);
|
|
fprintf(stderr, " Collisions: %zu\n", map->collisions);
|
|
|
|
if (map->count > 0) {
|
|
double load_factor = (double)map->count / SS_MAP_HASH_SIZE;
|
|
double collision_rate = (double)map->collisions / map->count;
|
|
|
|
fprintf(stderr, " Load factor: %.2f\n", load_factor);
|
|
fprintf(stderr, " Collision rate: %.1f%%\n", collision_rate * 100.0);
|
|
|
|
// Find longest chain
|
|
size_t max_chain = 0;
|
|
size_t empty_buckets = 0;
|
|
|
|
for (size_t i = 0; i < SS_MAP_HASH_SIZE; i++) {
|
|
size_t chain_len = 0;
|
|
SSMapEntry* entry = map->buckets[i];
|
|
|
|
if (!entry) {
|
|
empty_buckets++;
|
|
}
|
|
|
|
while (entry) {
|
|
chain_len++;
|
|
entry = entry->next;
|
|
}
|
|
|
|
if (chain_len > max_chain) {
|
|
max_chain = chain_len;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, " Longest chain: %zu\n", max_chain);
|
|
fprintf(stderr, " Empty buckets: %zu (%.1f%%)\n",
|
|
empty_buckets,
|
|
(double)empty_buckets / SS_MAP_HASH_SIZE * 100.0);
|
|
}
|
|
}
|
|
|
|
double ss_map_collision_rate(SSAddrMap* map) {
|
|
if (!map || map->count == 0) {
|
|
return 0.0;
|
|
}
|
|
return (double)map->collisions / map->count;
|
|
}
|
|
#endif
|