628 lines
20 KiB
Markdown
628 lines
20 KiB
Markdown
|
|
# リリースビルド デバッグ処理 洗い出しレポート
|
|||
|
|
|
|||
|
|
## 🔥 **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_add(5-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_add(5-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 Print(destructor)**
|
|||
|
|
|
|||
|
|
```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 Counters(Integrity 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` - **getenv(Cascade 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` - **getenv(Free 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` - **getenv(SuperSlab 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 Trace(5-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のgetenv(Cascade)
|
|||
|
|
13. `tiny_free_fast.inc.h`: 行206-212のgetenv(Free 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)
|