Files
hakmem/docs/analysis/STRUCTURAL_ANALYSIS.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

21 KiB
Raw Blame History

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 adoptionpublished 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 modeultra-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. 分割候補の特定

分割の根拠:

  1. 関数数: 10個 → サイズ大きい
  2. 責務の混在: Free, Allocation, Magazine, Remote queue all mixed
  3. 再利用性: Allocation 関数は独立可能
  4. テスト容易性: Remote queue と同期ロジックは隔離可能
  5. メンテナンス性: 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 最適化時の影響範囲を限定