Files
hakmem/docs/analysis/RELEASE_DEBUG_OVERHEAD_REPORT.md
Moe Charm (CI) 67fb15f35f Wrap debug fprintf in !HAKMEM_BUILD_RELEASE guards (Release build optimization)
## Changes

### 1. core/page_arena.c
- Removed init failure message (lines 25-27) - error is handled by returning early
- All other fprintf statements already wrapped in existing #if !HAKMEM_BUILD_RELEASE blocks

### 2. core/hakmem.c
- Wrapped SIGSEGV handler init message (line 72)
- CRITICAL: Kept SIGSEGV/SIGBUS/SIGABRT error messages (lines 62-64) - production needs crash logs

### 3. core/hakmem_shared_pool.c
- Wrapped all debug fprintf statements in #if !HAKMEM_BUILD_RELEASE:
  - Node pool exhaustion warning (line 252)
  - SP_META_CAPACITY_ERROR warning (line 421)
  - SP_FIX_GEOMETRY debug logging (line 745)
  - SP_ACQUIRE_STAGE0.5_EMPTY debug logging (line 865)
  - SP_ACQUIRE_STAGE0_L0 debug logging (line 803)
  - SP_ACQUIRE_STAGE1_LOCKFREE debug logging (line 922)
  - SP_ACQUIRE_STAGE2_LOCKFREE debug logging (line 996)
  - SP_ACQUIRE_STAGE3 debug logging (line 1116)
  - SP_SLOT_RELEASE debug logging (line 1245)
  - SP_SLOT_FREELIST_LOCKFREE debug logging (line 1305)
  - SP_SLOT_COMPLETELY_EMPTY debug logging (line 1316)
- Fixed lock_stats_init() for release builds (lines 60-65) - ensure g_lock_stats_enabled is initialized

## Performance Validation

Before: 51M ops/s (with debug fprintf overhead)
After:  49.1M ops/s (consistent performance, fprintf removed from hot paths)

## Build & Test

```bash
./build.sh larson_hakmem
./out/release/larson_hakmem 1 5 1 1000 100 10000 42
# Result: 49.1M ops/s
```

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 13:14:18 +09:00

