Following the C7 stride upgrade fix (commit 23c0d9541), this commit performs
comprehensive cleanup to improve code quality and reduce debug noise.
## Changes
### 1. Disable False Positive Checks (tiny_nextptr.h)
- **Disabled**: NXT_MISALIGN validation block with `#if 0`
- **Reason**: Produces false positives due to slab base offsets (2048, 65536)
not being stride-aligned, causing all blocks to appear "misaligned"
- **TODO**: Reimplement to check stride DISTANCE between consecutive blocks
instead of absolute alignment to stride boundaries
### 2. Remove Redundant Geometry Validations
**hakmem_tiny_refill_p0.inc.h (P0 batch refill)**
- Removed 25-line CARVE_GEOMETRY_FIX validation block
- Replaced with NOTE explaining redundancy
- **Reason**: Stride table is now correct in tiny_block_stride_for_class(),
defense-in-depth validation adds overhead without benefit
**ss_legacy_backend_box.c (legacy backend)**
- Removed 18-line LEGACY_FIX_GEOMETRY validation block
- Replaced with NOTE explaining redundancy
- **Reason**: Shared_pool validates geometry at acquisition time
### 3. Reduce Verbose Logging
**hakmem_shared_pool.c (sp_fix_geometry_if_needed)**
- Made SP_FIX_GEOMETRY logging conditional on `!HAKMEM_BUILD_RELEASE`
- **Reason**: Geometry fixes are expected during stride upgrades,
no need to log in release builds
### 4. Verification
- Build: ✅ Successful (LTO warnings expected)
- Test: ✅ 10K iterations (1.87M ops/s, no crashes)
- NXT_MISALIGN false positives: ✅ Eliminated
## Files Modified
- core/tiny_nextptr.h - Disabled false positive NXT_MISALIGN check
- core/hakmem_tiny_refill_p0.inc.h - Removed redundant CARVE validation
- core/box/ss_legacy_backend_box.c - Removed redundant LEGACY validation
- core/hakmem_shared_pool.c - Made SP_FIX_GEOMETRY logging debug-only
## Impact
- **Code clarity**: Removed 43 lines of redundant validation code
- **Debug noise**: Reduced false positive diagnostics
- **Performance**: Eliminated overhead from redundant geometry checks
- **Maintainability**: Single source of truth for geometry validation
🧹 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
142 lines
5.2 KiB
C
142 lines
5.2 KiB
C
// tiny_heap_v2.h - Tiny per-thread heap (Front-V2, tcache-like)
|
||
// Goal:
|
||
// - 1 レイヤの TLS magazine を前段に置き、FastCache/SFC 等をバイパス。
|
||
// - ENV で A/B 切り替え可能(デフォルト OFF)。戻しやすく安全に。
|
||
// - 対象は C0–C3 のみ。Magazine が空なら SLL→SS 経由で補充。
|
||
|
||
#ifndef HAK_FRONT_TINY_HEAP_V2_H
|
||
#define HAK_FRONT_TINY_HEAP_V2_H
|
||
|
||
#include "../hakmem_tiny.h"
|
||
#include "../box/tls_sll_box.h"
|
||
#include <stdlib.h>
|
||
|
||
// Phase 13-B: Magazine capacity (same as Phase 13-A)
|
||
#ifndef TINY_HEAP_V2_MAG_CAP
|
||
#define TINY_HEAP_V2_MAG_CAP 16
|
||
#endif
|
||
|
||
// TinyHeapV2 Magazine (per-thread, per-class)
|
||
typedef struct {
|
||
void* items[TINY_HEAP_V2_MAG_CAP];
|
||
int top;
|
||
} TinyHeapV2Mag;
|
||
|
||
// TinyHeapV2 Statistics (per-thread, per-class)
|
||
typedef struct {
|
||
uint64_t alloc_calls;
|
||
uint64_t mag_hits;
|
||
uint64_t refill_calls;
|
||
uint64_t refill_blocks;
|
||
uint64_t backend_oom;
|
||
} TinyHeapV2Stats;
|
||
|
||
// External TLS variables (defined in hakmem_tiny.c)
|
||
extern __thread TinyHeapV2Mag g_tiny_heap_v2_mag[TINY_NUM_CLASSES];
|
||
extern __thread TinyHeapV2Stats g_tiny_heap_v2_stats[TINY_NUM_CLASSES];
|
||
|
||
// Enable flag (cached)
|
||
// ENV: HAKMEM_TINY_FRONT_V2
|
||
// - 0 (default): OFF
|
||
// - 1: ON (Front-V2 有効化、FastCache/SFC を経由せず magazine を先頭に)
|
||
static inline int tiny_heap_v2_enabled(void) {
|
||
static int g_enable = -1;
|
||
if (__builtin_expect(g_enable == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_FRONT_V2");
|
||
g_enable = (e && *e && *e != '0') ? 1 : 0;
|
||
}
|
||
return g_enable;
|
||
}
|
||
|
||
// Class-specific enable mask (cached)
|
||
// ENV: HAKMEM_TINY_HEAP_V2_CLASS_MASK (bitmask: bit 0=C0, bit 1=C1, bit 2=C2, bit 3=C3)
|
||
// Default: 0xE (C1-C3 only, skip C0 8B due to -5% regression)
|
||
// Example: 0x2 = C1 only, 0x8 = C3 only, 0x6 = C1+C2, 0xF = all C0-C3
|
||
static inline int tiny_heap_v2_class_enabled(int class_idx) {
|
||
static int g_class_mask = -1;
|
||
if (__builtin_expect(g_class_mask == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_HEAP_V2_CLASS_MASK");
|
||
if (e && *e) {
|
||
// Parse hex or decimal
|
||
char* endptr;
|
||
long val = strtol(e, &endptr, 0); // 0 = auto-detect base (0x for hex, else decimal)
|
||
g_class_mask = (int)val;
|
||
} else {
|
||
g_class_mask = 0xE; // Default: C1-C3 (16/32/64B), skip C0 8B (-5% regression)
|
||
}
|
||
}
|
||
|
||
if (class_idx < 0 || class_idx >= 8) return 0;
|
||
return (g_class_mask & (1 << class_idx)) != 0;
|
||
}
|
||
|
||
// Leftover mode flag (cached)
|
||
// ENV: HAKMEM_TINY_HEAP_V2_LEFTOVER_MODE
|
||
// - 0 (default): L0 gets blocks first ("stealing" design, +18% @ 32B)
|
||
// - 1: L1 primary owner, L0 gets leftovers ("leftover" design, Box-clean but -5% @ 16B)
|
||
//
|
||
// Decision (Phase 13-B): Default to Mode 0 (Stealing) for performance
|
||
// Rationale (ChatGPT analysis):
|
||
// - Learning layer primarily observes Superslab/Pool statistics
|
||
// - L0 stealing doesn't corrupt Superslab carving/drain signals
|
||
// - If needed, add TinyHeapV2 hit/miss counters to learning layer later
|
||
// - Performance gain (+18% @ 32B) justifies less-strict Box boundary
|
||
static inline int tiny_heap_v2_leftover_mode(void) {
|
||
static int g_leftover_mode = -1;
|
||
if (__builtin_expect(g_leftover_mode == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_TINY_HEAP_V2_LEFTOVER_MODE");
|
||
g_leftover_mode = (e && *e && *e != '0') ? 1 : 0;
|
||
}
|
||
return g_leftover_mode;
|
||
}
|
||
|
||
// NOTE: This header MUST be included AFTER tiny_alloc_fast.inc.h!
|
||
// It uses fastcache_pop, tiny_alloc_fast_refill, hak_tiny_size_to_class which are
|
||
// static inline functions defined in tiny_alloc_fast.inc.h and related headers.
|
||
|
||
// Phase 13-A Step 2: Try to push a block into TinyHeapV2 magazine
|
||
// Called from free path to supply magazine with "leftover" blocks.
|
||
// Returns: 1 if pushed successfully, 0 if magazine is full
|
||
static inline int tiny_heap_v2_try_push(int class_idx, void* base) {
|
||
// 1. Check if class is enabled
|
||
if (class_idx < 0 || class_idx > 3) return 0;
|
||
if (!tiny_heap_v2_enabled()) return 0;
|
||
if (!tiny_heap_v2_class_enabled(class_idx)) return 0;
|
||
|
||
TinyHeapV2Mag* mag = &g_tiny_heap_v2_mag[class_idx];
|
||
|
||
// 2. Check if magazine has room
|
||
if (mag->top >= TINY_HEAP_V2_MAG_CAP) {
|
||
return 0; // Magazine full
|
||
}
|
||
|
||
// 3. Push BASE pointer into magazine
|
||
mag->items[mag->top++] = base;
|
||
|
||
// DEBUG: Log push events
|
||
static int g_push_dbg = -1;
|
||
if (g_push_dbg == -1) {
|
||
const char* e = getenv("HAKMEM_TINY_HEAP_V2_DEBUG");
|
||
g_push_dbg = (e && *e && *e != '0') ? 1 : 0;
|
||
}
|
||
if (g_push_dbg) {
|
||
static __thread int g_push_count[TINY_NUM_CLASSES] = {0};
|
||
if (g_push_count[class_idx] < 5) {
|
||
fprintf(stderr, "[HeapV2-PUSH] C%d push #%d, base=%p, mag->top=%d\n",
|
||
class_idx, g_push_count[class_idx]++, base, mag->top);
|
||
}
|
||
}
|
||
|
||
return 1; // Success
|
||
}
|
||
|
||
// Forward declaration: refill + alloc helper (implemented inline where included)
|
||
static inline int tiny_heap_v2_refill_mag(int class_idx);
|
||
static inline void* tiny_heap_v2_alloc_by_class(int class_idx);
|
||
static inline int tiny_heap_v2_stats_enabled(void);
|
||
|
||
// Print statistics (called at program exit if HAKMEM_TINY_HEAP_V2_STATS=1, impl in hakmem_tiny.c)
|
||
void tiny_heap_v2_print_stats(void);
|
||
|
||
#endif // HAK_FRONT_TINY_HEAP_V2_H
|