# Phase 2: Headerless化 実装指示書 Version: 1.0 (2025-12-03) Status: Phase 1 完了、Phase 2 開始準備完了 --- ## 🎯 目標 **Headerless Tiny Allocator** を実装し、C標準のアラインメント保証を達成する。 ### ゴール ```c // 現在(Phase 1) malloc(15) → 0x...0001 (奇数アドレス = base + 1) // Phase 2 完了後 malloc(15) → 0x...0000 (16B aligned = base + 0) ``` ### 成功基準 1. ✅ Release ビルドで `user_ptr = base` (ゼロオーバーヘッド) 2. ✅ 全クラス (0-7) で 16B アラインメント保証 3. ✅ sh8bench で TLS_SLL_HDR_RESET が発生しない 4. ✅ cfrac, larson で回帰なし 5. ✅ パフォーマンス低下 ≤ 5% --- ## 📋 設計概要 ### Before (Phase 1: Inline Header) ``` Block Layout (Class 1, 16B stride): ┌─────────┬────────────────────────────┐ │Header 1B│ User Payload 15B │ └─────────┴────────────────────────────┘ ↑ base ↑ user = base + 1 (奇数!) ``` ### After (Phase 2: Headerless) ``` Block Layout (Class 1, 16B stride): ┌──────────────────────────────────────┐ │ User Payload 16B │ └──────────────────────────────────────┘ ↑ base = user (16B aligned!) Free時のみ: ┌──────────────────────────────────────┐ │ Next Ptr (8B) │ Unused (8B) │ └──────────────────────────────────────┘ ↑ base (freelist linkage) ``` ### class_idx の取得方法 **Allocated 時**: Headerなし → class_idx は SuperSlab Registry から取得 ```c // Free時の処理 void hak_free(void* user_ptr) { // Step 1: user = base (Headerless) void* base = user_ptr; // Step 2: SuperSlab Registry から class_idx を取得 SuperSlab* ss = hak_super_lookup((uintptr_t)base); int class_idx = ss->class_idx; // ← ここが重要 // Step 3: 通常のfree処理 // ... } ``` --- ## 📝 実装タスク(優先度順) ### Task 2.1: A/B切替フラグ追加 ⭐⭐⭐ (CRITICAL) **目的**: Headerless 化を段階的に導入可能にする **場所**: `core/box/tiny_layout_box.h` **実装内容**: ```c // core/box/tiny_layout_box.h に追加 // A/B Toggle: Headerless mode // ENV: HAKMEM_TINY_HEADERLESS=1 で有効化 // Default: 0 (Phase 1互換) #ifndef HAKMEM_TINY_HEADERLESS #define HAKMEM_TINY_HEADERLESS 0 #endif // User offset: Headerless時は0, Header時は1 static inline size_t tiny_user_offset(int class_idx) { #if HAKMEM_TINY_HEADERLESS (void)class_idx; return 0; // Headerless: user = base #else // Phase 1互換: Class 0-6 = 1, Class 7 = 0 return (0x7Eu >> class_idx) & 1u; #endif } // Header size: Headerless時は0 static inline size_t tiny_header_size(int class_idx) { #if HAKMEM_TINY_HEADERLESS (void)class_idx; return 0; #else return (0x7Eu >> class_idx) & 1u; #endif } ``` **提出物**: - [ ] `tiny_layout_box.h` に A/B フラグ追加 - [ ] ビルド確認: `make shared EXTRA_CFLAGS="-DHAKMEM_TINY_HEADERLESS=1"` - [ ] ビルド確認: `make shared` (デフォルト = Phase 1互換) --- ### Task 2.2: ptr_conversion_box.h Headerless対応 ⭐⭐⭐ (CRITICAL) **目的**: ポインタ変換を Headerless モードに対応 **場所**: `core/box/ptr_conversion_box.h` **実装内容**: ```c // core/box/ptr_conversion_box.h 修正 #include "tiny_layout_box.h" // BASE → USER 変換 static inline void* ptr_base_to_user(void* base_ptr, uint8_t class_idx) { if (base_ptr == NULL) return NULL; #if HAKMEM_TINY_HEADERLESS // Headerless: user = base (identity) (void)class_idx; return base_ptr; #else // Phase 1: user = base + offset size_t offset = tiny_user_offset(class_idx); return (void*)((uint8_t*)base_ptr + offset); #endif } // USER → BASE 変換 static inline void* ptr_user_to_base(void* user_ptr, uint8_t class_idx) { if (user_ptr == NULL) return NULL; #if HAKMEM_TINY_HEADERLESS // Headerless: base = user (identity) (void)class_idx; return user_ptr; #else // Phase 1: base = user - offset size_t offset = tiny_user_offset(class_idx); return (void*)((uint8_t*)user_ptr - offset); #endif } ``` **提出物**: - [ ] `ptr_conversion_box.h` 修正完了 - [ ] Headerless ビルドでテスト - [ ] Phase 1 互換ビルドでテスト(回帰なし) --- ### Task 2.3: HAK_RET_ALLOC マクロ修正 ⭐⭐⭐ (CRITICAL) **目的**: Allocation パスを Headerless 対応に **場所**: `core/hakmem_tiny_config_box.inc` **実装内容**: ```c // core/hakmem_tiny_config_box.inc 修正 #if HAKMEM_TINY_HEADERLESS // Headerless: ヘッダー書き込み不要、user = base #define HAK_RET_ALLOC(base, cls) do { \ /* No header write needed */ \ return (base); \ } while(0) #else // Phase 1: ヘッダー書き込み + user = base + offset #define HAK_RET_ALLOC(base, cls) do { \ tiny_header_write((base), (cls)); \ return ptr_base_to_user((base), (cls)); \ } while(0) #endif ``` **提出物**: - [ ] `HAK_RET_ALLOC` マクロ修正完了 - [ ] Headerless: ヘッダー書き込みがスキップされることを確認 - [ ] Phase 1: 既存動作と同一であることを確認 --- ### Task 2.4: Free パス修正 ⭐⭐⭐ (CRITICAL) **目的**: Free 時の class_idx 取得を SuperSlab Registry 経由に **場所**: `core/hakmem_tiny_free.inc` または関連ファイル **確認すべき既存コード**: ```c // 現在のコード(推定) void hak_tiny_free(void* user_ptr) { // Step 1: user → base 変換 void* base = ptr_user_to_base(user_ptr, ???); // ← class_idx が必要! // 現在: ヘッダーから class_idx を読み取り int class_idx = *(uint8_t*)base & 0x0F; // ... } ``` **Headerless 対応**: ```c void hak_tiny_free(void* user_ptr) { #if HAKMEM_TINY_HEADERLESS // Headerless: user = base void* base = user_ptr; // SuperSlab Registry から class_idx を取得 SuperSlab* ss = hak_super_lookup((uintptr_t)base); if (!ss) { // エラー処理: Unknown pointer return; } int class_idx = ss->class_idx; #else // Phase 1: ヘッダーから取得 void* base = ptr_user_to_base(user_ptr, 0); // 仮の class_idx int class_idx = tiny_header_read_class(base); base = ptr_user_to_base(user_ptr, class_idx); // 正しい base #endif // 共通処理 // ... } ``` **重要**: SuperSlab に `class_idx` フィールドがあるか確認してください。 なければ追加が必要です。 **提出物**: - [ ] Free パスの現状調査レポート - [ ] class_idx 取得方法の決定 - [ ] 修正済みコード - [ ] テスト結果 --- ### Task 2.5: tiny_nextptr.h Headerless対応 ⭐⭐ (HIGH) **目的**: Next pointer 操作を Headerless モードに対応 **場所**: `core/tiny_nextptr.h` **確認ポイント**: ```c // tiny_next_off() の Headerless 対応 static inline size_t tiny_next_off(int class_idx) { #if HAKMEM_TINY_HEADERLESS // Headerless: 全クラスで offset = 0 (void)class_idx; return 0; #else // Phase 1: C0,C7 = 0, C1-C6 = 1 return (0x7Eu >> class_idx) & 1u; #endif } ``` **提出物**: - [ ] `tiny_nextptr.h` 修正完了 - [ ] Freelist 操作のテスト --- ### Task 2.6: TLS SLL Headerless対応 ⭐⭐ (HIGH) **目的**: TLS SLL push/pop を Headerless 対応に **場所**: `core/box/tls_sll_box.h` **修正ポイント**: 1. **Push 時**: ヘッダー書き込みをスキップ (Headerless時) 2. **Pop 時**: ヘッダー検証をスキップ (Headerless時) 3. **TLS_SLL_HDR_RESET**: 発生しなくなる(ヘッダーがないため) ```c // tls_sll_push_impl 修正 static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, ...) { // ... #if !HAKMEM_TINY_HEADERLESS // Phase 1: ヘッダー書き込み *(uint8_t*)b = (uint8_t)(0xa0 | (class_idx & 0x0f)); __atomic_thread_fence(__ATOMIC_RELEASE); #endif // ... } // tls_sll_pop_impl 修正 static inline bool tls_sll_pop_impl(int class_idx, hak_base_ptr_t* out, ...) { // ... #if !HAKMEM_TINY_HEADERLESS // Phase 1: ヘッダー検証 uint8_t got = *(uint8_t*)raw_base; uint8_t expect = (uint8_t)(0xa0 | (class_idx & 0x0f)); if (got != expect) { // TLS_SLL_HDR_RESET 処理 } #endif // ... } ``` **提出物**: - [ ] `tls_sll_box.h` 修正完了 - [ ] TLS_SLL_HDR_RESET が発生しないことを確認 (Headerless時) --- ### Task 2.7: 統合テスト ⭐⭐⭐ (CRITICAL) **目的**: Headerless モードの動作検証 **テスト手順**: ```bash cd /mnt/workdisk/public_share/hakmem # 1. Headerless ビルド find . -name "*.o" -delete && find . -name "*.so" -delete make shared -j8 EXTRA_CFLAGS="-DHAKMEM_TINY_HEADERLESS=1" # 2. sh8bench テスト(TLS_SLL_HDR_RESETが出ないことを確認) LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench 2>&1 | \ grep -E "TLS_SLL_HDR_RESET|Total|error" # 期待結果: # Total elapsed time for 8 threads: X.XX (XX.XX CPU) # [TLS_SLL_HDR_RESET] → 出力されない! # 3. cfrac テスト LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/cfrac 2>&1 | \ grep -E "error|Error|SEGV" # 4. larson テスト LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/larson 8 2>&1 | \ grep -E "error|Error|SEGV" # 5. Phase 1 互換ビルド(回帰テスト) find . -name "*.o" -delete && find . -name "*.so" -delete make shared -j8 # デフォルト = Headerless OFF LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench 2>&1 | \ grep -E "TLS_SLL_HDR_RESET|Total" # → TLS_SLL_HDR_RESET は出る(既存動作) ``` **提出物**: - [ ] Headerless ビルドのテスト結果 - [ ] Phase 1 互換ビルドの回帰テスト結果 - [ ] パフォーマンス比較(可能であれば) --- ## 🔄 段階的移行計画 ### Step 1: A/B フラグ導入 (Task 2.1) ``` HAKMEM_TINY_HEADERLESS=0 → Phase 1 互換(デフォルト) HAKMEM_TINY_HEADERLESS=1 → Headerless モード ``` ### Step 2: Core 修正 (Task 2.2-2.6) ``` 各コンポーネントを #if HAKMEM_TINY_HEADERLESS で分岐 ``` ### Step 3: 統合テスト (Task 2.7) ``` 両モードでテスト、回帰なし確認 ``` ### Step 4: デフォルト切替(将来) ``` Headerless モードをデフォルトに変更 Phase 1 コードを削除(または Legacy として維持) ``` --- ## ⚠️ 注意点 ### SuperSlab Registry への依存 Headerless モードでは、`free()` 時に class_idx を SuperSlab から取得します。 これは現在のアーキテクチャで既にサポートされているはずですが、確認が必要です。 ```c // 確認コマンド grep -n "class_idx\|size_class" core/superslab/*.h core/hakmem_super_registry.c ``` もし SuperSlab に class_idx がない場合: 1. `SuperSlab` 構造体に `uint8_t class_idx` フィールドを追加 2. Slab 作成時に class_idx を設定 ### パフォーマンス考慮 Headerless モードでは: - ✅ Allocation: ヘッダー書き込み削減 → 高速化 - ⚠️ Free: SuperSlab lookup 必要 → 若干のコスト 全体としてはトレードオフですが、lookup は既に実装されているため影響は最小限のはずです。 --- ## 📊 成功指標 | 指標 | 目標値 | 測定方法 | |------|--------|----------| | TLS_SLL_HDR_RESET | 0件 | sh8bench実行時 | | アラインメント | 16B | `malloc(15)` の戻り値 % 16 == 0 | | パフォーマンス | ≤ 5% 低下 | sh8bench 実行時間 | | 回帰テスト | 全Pass | cfrac, larson | | ビルド | 成功 | 両モードでエラーなし | --- ## 📞 進捗報告形式 各タスク完了時: ```markdown ## Task [番号] 完了レポート **実装内容**: - 修正ファイル: ... - 主な変更: ... **テスト結果**: - Headerless ビルド: ✅/❌ - Phase 1 互換ビルド: ✅/❌ - TLS_SLL_HDR_RESET: 発生なし/発生あり **備考**: - 予期しない課題: ... - 追加の検討事項: ... ``` --- ## 🎁 最終ゴール Phase 2 完了後の理想形: ```c // Release ビルド(Headerless) void* ptr = malloc(15); // ptr = 0x7f...0000 (16B aligned!) // オーバーヘッド: 0 free(ptr); // SuperSlab lookup → class_idx 取得 → freelist へ // sh8bench: TLS_SLL_HDR_RESET なし! // パフォーマンス: Phase 1 と同等以上 ``` --- ## 参考資料 - `docs/REFACTOR_PLAN_GEMINI_ENHANCED.md` - 全体計画 - `docs/REFACTORING_INSTRUCTION_FOR_GEMINI.md` - Phase 1 指示書 - `docs/tls_sll_hdr_reset_final_report.md` - 根本原因分析 - `core/box/tiny_layout_box.h` - Phase 1 で作成したレイアウト Box - `core/box/ptr_conversion_box.h` - Phase 1 で修正したポインタ変換 Box --- Phase 2 の成功で、hakmem は C 標準準拠の高性能アロケータに進化します! Gemini の実力に期待しています。よろしくお願いします!🚀