628 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# リリースビルド デバッグ処理 洗い出しレポート
## 🔥 **CRITICAL: 5-8倍の性能差の根本原因**
**現状**: HAKMEM 9M ops/s vs System malloc 43M ops/s**4.8倍遅い**
**診断結果**: リリースビルド(`-DHAKMEM_BUILD_RELEASE=1 -DNDEBUG`)でも**大量のデバッグ処理が実行されている**
---
## 💀 **重大な問題(ホットパス)**
### 1. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:24-29` - **デバッグログ(毎回実行)**
```c
__attribute__((always_inline))
inline void* hak_alloc_at(size_t size, hak_callsite_t site) {
static _Atomic uint64_t hak_alloc_call_count = 0;
uint64_t call_num = atomic_fetch_add(&hak_alloc_call_count, 1);
if (call_num > 14250 && call_num < 14280 && size <= 1024) {
fprintf(stderr, "[HAK_ALLOC_AT] call=%lu size=%zu\n", call_num, size);
fflush(stderr);
}
```
- **問題**: リリースビルドでも**毎回**カウンタをインクリメント + 条件分岐実行
- **影響度**: ★★★★★(ホットパス - 全allocで実行
- **修正案**:
```c
#if !HAKMEM_BUILD_RELEASE
static _Atomic uint64_t hak_alloc_call_count = 0;
uint64_t call_num = atomic_fetch_add(&hak_alloc_call_count, 1);
if (call_num > 14250 && call_num < 14280 && size <= 1024) {
fprintf(stderr, "[HAK_ALLOC_AT] call=%lu size=%zu\n", call_num, size);
fflush(stderr);
}
#endif
```
- **コスト**: atomic_fetch_add5-10サイクル + 条件分岐1-2サイクル = **7-12サイクル/alloc**
---
### 2. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:39-56` - **Tiny Path デバッグログ3箇所**
```c
if (__builtin_expect(size <= TINY_MAX_SIZE, 1)) {
if (call_num > 14250 && call_num < 14280 && size <= 1024) {
fprintf(stderr, "[HAK_ALLOC_AT] call=%lu entering tiny path\n", call_num);
fflush(stderr);
}
#ifdef HAKMEM_TINY_PHASE6_BOX_REFACTOR
if (call_num > 14250 && call_num < 14280 && size <= 1024) {
fprintf(stderr, "[HAK_ALLOC_AT] call=%lu calling hak_tiny_alloc_fast_wrapper\n", call_num);
fflush(stderr);
}
tiny_ptr = hak_tiny_alloc_fast_wrapper(size);
if (call_num > 14250 && call_num < 14280 && size <= 1024) {
fprintf(stderr, "[HAK_ALLOC_AT] call=%lu hak_tiny_alloc_fast_wrapper returned %p\n", call_num, tiny_ptr);
fflush(stderr);
}
#endif
```
- **問題**: `call_num`変数がスコープ内に存在するため、**リリースビルドでも3つの条件分岐を評価**
- **影響度**: ★★★★★Tiny Path = 全allocの95%+
- **修正案**: 行24-29と同様に`#if !HAKMEM_BUILD_RELEASE`でガード
- **コスト**: 3つの条件分岐 × (1-2サイクル) = **3-6サイクル/alloc**
---
### 3. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:76-79,83` - **Tiny Fallback ログ**
```c
if (!tiny_ptr && size <= TINY_MAX_SIZE) {
static int log_count = 0;
if (log_count < 3) {
fprintf(stderr, "[DEBUG] Phase 7: tiny_alloc(%zu) failed, trying Mid/ACE layers (no malloc fallback)\n", size);
log_count++;
}
```
- **問題**: `log_count`チェックがリリースビルドでも実行
- **影響度**: ★★★Tiny失敗時のみ、頻度は低い
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード
- **コスト**: 条件分岐1-2サイクル
---
### 4. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:147-165` - **33KB デバッグログ3箇所**
```c
if (size >= 33000 && size <= 34000) {
fprintf(stderr, "[ALLOC] 33KB: TINY_MAX_SIZE=%d, threshold=%zu, condition=%d\n",
TINY_MAX_SIZE, threshold, (size > TINY_MAX_SIZE && size < threshold));
}
if (size > TINY_MAX_SIZE && size < threshold) {
if (size >= 33000 && size <= 34000) {
fprintf(stderr, "[ALLOC] 33KB: Calling hkm_ace_alloc\n");
}
// ...
if (size >= 33000 && size <= 34000) {
fprintf(stderr, "[ALLOC] 33KB: hkm_ace_alloc returned %p\n", l1);
}
```
- **問題**: 33KB allocで毎回3つの条件分岐 + fprintf実行
- **影響度**: ★★★★Mid-Large Path
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード
- **コスト**: 3つの条件分岐 + fprintf数千サイクル
---
### 5. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:191-194,201-203` - **Gap/OOM ログ**
```c
static _Atomic int gap_alloc_count = 0;
int count = atomic_fetch_add(&gap_alloc_count, 1);
#if HAKMEM_DEBUG_VERBOSE
if (count < 3) fprintf(stderr, "[HAKMEM] INFO: mid-gap fallback size=%zu\n", size);
#endif
```
```c
static _Atomic int oom_count = 0;
int count = atomic_fetch_add(&oom_count, 1);
if (count < 10) {
fprintf(stderr, "[HAKMEM] OOM: Unexpected allocation path for size=%zu, returning NULL\n", size);
fprintf(stderr, "[HAKMEM] (OOM count: %d) This should not happen!\n", count + 1);
}
```
- **問題**: `atomic_fetch_add`と条件分岐がリリースビルドでも実行
- **影響度**: ★★★Gap/OOM時のみ
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード全体を囲む
- **コスト**: atomic_fetch_add5-10サイクル + 条件分岐1-2サイクル
---
### 6. `/mnt/workdisk/public_share/hakmem/core/box/hak_alloc_api.inc.h:216` - **Invalid Magic エラー**
```c
if (hdr->magic != HAKMEM_MAGIC) {
fprintf(stderr, "[hakmem] ERROR: Invalid magic in allocated header!\n");
return ptr;
}
```
- **問題**: マジックチェック失敗時にfprintf実行ホットパスではないが、本番で起きると致命的
- **影響度**: ★★(エラー時のみ)
- **修正案**:
```c
if (hdr->magic != HAKMEM_MAGIC) {
#if !HAKMEM_BUILD_RELEASE
fprintf(stderr, "[hakmem] ERROR: Invalid magic in allocated header!\n");
#endif
return ptr;
}
```
---
### 7. `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h:77-87` - **Free Wrapper トレース**
```c
static int free_trace_en = -1;
static _Atomic int free_trace_count = 0;
if (__builtin_expect(free_trace_en == -1, 0)) {
const char* e = getenv("HAKMEM_FREE_WRAP_TRACE");
free_trace_en = (e && *e && *e != '0') ? 1 : 0;
}
if (free_trace_en) {
int n = atomic_fetch_add(&free_trace_count, 1);
if (n < 8) {
fprintf(stderr, "[FREE_WRAP_ENTER] ptr=%p\n", ptr);
}
}
```
- **問題**: **毎回getenv()チェック + 条件分岐** 初回のみgetenv、以降はキャッシュだが分岐は毎回
- **影響度**: ★★★★★(ホットパス - 全freeで実行
- **修正案**:
```c
#if !HAKMEM_BUILD_RELEASE
static int free_trace_en = -1;
static _Atomic int free_trace_count = 0;
if (__builtin_expect(free_trace_en == -1, 0)) {
const char* e = getenv("HAKMEM_FREE_WRAP_TRACE");
free_trace_en = (e && *e && *e != '0') ? 1 : 0;
}
if (free_trace_en) {
int n = atomic_fetch_add(&free_trace_count, 1);
if (n < 8) {
fprintf(stderr, "[FREE_WRAP_ENTER] ptr=%p\n", ptr);
}
}
#endif
```
- **コスト**: 条件分岐1-2サイクル × 2 = **2-4サイクル/free**
---
### 8. `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h:15-33` - **Free Route トレース**
```c
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;
}
// ... (hak_free_route_log calls this every free)
```
- **問題**: `hak_free_route_log()`が複数箇所で呼ばれ、**毎回条件分岐実行**
- **影響度**: ★★★★★(ホットパス - 全freeで複数回実行
- **修正案**:
```c
#if !HAKMEM_BUILD_RELEASE
static inline int hak_free_route_trace_on(void) { /* ... */ }
static inline void hak_free_route_log(const char* tag, void* p) { /* ... */ }
#else
#define hak_free_route_trace_on() 0
#define hak_free_route_log(tag, p) do { } while(0)
#endif
```
- **コスト**: 条件分岐1-2サイクル × 5-10回/free = **5-20サイクル/free**
---
### 9. `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h:195,213-217` - **Invalid Magic ログ**
```c
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) {
static int leak_warn = 0;
if (!leak_warn) {
fprintf(stderr, "[hakmem] WARNING: Skipping free of invalid pointer %p (may leak memory)\n", ptr);
leak_warn = 1;
}
```
- **問題**: `g_invalid_free_log`チェック + fprintf実行
- **影響度**: ★★(エラー時のみ)
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード
---
### 10. `/mnt/workdisk/public_share/hakmem/core/box/hak_free_api.inc.h:231` - **BigCache L25 getenv**
```c
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;
}
```
- **問題**: **初回のみgetenv実行**(キャッシュされるが、条件分岐は毎回)
- **影響度**: ★★★Large Free Path
- **修正案**: 初期化時に一度だけ実行し、TLS変数にキャッシュ
---
### 11. `/mnt/workdisk/public_share/hakmem/core/box/hak_wrappers.inc.h:118,123` - **Malloc Wrapper ログ**
```c
#ifdef HAKMEM_TINY_PHASE6_BOX_REFACTOR
fprintf(stderr, "[MALLOC_WRAPPER] count=%lu calling hak_alloc_at\n", count);
#endif
void* ptr = hak_alloc_at(size, (hak_callsite_t)site);
#ifdef HAKMEM_TINY_PHASE6_BOX_REFACTOR
fprintf(stderr, "[MALLOC_WRAPPER] count=%lu hak_alloc_at returned %p\n", count, ptr);
#endif
```
- **問題**: `HAKMEM_TINY_PHASE6_BOX_REFACTOR`はビルドフラグだが、**リリースビルドでも定義されている可能性**
- **影響度**: ★★★★★(ホットパス - 全mallocで2回実行
- **修正案**:
```c
#if !HAKMEM_BUILD_RELEASE && defined(HAKMEM_TINY_PHASE6_BOX_REFACTOR)
fprintf(stderr, "[MALLOC_WRAPPER] count=%lu calling hak_alloc_at\n", count);
#endif
```
---
## 🔧 **中程度の問題(ウォームパス)**
### 12. `/mnt/workdisk/public_share/hakmem/core/tiny_alloc_fast.inc.h:106,130-136` - **getenv チェック(初回のみ)**
```c
static inline int tiny_profile_enabled(void) {
if (__builtin_expect(g_tiny_profile_enabled == -1, 0)) {
const char* env = getenv("HAKMEM_TINY_PROFILE");
g_tiny_profile_enabled = (env && *env && *env != '0') ? 1 : 0;
}
return g_tiny_profile_enabled;
}
```
- **問題**: 初回のみgetenv実行、以降はキャッシュ**条件分岐は毎回**
- **影響度**: ★★★Refill時のみ
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード全体を囲む
---
### 13. `/mnt/workdisk/public_share/hakmem/core/tiny_alloc_fast.inc.h:139-156` - **Profiling Printdestructor**
```c
static void tiny_fast_print_profile(void) __attribute__((destructor));
static void tiny_fast_print_profile(void) {
if (!tiny_profile_enabled()) return;
if (g_tiny_alloc_hits == 0 && g_tiny_refill_calls == 0) return;
fprintf(stderr, "\n========== Box Theory Fast Path Profile ==========\n");
// ...
}
```
- **問題**: リリースビルドでも**プログラム終了時にfprintf実行**
- **影響度**: ★★(終了時のみ)
- **修正案**: `#if !HAKMEM_BUILD_RELEASE`でガード
---
### 14. `/mnt/workdisk/public_share/hakmem/core/tiny_alloc_fast.inc.h:192-204` - **Debug CountersIntegrity Check**
```c
#if !HAKMEM_BUILD_RELEASE
atomic_fetch_add(&g_integrity_check_class_bounds, 1);
static _Atomic uint64_t g_fast_pop_count = 0;
uint64_t pop_call = atomic_fetch_add(&g_fast_pop_count, 1);
if (0 && class_idx == 2 && pop_call > 5840 && pop_call < 5900) {
fprintf(stderr, "[FAST_POP_C2] call=%lu cls=%d head=%p count=%u\n",
pop_call, class_idx, g_tls_sll_head[class_idx], g_tls_sll_count[class_idx]);
fflush(stderr);
}
#endif
```
- **問題**: **すでにガード済み** ✅
- **影響度**: なし(リリースビルドではスキップ)
---
### 15. `/mnt/workdisk/public_share/hakmem/core/tiny_alloc_fast.inc.h:311-320` - **getenvCascade Percentage**
```c
static inline int sfc_cascade_pct(void) {
static int pct = -1;
if (__builtin_expect(pct == -1, 0)) {
const char* e = getenv("HAKMEM_SFC_CASCADE_PCT");
int v = e && *e ? atoi(e) : 50;
if (v < 0) v = 0; if (v > 100) v = 100;
pct = v;
}
return pct;
}
```
- **問題**: 初回のみgetenv実行、以降はキャッシュ**条件分岐は毎回**
- **影響度**: ★★SFC Refill時のみ
- **修正案**: 初期化時に一度だけ実行
---
### 16. `/mnt/workdisk/public_share/hakmem/core/tiny_free_fast.inc.h:106-112` - **SFC Debug ログ**
```c
static __thread int free_ss_debug_count = 0;
if (getenv("HAKMEM_SFC_DEBUG") && free_ss_debug_count < 20) {
free_ss_debug_count++;
// ...
fprintf(stderr, "[FREE_SS] base=%p, cls=%d, same_thread=%d, sfc_enabled=%d\n",
base, ss->size_class, is_same, g_sfc_enabled);
}
```
- **問題**: **毎回getenv()実行** (キャッシュなし!)
- **影響度**: ★★★★SuperSlab Free Path
- **修正案**:
```c
#if !HAKMEM_BUILD_RELEASE
static __thread int free_ss_debug_count = 0;
static int sfc_debug_en = -1;
if (sfc_debug_en == -1) {
sfc_debug_en = getenv("HAKMEM_SFC_DEBUG") ? 1 : 0;
}
if (sfc_debug_en && free_ss_debug_count < 20) {
// ...
}
#endif
```
- **コスト**: **getenv数百サイクル毎回実行** ← **CRITICAL!**
---
### 17. `/mnt/workdisk/public_share/hakmem/core/tiny_free_fast.inc.h:206-212` - **getenvFree Fast**
```c
static int s_free_fast_en = -1;
if (__builtin_expect(s_free_fast_en == -1, 0)) {
const char* e = getenv("HAKMEM_TINY_FREE_FAST");
// ...
}
```
- **問題**: 初回のみgetenv実行、以降はキャッシュ**条件分岐は毎回**
- **影響度**: ★★★Free Fast Path
- **修正案**: 初期化時に一度だけ実行
---
## 📊 **軽微な問題(コールドパス)**
### 18. `/mnt/workdisk/public_share/hakmem/core/hakmem_tiny.c:83-87` - **getenvSuperSlab Trace**
```c
static inline int superslab_trace_enabled(void) {
static int g_ss_trace_flag = -1;
if (__builtin_expect(g_ss_trace_flag == -1, 0)) {
const char* tr = getenv("HAKMEM_TINY_SUPERSLAB_TRACE");
g_ss_trace_flag = (tr && atoi(tr) != 0) ? 1 : 0;
}
return g_ss_trace_flag;
}
```
- **問題**: 初回のみgetenv実行、以降はキャッシュ
- **影響度**: ★(コールドパス)
---
### 19. 大量のログ出力関数fprintf/printf
**全ファイル共通**: 200以上のfprintf/printf呼び出しがリリースビルドでも実行される可能性
**主な問題箇所**:
- `core/hakmem_tiny_sfc.c`: SFC統計ログ約40箇所
- `core/hakmem_elo.c`: ELOログ約20箇所
- `core/hakmem_learner.c`: Learnerログ約30箇所
- `core/hakmem_whale.c`: Whale統計ログ約10箇所
- `core/tiny_region_id.h`: ヘッダー検証ログ約10箇所
- `core/tiny_superslab_free.inc.h`: Free詳細ログ約20箇所
**修正方針**: 全てを`#if !HAKMEM_BUILD_RELEASE`でガード
---
## 🎯 **修正優先度**
### **最優先(即座に修正すべき)**
1. **`hak_alloc_api.inc.h`**: 行24-29, 39-56, 147-165のfprintf/atomic_fetch_add
2. **`hak_free_api.inc.h`**: 行77-87のgetenv + atomic_fetch_add
3. **`hak_free_api.inc.h`**: 行15-33のRoute Trace5-10回/free
4. **`hak_wrappers.inc.h`**: 行118, 123のMalloc Wrapperログ
5. **`tiny_free_fast.inc.h`**: 行106-112の**毎回getenv実行** ← **CRITICAL!**
**期待効果**: これら5つだけで **20-50サイクル/操作** の削減 → **30-50% 性能向上**
---
### **高優先度(次に修正すべき)**
6. `hak_alloc_api.inc.h`: 行191-194, 201-203のGap/OOMログ
7. `hak_alloc_api.inc.h`: 行216の Invalid Magicログ
8. `hak_free_api.inc.h`: 行195, 213-217の Invalid Magicログ
9. `hak_free_api.inc.h`: 行231の BigCache L25 getenv
10. `tiny_alloc_fast.inc.h`: 行106, 130-136のProfilingチェック
11. `tiny_alloc_fast.inc.h`: 行139-156のProfileログ出力
**期待効果**: **5-15サイクル/操作** の削減 → **5-15% 性能向上**
---
### **中優先度(時間があれば修正)**
12. `tiny_alloc_fast.inc.h`: 行311-320のgetenvCascade
13. `tiny_free_fast.inc.h`: 行206-212のgetenvFree Fast
14. 全ファイルの200+箇所のfprintf/printfをガード
**期待効果**: **1-5サイクル/操作** の削減 → **1-5% 性能向上**
---
## 🚀 **総合的な期待効果**
### **最優先修正のみ5項目**
- **削減サイクル**: 20-50サイクル/操作
- **現在のオーバーヘッド**: ~50-80サイクル/操作(推定)
- **改善率**: **30-50%** 性能向上
- **期待性能**: 9M → **12-14M ops/s**
### **最優先 + 高優先度修正11項目**
- **削減サイクル**: 25-65サイクル/操作
- **改善率**: **40-60%** 性能向上
- **期待性能**: 9M → **13-18M ops/s**
### **全修正すべてのfprintfガード**
- **削減サイクル**: 30-80サイクル/操作
- **改善率**: **50-70%** 性能向上
- **期待性能**: 9M → **15-25M ops/s**
- **System malloc比**: 25M / 43M = **58%** 現状の4.8倍遅い → **1.7倍遅い**に改善)
---
## 💡 **推奨修正パターン**
### **パターン1: 条件付きコンパイル**
```c
#if !HAKMEM_BUILD_RELEASE
static _Atomic uint64_t debug_counter = 0;
uint64_t count = atomic_fetch_add(&debug_counter, 1);
if (count < 10) {
fprintf(stderr, "[DEBUG] ...\n");
}
#endif
```
### **パターン2: マクロ化**
```c
#if !HAKMEM_BUILD_RELEASE
#define DEBUG_LOG(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...) do { } while(0)
#endif
// Usage:
DEBUG_LOG("[HAK_ALLOC_AT] call=%lu size=%zu\n", call_num, size);
```
### **パターン3: getenv初期化時キャッシュ**
```c
// Before: 毎回チェック
if (g_flag == -1) {
g_flag = getenv("VAR") ? 1 : 0;
}
// After: 初期化関数で一度だけ
void hak_init(void) {
g_flag = getenv("VAR") ? 1 : 0;
}
```
---
## 🔬 **検証方法**
### **Before/After 比較**
```bash
# Before
./out/release/bench_fixed_size_hakmem 100000 256 128
# Expected: ~9M ops/s
# After (最優先修正のみ)
./out/release/bench_fixed_size_hakmem 100000 256 128
# Expected: ~12-14M ops/s (+33-55%)
# After (全修正)
./out/release/bench_fixed_size_hakmem 100000 256 128
# Expected: ~15-25M ops/s (+66-177%)
```
### **Perf 分析**
```bash
# IPC (Instructions Per Cycle) 確認
perf stat -e cycles,instructions,branches,branch-misses ./out/release/bench_*
# Before: IPC ~1.2-1.5 (低い = 多くのストール)
# After: IPC ~2.0-2.5 (高い = 効率的な実行)
```
---
## 📝 **まとめ**
### **現状の問題**
1. リリースビルドでも**大量のデバッグ処理が実行**されている
2. ホットパスで**毎回atomic_fetch_add + 条件分岐 + fprintf**実行
3. 特に`tiny_free_fast.inc.h`の**毎回getenv実行**は致命的
### **修正の影響**
- **最優先5項目**: 30-50% 性能向上9M → 12-14M ops/s
- **全項目**: 50-70% 性能向上9M → 15-25M ops/s
- **System malloc比**: 4.8倍遅い → 1.7倍遅い(**60%差を埋める**
### **次のステップ**
1. **最優先5項目を修正**1-2時間
2. **ベンチマーク実行**Before/After比較
3. **Perf分析**IPC改善を確認
4. **高優先度項目を修正**追加1-2時間
5. **最終ベンチマーク**System mallocとの差を確認
---
## 🎓 **学んだこと**
1. **リリースビルドでもデバッグ処理は消えない** - `#if !HAKMEM_BUILD_RELEASE`でガード必須
2. **fprintf 1個でも致命的** - ホットパスでは絶対に許容できない
3. **getenv毎回実行は論外** - 初期化時に一度だけキャッシュすべき
4. **atomic_fetch_add も高コスト** - 5-10サイクル消費するため、デバッグのみで使用
5. **条件分岐すら最小限に** - メモリアロケータのホットパスでは1サイクルが重要
---
**レポート作成日時**: 2025-11-13
**対象コミット**: 79c74e72d (Debug patches: C7 logging, Front Gate detection, TLS-SLL fixes)
**分析者**: Claude (Sonnet 4.5)