**問題:**
- Larson 4T で 100% SEGV (1T は 2.09M ops/s で完走)
- System/mimalloc は 4T で 33.52M ops/s 正常動作
- SS OFF + Remote OFF でも 4T で SEGV
**根本原因: (Task agent ultrathink 調査結果)**
```
CRASH: mov (%r15),%r13
R15 = 0x6261 ← ASCII "ba" (ゴミ値、未初期化TLS)
```
Worker スレッドの TLS 変数が未初期化:
- `__thread void* g_tls_sll_head[TINY_NUM_CLASSES];` ← 初期化なし
- pthread_create() で生成されたスレッドでゼロ初期化されない
- NULL チェックが通過 (0x6261 != NULL) → dereference → SEGV
**修正内容:**
全 TLS 配列に明示的初期化子 `= {0}` を追加:
1. **core/hakmem_tiny.c:**
- `g_tls_sll_head[TINY_NUM_CLASSES] = {0}`
- `g_tls_sll_count[TINY_NUM_CLASSES] = {0}`
- `g_tls_live_ss[TINY_NUM_CLASSES] = {0}`
- `g_tls_bcur[TINY_NUM_CLASSES] = {0}`
- `g_tls_bend[TINY_NUM_CLASSES] = {0}`
2. **core/tiny_fastcache.c:**
- `g_tiny_fast_cache[TINY_FAST_CLASS_COUNT] = {0}`
- `g_tiny_fast_count[TINY_FAST_CLASS_COUNT] = {0}`
- `g_tiny_fast_free_head[TINY_FAST_CLASS_COUNT] = {0}`
- `g_tiny_fast_free_count[TINY_FAST_CLASS_COUNT] = {0}`
3. **core/hakmem_tiny_magazine.c:**
- `g_tls_mags[TINY_NUM_CLASSES] = {0}`
4. **core/tiny_sticky.c:**
- `g_tls_sticky_ss[TINY_NUM_CLASSES][TINY_STICKY_RING] = {0}`
- `g_tls_sticky_idx[TINY_NUM_CLASSES][TINY_STICKY_RING] = {0}`
- `g_tls_sticky_pos[TINY_NUM_CLASSES] = {0}`
**効果:**
```
Before: 1T: 2.09M ✅ | 4T: SEGV 💀
After: 1T: 2.41M ✅ | 4T: 4.19M ✅ (+15% 1T, SEGV解消)
```
**テスト:**
```bash
# 1 thread: 完走
./larson_hakmem 2 8 128 1024 1 12345 1
→ Throughput = 2,407,597 ops/s ✅
# 4 threads: 完走(以前は SEGV)
./larson_hakmem 2 8 128 1024 1 12345 4
→ Throughput = 4,192,155 ops/s ✅
```
**調査協力:** Task agent (ultrathink mode) による完璧な根本原因特定
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
119 lines
5.0 KiB
C
119 lines
5.0 KiB
C
// hak_free_api.inc.h — Box: hak_free_at() implementation
|
||
#ifndef HAK_FREE_API_INC_H
|
||
#define HAK_FREE_API_INC_H
|
||
|
||
// Optional route trace: print first N classification lines when enabled by env
|
||
static inline int hak_free_route_trace_on(void) {
|
||
static int g_trace = -1;
|
||
if (__builtin_expect(g_trace == -1, 0)) {
|
||
const char* e = getenv("HAKMEM_FREE_ROUTE_TRACE");
|
||
g_trace = (e && *e && *e != '0') ? 1 : 0;
|
||
}
|
||
return g_trace;
|
||
}
|
||
static inline int* hak_free_route_budget_ptr(void) {
|
||
static int g_budget = 32; // first 32 frees only
|
||
return &g_budget;
|
||
}
|
||
static inline void hak_free_route_log(const char* tag, void* p) {
|
||
if (!hak_free_route_trace_on()) return;
|
||
int* budget = hak_free_route_budget_ptr();
|
||
if (*budget <= 0) return;
|
||
(*budget)--;
|
||
fprintf(stderr, "[FREE_ROUTE] %s ptr=%p\n", tag, p);
|
||
}
|
||
|
||
#ifndef HAKMEM_TINY_PHASE6_BOX_REFACTOR
|
||
__attribute__((always_inline))
|
||
inline
|
||
#endif
|
||
void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||
#if HAKMEM_DEBUG_TIMING
|
||
HKM_TIME_START(t0);
|
||
#endif
|
||
(void)site; (void)size;
|
||
if (!ptr) {
|
||
#if HAKMEM_DEBUG_TIMING
|
||
HKM_TIME_END(HKM_CAT_HAK_FREE, t0);
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
// SS-first free(既定ON)
|
||
{
|
||
static int s_free_to_ss = -2;
|
||
if (s_free_to_ss == -2) {
|
||
const char* e = getenv("HAKMEM_TINY_FREE_TO_SS");
|
||
s_free_to_ss = (e && *e) ? ((*e!='0')?1:0) : 1;
|
||
}
|
||
if (s_free_to_ss) {
|
||
extern int g_use_superslab;
|
||
if (__builtin_expect(g_use_superslab != 0, 1)) {
|
||
SuperSlab* ss = hak_super_lookup(ptr);
|
||
if (ss && ss->magic == SUPERSLAB_MAGIC) {
|
||
int sidx = slab_index_for(ss, ptr);
|
||
int cap = ss_slabs_capacity(ss);
|
||
if (__builtin_expect(sidx >= 0 && sidx < cap, 1)) { hak_free_route_log("ss_hit", ptr); hak_tiny_free(ptr); goto done; }
|
||
}
|
||
for (int lg=21; lg>=20; lg--) {
|
||
uintptr_t mask=((uintptr_t)1<<lg)-1; SuperSlab* guess=(SuperSlab*)((uintptr_t)ptr & ~mask);
|
||
if (guess && guess->magic==SUPERSLAB_MAGIC) { int sidx=slab_index_for(guess,ptr); int cap=ss_slabs_capacity(guess); if (sidx>=0&&sidx<cap){ hak_free_route_log("ss_guess", ptr); hak_tiny_free(ptr); goto done; }}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Mid/L25 headerless経路
|
||
{
|
||
extern int hak_pool_mid_lookup(void* ptr, size_t* out_size);
|
||
extern void hak_pool_free_fast(void* ptr, uintptr_t site_id);
|
||
size_t mid_sz = 0; if (hak_pool_mid_lookup(ptr, &mid_sz)) { hak_free_route_log("mid_hit", ptr); hak_pool_free_fast(ptr, (uintptr_t)site); goto done; }
|
||
}
|
||
{
|
||
extern int hak_l25_lookup(void* ptr, size_t* out_size);
|
||
extern void hak_l25_pool_free_fast(void* ptr, uintptr_t site_id);
|
||
size_t l25_sz = 0; if (hak_l25_lookup(ptr, &l25_sz)) { hak_free_route_log("l25_hit", ptr); hkm_ace_stat_large_free(); hak_l25_pool_free_fast(ptr, (uintptr_t)site); goto done; }
|
||
}
|
||
|
||
// Raw header dispatch(mmap/malloc/BigCacheなど)
|
||
{
|
||
void* raw = (char*)ptr - HEADER_SIZE;
|
||
AllocHeader* hdr = (AllocHeader*)raw;
|
||
if (hdr->magic != HAKMEM_MAGIC) {
|
||
if (g_invalid_free_log) fprintf(stderr, "[hakmem] ERROR: Invalid magic 0x%X (expected 0x%X)\n", hdr->magic, HAKMEM_MAGIC);
|
||
if (g_invalid_free_mode) { goto done; } else { extern void __libc_free(void*); __libc_free(ptr); goto done; }
|
||
}
|
||
if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->class_bytes >= 2097152) {
|
||
if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done;
|
||
}
|
||
{
|
||
static int g_bc_l25_en_free = -1; if (g_bc_l25_en_free == -1) { const char* e = getenv("HAKMEM_BIGCACHE_L25"); g_bc_l25_en_free = (e && atoi(e) != 0) ? 1 : 0; }
|
||
if (g_bc_l25_en_free && HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->size >= 524288 && hdr->size < 2097152) {
|
||
if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done;
|
||
}
|
||
}
|
||
switch (hdr->method) {
|
||
case ALLOC_METHOD_POOL: if (HAK_ENABLED_ALLOC(HAKMEM_FEATURE_POOL)) { hkm_ace_stat_mid_free(); hak_pool_free(ptr, hdr->size, hdr->alloc_site); goto done; } break;
|
||
case ALLOC_METHOD_L25_POOL: hkm_ace_stat_large_free(); hak_l25_pool_free(ptr, hdr->size, hdr->alloc_site); goto done;
|
||
case ALLOC_METHOD_MALLOC: hak_free_route_log("malloc_hdr", ptr); free(raw); break;
|
||
case ALLOC_METHOD_MMAP:
|
||
#ifdef __linux__
|
||
if (HAK_ENABLED_MEMORY(HAKMEM_FEATURE_BATCH_MADVISE) && hdr->size >= BATCH_MIN_SIZE) { hak_batch_add(raw, hdr->size); goto done; }
|
||
if (hkm_whale_put(raw, hdr->size) != 0) { hkm_sys_munmap(raw, hdr->size); }
|
||
#else
|
||
free(raw);
|
||
#endif
|
||
break;
|
||
default: fprintf(stderr, "[hakmem] ERROR: Unknown allocation method: %d\n", hdr->method); break;
|
||
}
|
||
}
|
||
|
||
done:
|
||
#if HAKMEM_DEBUG_TIMING
|
||
HKM_TIME_END(HKM_CAT_HAK_FREE, t0);
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
#endif // HAK_FREE_API_INC_H
|