## 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>
21 KiB
21 KiB
hakmem_tiny_free.inc - 構造分析と分割提案
1. ファイル全体の概要
ファイル統計:
| 項目 | 値 |
|---|---|
| 総行数 | 1,711 |
| 実コード行 | 1,348 (78.7%) |
| コメント行 | 257 (15.0%) |
| 空行 | 107 (6.3%) |
責務エリア別行数:
| 責務エリア | 行数 | コード行 | 割合 |
|---|---|---|---|
| Free with TinySlab(両パス) | 558 | 462 | 34.2% |
| SuperSlab free path | 305 | 281 | 18.7% |
| SuperSlab allocation & refill | 394 | 308 | 24.1% |
| Main free entry point | 135 | 116 | 8.3% |
| Helper functions | 65 | 60 | 4.0% |
| Shutdown | 30 | 28 | 1.8% |
2. 関数一覧と構造
全10関数の詳細マップ:
Phase 1: Helper Functions (Lines 1-65)
1-15 Includes & extern declarations
16-25 tiny_drain_to_sll_budget() [10 lines] ← ENV-based config
27-42 tiny_drain_freelist_to_slab_to_sll_once() [16 lines] ← Freelist splicing
44-64 tiny_remote_queue_contains_guard() [21 lines] ← Remote queue traversal
責務:
- TLS SLL へのドレイン予算決定(環境変数ベース)
- リモートキューの重複検査
- 重要度: LOW (ユーティリティ関数)
Phase 2: Main Free Path - TinySlab (Lines 68-625)
関数: hak_tiny_free_with_slab(void* ptr, TinySlab* slab) (558行)
構成:
68-67 入口・コメント
70-133 SuperSlab mode (slab == NULL) [64 行]
- SuperSlab lookup
- Class validation
- Safety checks (HAKMEM_SAFE_FREE)
- Cross-thread detection
135-206 Same-thread TLS push paths [72 行]
- Fast path (g_fast_enable)
- TLS List push (g_tls_list_enable)
- HotMag push (g_hotmag_enable)
208-620 Magazine/SLL push paths [413 行]
- TinyQuickSlot handling
- TLS SLL push (fast)
- Magazine push (with hysteresis)
- Background spill (g_bg_spill_enable)
- Super Registry spill
- Publisher final fallback
622-625 Closing
内部フローチャート:
hak_tiny_free_with_slab(ptr, slab)
│
├─ if (!slab) ← SuperSlab path
│ │
│ ├─ hak_super_lookup(ptr)
│ ├─ Class validation
│ ├─ HAKMEM_SAFE_FREE checks
│ ├─ Cross-thread detection
│ │ │
│ │ └─ if (meta->owner_tid != self_tid)
│ │ └─ hak_tiny_free_superslab(ptr, ss) ← REMOTE PATH
│ │ └─ return
│ │
│ └─ Same-thread paths (owner_tid == self_tid)
│ │
│ ├─ g_fast_enable + tiny_fast_push() ← FAST CACHE
│ │
│ ├─ g_tls_list_enable + tls_list push ← TLS LIST
│ │
│ └─ Magazine/SLL paths:
│ ├─ TinyQuickSlot (≤64B)
│ ├─ TLS SLL push (fast, no lock)
│ ├─ Magazine push (with hysteresis)
│ ├─ Background spill (async)
│ ├─ SuperRegistry spill (with lock)
│ └─ Publisher fallback
│
└─ else ← TinySlab-direct path
[continues with similar structure]
キー特性:
- 責務の多重性: Free path が複数ポリシーを内包
- Fast path (タイム測定なし)
- TLS List (容量制限あり)
- Magazine (容量チューニング)
- SLL (ロックフリー)
- Background async
- 責任: VERY HIGH (メイン Free 処理の 34%)
- リスク: HIGH (複数パスの相互作用)
Phase 3: SuperSlab Allocation Helpers (Lines 626-1019)
3a. superslab_alloc_from_slab() (Lines 626-709)
626-628 入口
630-663 Remote queue drain(リモートキュー排出)
665-677 Remote pending check(デバッグ)
679-708 Linear / Freelist allocation
- Linear: sequential access (cache-friendly)
- Freelist: pop from meta->freelist
責務:
- SuperSlab の単一スラブからのブロック割り当て
- リモートキューの管理
- Linear/Freelist の2パスをサポート
- 重要度: HIGH (allocation hot path)
3b. superslab_refill() (Lines 712-1019)
712-745 初期化・状態キャプチャ
747-782 Mid-size simple refill(クラス>=4)
785-947 SuperSlab adoption(published partial の採用)
- g_ss_adopt_en フラグチェック
- クールダウン管理
- First-fit slab スキャン
- Best-fit scoring
- slab acquisition & binding
949-1019 SuperSlab allocation(新規作成)
- superslab_allocate()
- slab init & binding
- refcount管理
キー特性:
- 複雑度: VERY HIGH
- Adoption vs allocation decision logic
- Scoring algorithm (lines 850-947)
- Multi-layer registry scan
- 責任: HIGH (24% of file)
- 最適化ターゲット: Phase P0 最適化(
nonempty_maskで O(n) → O(1) 化)
内部フロー:
superslab_refill(class_idx)
│
├─ Try mid_simple_refill (if class >= 4)
│ ├─ Use existing TLS SuperSlab's virgin slab
│ └─ return
│
├─ Try ss_partial_adopt() (if g_ss_adopt_en)
│ ├─ First-fit or Best-fit scoring
│ ├─ slab_try_acquire()
│ ├─ tiny_tls_bind_slab()
│ └─ return adopted
│
└─ superslab_allocate() (fresh allocation)
├─ Allocate new SuperSlab memory
├─ superslab_init_slab(slab_0)
├─ tiny_tls_bind_slab()
└─ return new
Phase 4: SuperSlab Allocation Entry (Lines 1020-1170)
関数: hak_tiny_alloc_superslab() (151行)
1020-1024 入口・ENV検査
1026-1169 TLS lookup + refill logic
- TLS cache hit (fast)
- Linear/Freelist allocation
- Refill on miss
- Adopt/allocate decision
責務:
- SuperSlab-based allocation の main entry point
- TLS キャッシュ管理
- 重要度: MEDIUM (allocation のみ, free ではない)
Phase 5: SuperSlab Free Path (Lines 1171-1475)
関数: hak_tiny_free_superslab() (305行)
1171-1198 入口・デバッグ
1200-1230 Validation & safety checks
- size_class bounds checking
- slab_idx validation
- Double-free detection
1232-1310 Same-thread free path [79 lines]
- ROUTE_MARK tracking
- Direct freelist push
- remote guard check
- MidTC (TLS tcache) integration
- First-free publish detection
1312-1470 Remote/cross-thread path [159 lines]
- Remote queue enqueue
- Pending drain check
- Remote sentinel validation
- Bulk refill coordination
キー特性:
- 責務: HIGH (18.7% of file)
- 複雑度: VERY HIGH
- Same-thread vs remote path の分岐
- Remote queue management
- Sentinel validation
- Guard transitions (ROUTE_MARK)
内部フロー:
hak_tiny_free_superslab(ptr, ss)
│
├─ Validation (bounds, magic, size_class)
│
├─ if (same-thread: owner_tid == my_tid)
│ ├─ tiny_free_local_box() → freelist push
│ ├─ first-free → publish detection
│ └─ MidTC integration
│
└─ else (remote/cross-thread)
├─ tiny_free_remote_box() → remote queue
├─ Sentinel validation
└─ Bulk refill coordination
Phase 6: Main Free Entry Point (Lines 1476-1610)
関数: hak_tiny_free() (135行)
1476-1478 入口チェック
1482-1505 HAKMEM_TINY_BENCH_SLL_ONLY mode(ベンチ用)
1507-1529 TINY_ULTRA mode(ultra-simple path)
1531-1575 Fast class resolution + Fast path attempt
- SuperSlab lookup (g_use_superslab)
- TinySlab lookup (fallback)
- Fast cache push attempt
1577-1596 SuperSlab dispatch
1598-1610 TinySlab fallback
責務:
- Global free() エントリポイント
- Mode selection (benchmark/ultra/normal)
- Class resolution
- hak_tiny_free_with_slab() への delegation
- 重要度: MEDIUM (8.3%)
- 責任: Dispatch + routing only
Phase 7: Shutdown (Lines 1676-1705)
関数: hak_tiny_shutdown() (30行)
1676-1686 TLS SuperSlab refcount cleanup
1687-1694 Background bin thread shutdown
1695-1704 Intelligence Engine shutdown
責務:
- Resource cleanup
- Thread termination
- 重要度: LOW (1.8%)
3. 責任範囲の詳細分析
3.1 By Responsibility Domain
Free Paths:
- Same-thread (TinySlab): lines 135-206, 1232-1310
- Same-thread (SuperSlab via hak_tiny_free_with_slab): lines 70-133
- Remote/cross-thread (SuperSlab): lines 1312-1470
- Magazine/SLL (async): lines 208-620
Allocation Paths:
- SuperSlab alloc: lines 626-709
- SuperSlab refill: lines 712-1019
- SuperSlab entry: lines 1020-1170
Management:
- Remote queue guard: lines 44-64
- SLL drain: lines 27-42
- Shutdown: lines 1676-1705
3.2 External Dependencies
本ファイル内で定義:
hak_tiny_free()[PUBLIC]hak_tiny_free_with_slab()[PUBLIC]hak_tiny_shutdown()[PUBLIC]- All other functions [STATIC]
依存先ファイル:
tiny_remote.h
├─ tiny_remote_track_*
├─ tiny_remote_queue_contains_guard
├─ tiny_remote_pack_diag
└─ tiny_remote_side_get
slab_handle.h
├─ slab_try_acquire()
├─ slab_drain_remote_full()
├─ slab_release()
└─ slab_is_valid()
tiny_refill.h
├─ tiny_tls_bind_slab()
├─ superslab_find_free_slab()
├─ superslab_init_slab()
├─ ss_partial_adopt()
├─ ss_partial_publish()
└─ ss_active_dec_one()
tiny_tls_guard.h
├─ tiny_tls_list_guard_push()
├─ tiny_tls_refresh_params()
└─ tls_list_* functions
mid_tcache.h
├─ midtc_enabled()
└─ midtc_push()
hakmem_tiny_magazine.h (BUILD_RELEASE=0)
├─ TinyTLSMag structure
├─ mag operations
└─ hotmag_push()
box/free_publish_box.h
box/free_remote_box.h (line 1252)
box/free_local_box.h (line 1287)
4. 関数間の呼び出し関係
[Global Entry Points]
hak_tiny_free()
└─ (1531-1609) Dispatch logic
│
├─> hak_tiny_free_with_slab(ptr, NULL) [SS mode]
│ └─> hak_tiny_free_superslab() [Remote path]
│
├─> hak_tiny_free_with_slab(ptr, slab) [TS mode]
│
└─> hak_tiny_free_superslab() [Direct dispatch]
hak_tiny_free_with_slab(ptr, slab) [Lines 68-625]
├─> Magazine/SLL management
│ ├─ tiny_fast_push()
│ ├─ tls_list_push()
│ ├─ hotmag_push()
│ ├─ bulk_mag_to_sll_if_room()
│ ├─ [background spill]
│ └─ [super registry spill]
│
└─> hak_tiny_free_superslab() [Remote transition]
[Lines 1171-1475]
hak_tiny_free_superslab()
├─> (same-thread) tiny_free_local_box()
│ └─ Direct freelist push
├─> (remote) tiny_free_remote_box()
│ └─ Remote queue enqueue
└─> tiny_remote_queue_contains_guard() [Duplicate check]
[Allocation]
hak_tiny_alloc_superslab()
└─> superslab_refill()
├─> ss_partial_adopt()
│ ├─ slab_try_acquire()
│ ├─ slab_drain_remote_full()
│ └─ slab_release()
│
└─> superslab_allocate()
└─> superslab_init_slab()
superslab_alloc_from_slab() [Helper for refill]
├─> slab_try_acquire()
└─> slab_drain_remote_full()
[Utilities]
tiny_drain_to_sll_budget() [Config getter]
tiny_remote_queue_contains_guard() [Duplicate validation]
[Shutdown]
hak_tiny_shutdown()
5. 分割候補の特定
分割の根拠:
- 関数数: 10個 → サイズ大きい
- 責務の混在: Free, Allocation, Magazine, Remote queue all mixed
- 再利用性: Allocation 関数は独立可能
- テスト容易性: Remote queue と同期ロジックは隔離可能
- メンテナンス性: 558行 の
hak_tiny_free_with_slab()は理解困難
分割可能性スコア:
| セクション | 独立度 | 複雑度 | サイズ | 優先度 |
|---|---|---|---|---|
| Helper (drain, remote guard) | ★★★★★ | ★☆☆☆☆ | 65行 | P3 (LOW) |
| Magazine/SLL management | ★★★★☆ | ★★★★☆ | 413行 | P1 (HIGH) |
| Same-thread free paths | ★★★☆☆ | ★★★☆☆ | 72行 | P2 (MEDIUM) |
| SuperSlab alloc/refill | ★★★★☆ | ★★★★★ | 394行 | P1 (HIGH) |
| SuperSlab free path | ★★★☆☆ | ★★★★★ | 305行 | P1 (HIGH) |
| Main entry point | ★★★★★ | ★★☆☆☆ | 135行 | P2 (MEDIUM) |
| Shutdown | ★★★★★ | ★☆☆☆☆ | 30行 | P3 (LOW) |
6. 推奨される分割案(3段階)
Phase 1: Magazine/SLL 関連を分離
新ファイル: tiny_free_magazine.inc.h (413行 → 400行推定)
含める関数:
- Magazine push/spill logic
- TLS SLL push
- HotMag handling
- Background spill
- Super Registry spill
- Publisher fallback
呼び出し元から参照:
// In hak_tiny_free_with_slab()
#include "tiny_free_magazine.inc.h"
if (tls_list_enabled) {
tls_list_push(class_idx, ptr);
// ...
}
// Then continue with magazine code via include
メリット:
- Magazine は独立した "レイヤー" (Policy pattern)
- 環境変数で on/off 可能
- テスト時に完全に mock 可能
- 関数削減: 8個 → 6個
Phase 2: SuperSlab Allocation を分離
新ファイル: tiny_superslab_alloc.inc.h (394行 → 380行推定)
含める関数:
static SuperSlab* superslab_refill(int class_idx)
static inline void* superslab_alloc_from_slab(SuperSlab* ss, int slab_idx)
static inline void* hak_tiny_alloc_superslab(int class_idx)
// + adoption & registry helpers
呼び出し元:
hak_tiny_free.inc(main entry point のみ)- 他のファイル (already external)
メリット:
- Allocation は free と直交
- Adoption logic は独立テスト可能
- Registry optimization (P0) は此処に focused
- Hot path を明確化
Phase 3: SuperSlab Free を分離
新ファイル: tiny_superslab_free.inc.h (305行 → 290行推定)
含める関数:
static inline void hak_tiny_free_superslab(void* ptr, SuperSlab* ss)
// + remote/local box includes (inline)
責務:
- Same-thread freelist push
- Remote queue management
- Sentinel validation
- First-free publish detection
メリット:
- Remote queue logic は純粋 (no allocation)
- Cross-thread free は critical path
- Debugging が簡単 (ROUTE_MARK)
7. 分割後のファイル構成
Current:
hakmem_tiny_free.inc (1,711行)
├─ Includes (8行)
├─ Helpers (65行)
├─ hak_tiny_free_with_slab (558行)
│ ├─ Magazine/SLL paths (413行)
│ └─ TinySlab path (145行)
├─ SuperSlab alloc/refill (394行)
├─ SuperSlab free (305行)
├─ hak_tiny_free (135行)
├─ [extracted queries] (50行)
└─ hak_tiny_shutdown (30行)
After Phase 1-3 Refactoring:
hakmem_tiny_free.inc (450行)
├─ Includes (8行)
├─ Helpers (65行)
├─ hak_tiny_free_with_slab (stub, delegates)
├─ hak_tiny_free (main entry) (135行)
├─ hak_tiny_shutdown (30行)
└─ #include "tiny_superslab_alloc.inc.h"
└─ #include "tiny_superslab_free.inc.h"
└─ #include "tiny_free_magazine.inc.h"
tiny_superslab_alloc.inc.h (380行)
├─ superslab_refill()
├─ superslab_alloc_from_slab()
├─ hak_tiny_alloc_superslab()
├─ Adoption/registry logic
tiny_superslab_free.inc.h (290行)
├─ hak_tiny_free_superslab()
├─ Remote queue management
├─ Sentinel validation
tiny_free_magazine.inc.h (400行)
├─ Magazine push/spill
├─ TLS SLL management
├─ HotMag integration
├─ Background spill
8. インターフェース設計
Internal Dependencies (headers needed):
tiny_superslab_alloc.inc.h は以下を require:
#include "tiny_refill.h" // ss_partial_adopt, superslab_allocate
#include "slab_handle.h" // slab_try_acquire
#include "tiny_remote.h" // remote tracking
tiny_superslab_free.inc.h は以下を require:
#include "box/free_local_box.h"
#include "box/free_remote_box.h"
#include "tiny_remote.h" // validation
#include "slab_handle.h" // slab_index_for
tiny_free_magazine.inc.h は以下を require:
#include "hakmem_tiny_magazine.h" // Magazine structures
#include "tiny_tls_guard.h" // TLS list ops
#include "mid_tcache.h" // MidTC
// + many helper functions already in scope
New Integration Header:
tiny_free_internal.h (新規作成)
// Public exports from tiny_free.inc components
extern void hak_tiny_free(void* ptr);
extern void hak_tiny_free_with_slab(void* ptr, TinySlab* slab);
extern void hak_tiny_shutdown(void);
// Internal allocation API (for free path)
extern void* hak_tiny_alloc_superslab(int class_idx);
extern static void hak_tiny_free_superslab(void* ptr, SuperSlab* ss);
// Forward declarations for cross-component calls
struct TinySlabMeta;
struct SuperSlab;
9. 分割後の呼び出しフロー(改善版)
[hak_tiny_free.inc]
hak_tiny_free(ptr)
├─ mode selection (BENCH, ULTRA, NORMAL)
├─ class resolution
│ └─ SuperSlab lookup OR TinySlab lookup
│
└─> (if SuperSlab)
├─ DISPATCH: #include "tiny_superslab_free.inc.h"
│ └─ hak_tiny_free_superslab(ptr, ss)
│ ├─ same-thread: freelist push
│ └─ remote: queue enqueue
│
└─ (if TinySlab)
├─ DISPATCH: #include "tiny_superslab_alloc.inc.h" [if needed for refill]
└─ DISPATCH: #include "tiny_free_magazine.inc.h"
├─ Fast cache?
├─ TLS list?
├─ Magazine?
├─ SLL?
├─ Background spill?
└─ Publisher fallback?
[tiny_superslab_alloc.inc.h]
hak_tiny_alloc_superslab(class_idx)
└─ superslab_refill()
├─ adoption: ss_partial_adopt()
└─ allocate: superslab_allocate()
[tiny_superslab_free.inc.h]
hak_tiny_free_superslab(ptr, ss)
├─ (same-thread) tiny_free_local_box()
└─ (remote) tiny_free_remote_box()
[tiny_free_magazine.inc.h]
magazine_push_or_spill(class_idx, ptr)
├─ quick slot?
├─ SLL?
├─ magazine?
├─ background spill?
└─ publisher?
10. メリット・デメリット分析
分割のメリット:
| メリット | 詳細 |
|---|---|
| 理解容易性 | 各ファイルが単一責務(Free / Alloc / Magazine) |
| テスト容易性 | Magazine 層を mock して free path テスト可能 |
| リビジョン追跡 | Magazine スパイル改善時に superslab_free は影響なし |
| 並列開発 | 3つのファイルを独立で開発・最適化可能 |
| 再利用 | tiny_superslab_alloc.inc.h を alloc.inc でも再利用可能 |
| デバッグ | 各層の enable/disable フラグで検証容易 |
分割のデメリット:
| デメリット | 対策 |
|---|---|
| include 増加 | 3個 include (acceptable, #include guard) |
| 複雑度追加 | モジュール図を CLAUDE.md に記載 |
| circular dependency risk | tiny_free_internal.h で forwarding declaration |
| マージ困難 | git rebase 時に conflict (minor) |
11. 実装ロードマップ
Step 1: バックアップ
cp core/hakmem_tiny_free.inc core/hakmem_tiny_free.inc.bak
Step 2: tiny_free_magazine.inc.h 抽出
- Lines 208-620 を新ファイルに
- External function prototype をヘッダに
- hakmem_tiny_free.inc で
#includeに置換
Step 3: tiny_superslab_alloc.inc.h 抽出
- Lines 626-1019 を新ファイルに
- hakmem_tiny_free.inc で
#includeに置換
Step 4: tiny_superslab_free.inc.h 抽出
- Lines 1171-1475 を新ファイルに
- hakmem_tiny_free.inc で
#includeに置換
Step 5: テスト & ビルド確認
make clean && make
./larson_hakmem ... # Regression テスト
12. 現在の複雑度指標
サイクロマティック複雑度 (推定):
| 関数 | CC | リスク |
|---|---|---|
| hak_tiny_free_with_slab | 28 | ★★★★★ CRITICAL |
| superslab_refill | 18 | ★★★★☆ HIGH |
| hak_tiny_free_superslab | 16 | ★★★★☆ HIGH |
| hak_tiny_free | 12 | ★★★☆☆ MEDIUM |
| superslab_alloc_from_slab | 4 | ★☆☆☆☆ LOW |
分割により:
- hak_tiny_free_with_slab: 28 → 8-12 (中規模に削減)
- 複数の小さい関数に分散
- 各ファイルが「焦点を絞った責務」に
13. 関連ドキュメント参照
- CLAUDE.md: Phase 6-2.1 P0 最適化 (superslab_refill の O(n)→O(1) 化)
- HISTORY.md: 過去の分割失敗 (Phase 5-B-Simple)
- LARSON_GUIDE.md: ビルド・テスト方法
サマリー
| 項目 | 現状 | 分割後 |
|---|---|---|
| ファイル数 | 1 | 4 |
| 総行数 | 1,711 | 1,520 (include overhead相殺) |
| 平均関数サイズ | 171行 | 95行 |
| 最大関数サイズ | 558行 | 305行 |
| 理解難易度 | ★★★★☆ | ★★★☆☆ |
| テスト容易性 | ★★☆☆☆ | ★★★★☆ |
推奨実施: YES - Magazine/SLL + SuperSlab free を分離することで
- 主要な複雑性 (CC 28) を 4-8 に削減
- Free path と allocation path を明確に分離
- Magazine 最適化時の影響範囲を限定