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

519 lines
13 KiB
Markdown
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.

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