Files
hakmem/docs/PHASE2_HEADERLESS_INSTRUCTION_FOR_GEMINI.md
Moe Charm (CI) 2f09f3cba8 Add Phase 2 Headerless implementation instruction for Gemini
Phase 2 Goal: Eliminate inline headers for C standard alignment compliance

Tasks (7 total):
- Task 2.1: Add A/B toggle flag (HAKMEM_TINY_HEADERLESS)
- Task 2.2: Update ptr_conversion_box.h for Headerless mode
- Task 2.3: Modify HAK_RET_ALLOC macro (skip header write)
- Task 2.4: Update Free path (class_idx from SuperSlab Registry)
- Task 2.5: Update tiny_nextptr.h for Headerless
- Task 2.6: Update TLS SLL (skip header validation)
- Task 2.7: Integration testing

Expected Results:
- malloc(15) returns 16B-aligned address (not odd)
- TLS_SLL_HDR_RESET eliminated in sh8bench
- Zero overhead in Release build
- A/B toggle for gradual rollout

Design:
- Before: user = base + 1 (odd address)
- After:  user = base + 0 (aligned!)
- Free path: class_idx from SuperSlab Registry (no header)

🤖 Generated with Claude Code

Co-Authored-By: Gemini <gemini@example.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 11:41:34 +09:00

13 KiB
Raw Blame History

Phase 2: Headerless化 実装指示書

Version: 1.0 (2025-12-03) Status: Phase 1 完了、Phase 2 開始準備完了


🎯 目標

Headerless Tiny Allocator を実装し、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 から取得

// 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

実装内容:

// 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

実装内容:

// 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

実装内容:

// 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 または関連ファイル

確認すべき既存コード:

// 現在のコード(推定)
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 対応:

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

確認ポイント:

// 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: 発生しなくなる(ヘッダーがないため)
// 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 モードの動作検証

テスト手順:

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 から取得します。 これは現在のアーキテクチャで既にサポートされているはずですが、確認が必要です。

// 確認コマンド
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
ビルド 成功 両モードでエラーなし

📞 進捗報告形式

各タスク完了時:

## Task [番号] 完了レポート

**実装内容**:
- 修正ファイル: ...
- 主な変更: ...

**テスト結果**:
- Headerless ビルド: ✅/❌
- Phase 1 互換ビルド: ✅/❌
- TLS_SLL_HDR_RESET: 発生なし/発生あり

**備考**:
- 予期しない課題: ...
- 追加の検討事項: ...

🎁 最終ゴール

Phase 2 完了後の理想形:

// 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 の実力に期待しています。よろしくお願いします!🚀