Files
hakmem/core/box/tiny_route_env_box.h
Moe Charm (CI) 118c0e4857 Phase FREE-DISPATCHER-OPT-1: free dispatcher 統計計測
**目的**: free dispatcher(29%)の内訳を細分化して計測。

**実装内容**:
- FreeDispatchStats 構造体追加(ENV: HAKMEM_FREE_DISPATCH_STATS, default 0)
- カウンタ: total_calls / domain (tiny/mid/large) / route (ultra/legacy/pool/v6) / env_checks / route_for_class_calls
- hak_free_at / tiny_route_for_class / tiny_route_snapshot_init にカウンタ埋め込み
- 挙動変更なし(計測のみ、ENV OFF 時は overhead ゼロ)

**計測結果**:

Mixed 16-1024B (1M iter, ws=400):
- total=8,081, route_calls=267,967, env_checks=9
- BENCH_FAST_FRONT により大半は早期リターン
- route_for_class は主に alloc 側で呼ばれる(267k calls vs 8k frees)
- ENV check は初期化時の 9回のみ(snapshot 効果)

C6-heavy (257-768B, 1M iter, ws=400):
- total=500,099, route_calls=1,034, env_checks=9
- fg_classify_domain に到達する free が多い
- route_for_class 呼び出しは極小(snapshot 効果)

**結論**:
- ENV check は既に十分最適化されている(初期化時のみ)
- route_for_class は alloc 側での呼び出しが主で、free 側は snapshot で O(1)
- 次フェーズ(OPT-2)では別のアプローチを検討

**ドキュメント追加**:
- docs/analysis/FREE_DISPATCHER_ANALYSIS.md(新規)
- CURRENT_TASK.md に Phase FREE-DISPATCHER-OPT-1 セクション追加

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 21:21:40 +09:00

134 lines
5.4 KiB
C
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.

