Files
hakmem/core/box/carve_push_box.c
Moe Charm (CI) acc64f2438 Phase ML1: Pool v1 memset 89.73% overhead 軽量化 (+15.34% improvement)
## 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>
2025-12-10 09:08:18 +09:00

249 lines
8.9 KiB
C

// carve_push_box.c - Box Carve-And-Push Implementation
#include <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#include "../hakmem_tiny.h" // MUST BE FIRST: Base types
#include "../tiny_tls.h" // TinyTLSSlab type definition
#include "../hakmem_tiny_config.h" // TINY_NUM_CLASSES
#include "../hakmem_tiny_superslab.h" // ss_active_add(), SuperSlab
#include "../hakmem_tiny_integrity.h" // HAK_CHECK_CLASS_IDX
#include "../tiny_region_id.h" // HEADER_MAGIC, HEADER_CLASS_MASK
#include "carve_push_box.h"
#include "capacity_box.h" // box_cap_has_room()
#include "tls_sll_box.h" // tls_sll_push()
#include "tiny_next_ptr_box.h" // tiny_next_write()
#include "tiny_header_box.h" // Header Box: Single Source of Truth for header operations
#include "../tiny_refill_opt.h" // TinyRefillChain, trc_linear_carve()
#include "../tiny_box_geometry.h" // tiny_stride_for_class(), tiny_slab_base_for_geometry()
#include "c7_meta_used_counter_box.h"
// External declarations
extern __thread TinyTLSSlab g_tls_slabs[TINY_NUM_CLASSES];
extern __thread TinyTLSSLL g_tls_sll[TINY_NUM_CLASSES];
extern void ss_active_add(SuperSlab* ss, uint32_t n);
// ============================================================================
// Internal Helpers
// ============================================================================
// Rollback: return carved blocks to freelist
static __attribute__((unused)) void rollback_carved_blocks(int class_idx, TinySlabMeta* meta,
void* head, uint32_t count) {
// Walk the chain and prepend to freelist
void* node = head;
for (uint32_t i = 0; i < count && node; i++) {
void* next = tiny_next_read(class_idx, node);
// Prepend to freelist
tiny_next_write(class_idx, node, meta->freelist);
meta->freelist = node;
node = next;
}
// Rollback metadata counters
meta->carved = (uint16_t)((uint32_t)meta->carved - count);
meta->used = (uint16_t)((uint32_t)meta->used - count);
}
// ============================================================================
// Box Carve-Push API Implementation
// ============================================================================
uint32_t box_carve_and_push(int class_idx, uint32_t want) {
// PRIORITY 1: Bounds check
HAK_CHECK_CLASS_IDX(class_idx, "box_carve_and_push");
if (want == 0) return 0;
// Step 1: Check TLS SLL capacity
if (!box_cap_has_room(class_idx, want)) {
// Not enough room in TLS SLL
return 0;
}
// Step 2: Get TLS slab
TinyTLSSlab* tls = &g_tls_slabs[class_idx];
if (!tls->ss || !tls->meta) {
// No SuperSlab available
return 0;
}
TinySlabMeta* meta = tls->meta;
// Step 3: Check if slab has enough uncarved blocks
uint32_t available = (meta->capacity > meta->carved)
? (meta->capacity - meta->carved) : 0;
if (available < want) {
// Not enough uncarved blocks
// Note: Could try superslab_refill() here, but keeping it simple for now
return 0;
}
// Step 4: Get stride and slab base
size_t bs = tiny_stride_for_class(class_idx);
uint8_t* slab_base = tls->slab_base ? tls->slab_base
: tiny_slab_base_for_geometry(tls->ss, tls->slab_idx);
// Step 5: Carve blocks (builds a linked chain)
TinyRefillChain chain;
trc_linear_carve(slab_base, bs, meta, want, class_idx, &chain);
// Sanity check
if (chain.count != want) {
// Carve failed to produce expected count
// This should not happen, but handle defensively
#if !HAKMEM_BUILD_RELEASE
fprintf(stderr, "[BOX_CARVE_PUSH] WARN: carved %u blocks but expected %u\n",
chain.count, want);
#endif
// Rollback metadata (carved/used already updated by trc_linear_carve)
meta->carved = (uint16_t)((uint32_t)meta->carved - chain.count);
meta->used = (uint16_t)((uint32_t)meta->used - chain.count);
return 0;
}
// Step 6: Push all blocks to TLS SLL (with rollback on failure)
uint32_t sll_cap = box_cap_get(class_idx);
uint32_t pushed = 0;
void* node = chain.head;
for (uint32_t i = 0; i < want && node; i++) {
void* next = tiny_next_read(class_idx, node);
if (!tls_sll_push(class_idx, node, sll_cap)) {
// Push failed (SLL full or other error)
// Rollback: pop all pushed blocks and return to freelist
#if !HAKMEM_BUILD_RELEASE
fprintf(stderr, "[BOX_CARVE_PUSH] Push failed at block %u/%u, rolling back\n",
i, want);
#endif
// Pop the blocks we just pushed
uint32_t pop_failed = 0;
for (uint32_t j = 0; j < pushed; j++) {
void* popped;
if (tls_sll_pop(class_idx, &popped)) {
// Return to freelist
tiny_next_write(class_idx, popped, meta->freelist);
meta->freelist = popped;
} else {
// Pop failed - block remains orphaned in SLL!
pop_failed++;
#if !HAKMEM_BUILD_RELEASE
fprintf(stderr, "[BOX_CARVE_PUSH_ROLLBACK] Pop failed for block %u/%u (cls=%d)\n",
j, pushed, class_idx);
fprintf(stderr, "[BOX_CARVE_PUSH_ROLLBACK] Block orphaned in TLS SLL - potential double-free risk!\n");
#endif
}
}
#if !HAKMEM_BUILD_RELEASE
if (pop_failed > 0) {
fprintf(stderr, "[BOX_CARVE_PUSH_ROLLBACK] WARNING: %u/%u blocks orphaned in SLL (cls=%d)\n",
pop_failed, pushed, class_idx);
}
#endif
// Return remaining unpushed blocks to freelist
while (node) {
void* next_unpushed = tiny_next_read(class_idx, node);
tiny_next_write(class_idx, node, meta->freelist);
meta->freelist = node;
node = next_unpushed;
}
// Rollback metadata counters
meta->carved = (uint16_t)((uint32_t)meta->carved - want);
meta->used = (uint16_t)((uint32_t)meta->used - want);
return 0; // All-or-nothing: return 0 on failure
}
pushed++;
node = next;
}
// Step 7: Update active counter (all blocks successfully pushed)
ss_active_add(tls->ss, want);
return want; // Success: all blocks pushed
}
uint32_t box_carve_and_push_with_freelist(int class_idx, uint32_t want) {
// PRIORITY 1: Bounds check
HAK_CHECK_CLASS_IDX(class_idx, "box_carve_and_push_with_freelist");
if (want == 0) return 0;
// Step 1: Check capacity
if (!box_cap_has_room(class_idx, want)) {
return 0;
}
// Step 2: Get TLS slab
TinyTLSSlab* tls = &g_tls_slabs[class_idx];
if (!tls->ss || !tls->meta) {
return 0;
}
TinySlabMeta* meta = tls->meta;
uint32_t sll_cap = box_cap_get(class_idx);
uint32_t pushed = 0;
// Step 3: Try freelist first
while (pushed < want && meta->freelist) {
void* p = meta->freelist;
meta->freelist = tiny_next_read(class_idx, p);
meta->used++;
c7_meta_used_note(class_idx, C7_META_USED_SRC_FRONT);
// CRITICAL FIX: Restore header BEFORE pushing to TLS SLL
// Freelist blocks may have stale data at offset 0
// Uses Header Box API (C1-C6 only; C0/C7 skip)
tiny_header_write_if_preserved(p, class_idx);
if (!tls_sll_push(class_idx, p, sll_cap)) {
// Rollback
tiny_next_write(class_idx, p, meta->freelist);
meta->freelist = p;
meta->used--;
// Rollback all pushed
for (uint32_t j = 0; j < pushed; j++) {
void* popped;
if (tls_sll_pop(class_idx, &popped)) {
tiny_next_write(class_idx, popped, meta->freelist);
meta->freelist = popped;
meta->used--;
}
}
return 0;
}
ss_active_add(tls->ss, 1);
pushed++;
}
// Step 4: If still need more, try carving
if (pushed < want) {
uint32_t need = want - pushed;
uint32_t carved = box_carve_and_push(class_idx, need);
if (carved < need) {
// Partial failure: rollback freelist pushes
for (uint32_t j = 0; j < pushed; j++) {
void* popped;
if (tls_sll_pop(class_idx, &popped)) {
tiny_next_write(class_idx, popped, meta->freelist);
meta->freelist = popped;
meta->used--;
ss_active_add(tls->ss, -1);
}
}
return 0;
}
pushed += carved;
}
return pushed;
}