// tiny_route_env_box.h - Route snapshot for Tiny front (Heap vs Legacy)
// 役割:
// - 起動時に「各クラスが TinyHeap を使うか」をスナップショットし、ホットパスでは LUT 1 回に縮約する。
// - HAKMEM_TINY_HEAP_PROFILE / HAKMEM_TINY_HEAP_BOX / HAKMEM_TINY_HEAP_CLASSES の組合せをここで解決する。
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include "../hakmem_tiny_config.h"
#include "tiny_heap_env_box.h"
#include "free_dispatch_stats_box.h" // Phase FREE-DISPATCHER-OPT-1
#include "smallobject_hotbox_v3_env_box.h"
#include "smallobject_hotbox_v4_env_box.h"
#include "smallobject_v5_env_box.h"
// ENV sentinel values
#ifndef ENV_UNINIT
#define ENV_UNINIT (-1)
#define ENV_ENABLED (1)
#define ENV_DISABLED (0)
#endif
typedef enum {
TINY_ROUTE_LEGACY = 0,
TINY_ROUTE_HEAP = 1, // TinyHeap v1
TINY_ROUTE_HOTHEAP_V2 = 2, // TinyHotHeap v2
TINY_ROUTE_SMALL_HEAP_V3 = 3, // SmallObject HotHeap v3 (C7-first,研究箱)
TINY_ROUTE_SMALL_HEAP_V4 = 4, // SmallObject HotHeap v4 (stub, route未使用)
TINY_ROUTE_SMALL_HEAP_V5 = 5, // SmallObject HotHeap v5 (C6-only route stub, Phase v5-1)
TINY_ROUTE_SMALL_HEAP_V6 = 6, // SmallObject Core v6 (C6-only route stub, Phase v6-1)
} tiny_route_kind_t;
extern tiny_route_kind_t g_tiny_route_class[TINY_NUM_CLASSES];
extern int g_tiny_route_snapshot_done;
// ============================================================================
// Phase v6-1: SmallObject Core v6 ENV gate (must be before tiny_route_snapshot_init)
// ============================================================================
// small_heap_v6_enabled() - グローバル v6 enable check
static inline int small_heap_v6_enabled(void) {
static int g_enabled = ENV_UNINIT;
if (__builtin_expect(g_enabled == ENV_UNINIT, 0)) {
const char* e = getenv("HAKMEM_SMALL_HEAP_V6_ENABLED");
g_enabled = (e && *e && *e != '0') ? ENV_ENABLED : ENV_DISABLED;
}
return (g_enabled == ENV_ENABLED);
}
// small_heap_v6_class_mask() - v6 対象クラスのビットマスク
static inline uint32_t small_heap_v6_class_mask(void) {
static int g_mask = ENV_UNINIT;
if (__builtin_expect(g_mask == ENV_UNINIT, 0)) {
const char* e = getenv("HAKMEM_SMALL_HEAP_V6_CLASSES");
if (e && *e) {
g_mask = (int)strtoul(e, NULL, 0);
} else {
g_mask = 0x0; // default: OFF
}
}
return (uint32_t)g_mask;
}
// small_heap_v6_class_enabled() - 指定クラスが v6 有効か
static inline int small_heap_v6_class_enabled(uint32_t class_idx) {
if (class_idx >= 8) return 0;
if (!small_heap_v6_enabled()) return 0;
uint32_t mask = small_heap_v6_class_mask();
return (mask & (1u << class_idx)) ? 1 : 0;
}
static inline void tiny_route_snapshot_init(void) {
for (int i = 0; i < TINY_NUM_CLASSES; i++) {
// Phase v6-1: C6-only v6 route stub (highest priority)
FREE_DISPATCH_STAT_INC(env_checks); // ENV check counter
if (small_heap_v6_class_enabled((uint32_t)i)) {
g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V6;
FREE_DISPATCH_STAT_INC(route_core_v6);
} else if (i == 6 && small_heap_v5_class_enabled(6)) {
// Phase v5-1: C6-only v5 route stub (before v4 check)
FREE_DISPATCH_STAT_INC(env_checks);
g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V5;
} else if (small_heap_v4_class_enabled((uint8_t)i)) {
FREE_DISPATCH_STAT_INC(env_checks);
g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V4;
} else if (small_heap_v3_class_enabled((uint8_t)i)) {
FREE_DISPATCH_STAT_INC(env_checks);
g_tiny_route_class[i] = TINY_ROUTE_SMALL_HEAP_V3;
} else if (tiny_hotheap_v2_class_enabled((uint8_t)i)) {
FREE_DISPATCH_STAT_INC(env_checks);
g_tiny_route_class[i] = TINY_ROUTE_HOTHEAP_V2;
} else if (tiny_heap_box_enabled() && tiny_heap_class_route_enabled(i)) {
FREE_DISPATCH_STAT_INC(env_checks);
FREE_DISPATCH_STAT_INC(env_checks);
g_tiny_route_class[i] = TINY_ROUTE_HEAP;
} else {
g_tiny_route_class[i] = TINY_ROUTE_LEGACY;
FREE_DISPATCH_STAT_INC(route_tiny_legacy);
}
}
g_tiny_route_snapshot_done = 1;
}
static inline tiny_route_kind_t tiny_route_for_class(uint8_t ci) {
FREE_DISPATCH_STAT_INC(route_for_class_calls); // Phase FREE-DISPATCHER-OPT-1
if (__builtin_expect(!g_tiny_route_snapshot_done, 0)) {
tiny_route_snapshot_init();
}
if (__builtin_expect(ci >= TINY_NUM_CLASSES, 0)) {
return TINY_ROUTE_LEGACY;
}
return g_tiny_route_class[ci];
}
static inline int tiny_route_is_heap_kind(tiny_route_kind_t route) {
return route == TINY_ROUTE_HEAP ||
route == TINY_ROUTE_HOTHEAP_V2 ||
route == TINY_ROUTE_SMALL_HEAP_V3 ||
route == TINY_ROUTE_SMALL_HEAP_V4 ||
route == TINY_ROUTE_SMALL_HEAP_V5 ||
route == TINY_ROUTE_SMALL_HEAP_V6;
}
// C7 front が TinyHeap を使うかRoute snapshot 経由で判定)
static inline int tiny_c7_front_uses_heap(void) {
return tiny_route_is_heap_kind(tiny_route_for_class(7));
}
// C6 front が TinyHeap を使うかRoute snapshot 経由で判定)
static inline int tiny_c6_front_uses_heap(void) {
return tiny_route_is_heap_kind(tiny_route_for_class(6));
}