Files
hakmem/docs/tls_sll_hdr_reset_for_gemini.md

366 lines
11 KiB
Markdown
Raw Normal View History

# TLS_SLL_HDR_RESET Root Cause Investigation (Gemini Edition)
## 背景
hakmemメモリアロケータのsh8benchで`[TLS_SLL_HDR_RESET]`エラーが継続発生しています。
これまでClaude Code、ChatGPT、Task agentが調査しましたが根治に至っていません。
Geminiに最終調査をお願いします。
## 現在の状況2025-12-03 commit 6154e7656
### ✅ 解決済み問題
1. **unified_cache_refill SEGVAULT** (commit 6154e7656)
- 根本原因: コンパイラ最適化による操作順序入れ替え
- 修正: ヘッダー書き込みをtiny_next_read()の前に移動 + atomic fence
- 状態: 完全解決、sh8bench実行可能に
2. **LRU registry未登録** (commit 4cc2d8add)
- 根本原因: LRU pop時にhak_super_register()未呼び出し
- 修正: LRU pop後に明示的に再登録
- 状態: 解決
3. **ChatGPTの「8bit右シフト圧縮ポインタ」仮説**
- Task agentが否定: 意図的な圧縮スキームは存在しない
- 真の原因: unified_cache_refillのコンパイラ最適化問題既に解決済み
### ❌ 未解決問題
**TLS_SLL_HDR_RESET エラー** - sh8benchで継続発生
```
[TLS_SLL_HDR_RESET] cls=1 base=0x71bcf31bd858 got=0x51 expect=0xa1 count=0
```
- **発生箇所**: `core/box/tls_sll_box.h:585` (TLS SLL pop時のヘッダー検証失敗)
- **期待値**: `0xa1` (class_idx=1のヘッダーマーカー)
- **実際値**: `0x51`, `0x61` など(破損)
- **動作**: SLL全体をリセット安全だが非効率
## エラーの詳細
### ヘッダーフォーマット
```
期待値: 0xa1
bit 7-4: 0xa (固定マーカー)
bit 3-0: 0x1 (サイズクラスインデックス)
```
### 破損パターン
```
got=0x51: 01010001 (未初期化メモリ?)
got=0x61: 01100001 ('a' ASCII文字)
got=0x00: 00000000 (mmap zero初期値)
```
### 発生パターン
-**sh8bench**: ほぼ毎回発生
-**リリース版**: 発生
-**cfrac, larson**: 発生しない
-**ASan版**: Task agent報告では未再現
## これまでの調査と既知の修正
### 既に修正済みの境界commit 3c6c76cb1, a94344c1a
以下の経路でのヘッダー復元は実装済み:
1. **box_carve_and_push_with_freelist()** (commit 3c6c76cb1)
```c
void* p = meta->freelist;
meta->freelist = tiny_next_read(class_idx, p);
tiny_header_write_if_preserved(p, class_idx); // ← 修正済み
if (!tls_sll_push(class_idx, p, sll_cap)) { ... }
```
2. **tiny_drain_freelist_to_sll_once()** (commit a94344c1a)
```c
void* p = m->freelist;
m->freelist = tiny_next_read(class_idx, p);
tiny_header_write_if_preserved(p, class_idx); // ← 修正済み
if (tls_sll_push(class_idx, HAK_BASE_FROM_RAW(p), sll_capacity)) { ... }
```
### 現在の設定commit 6154e7656
- ✅ ヘッダー書き込みデフォルトON (`g_write_header=1`)
- ✅ HAKMEM_TINY_WRITE_HEADER=0 で旧挙動に戻せるA/B切替
## Geminiへの調査依頼
### 調査の焦点
**「なぜsh8benchだけでTLS_SLL_HDR_RESETが発生するのか」**
cfrac/larsonでは発生しないことから、**sh8bench固有のアクセスパターン**に起因する経路がある可能性が高いです。
### 仮説(優先度順)
#### 仮説1: TLS SLL push時のヘッダー未書き込み最有力
**コード箇所**: `core/box/tls_sll_box.h``tiny_tls_sll_push()`
**確認すべきこと**:
1. push時に本当にヘッダーを書き込んでいるか
```c
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
```
2. 書き込み順序は正しいか?
- next pointer書き込みの**前**にヘッダー書き込み
- atomic fence有無
3. 条件分岐で書き込みをスキップしていないか?
**調査方法**:
```bash
grep -n "static inline.*tiny_tls_sll_push" -A 100 core/box/tls_sll_box.h | \
grep -E "raw_base.*=.*0xa0|class_idx"
```
#### 仮説2: unified_cache経由の未発見経路
**背景**:
- unified_cache_refillでヘッダーを書き込み済みP1修正
- しかしその後、**別の経路**でTLS SLLに入る可能性
**確認すべきこと**:
1. unified_cache_refillで返されたポインタがfree時にどの経路を通るか
2. その経路でヘッダーが保持されているか
3. TLS SLLに入る直前で破損していないか
**調査方法**:
```bash
# unified_cache関連のfree/drain経路
grep -n "unified_cache.*drain\|unified_cache.*free" \
core/front/tiny_unified_cache.c core/box/tiny_front_cold_box.h
```
#### 仮説3: sh8bench固有のマルチスレッド競合
**背景**:
- sh8benchは8スレッド並行
- 小さいブロックclass 1などを高速にalloc/free
**確認すべきこと**:
1. TLS SLL pushがスレッドセーフか
2. ヘッダー書き込みとnext pointer書き込みの間に競合窓がないか
3. `__atomic_thread_fence`の配置は適切か
**調査方法**:
```bash
# TLS SLL実装の同期機構確認
grep -n "thread_fence\|atomic\|mutex\|lock" core/box/tls_sll_box.h
```
## 具体的な調査手順
### Step 1: TLS SLL push実装の精査
```bash
cd /mnt/workdisk/public_share/hakmem
# push実装を確認
cat -n core/box/tls_sll_box.h | sed -n '450,550p'
```
**チェックポイント**:
- [ ] `*(uint8_t*)raw_base = 0xa0 | cls` が実行されているか
- [ ] `tiny_class_preserves_header(class_idx)` 条件は正しいか
- [ ] `__atomic_thread_fence(__ATOMIC_RELEASE)` があるか
- [ ] next pointer書き込みより**前**に実行されているか
### Step 2: 詳細ログで経路追跡
```bash
# デバッグビルド
find . -name "*.o" -delete && find . -name "*.so" -delete
make shared -j8 EXTRA_CFLAGS="-g -O1"
# リング有効化で実行
HAKMEM_TINY_SLL_RING=1 HAKMEM_DEBUG_LEVEL=3 \
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench \
2>&1 | tee sh8bench_gemini_debug.log
# push/pop/resetの順序を確認
grep -E "TLS_SLL_PUSH|TLS_SLL_POP|TLS_SLL_HDR_RESET" \
sh8bench_gemini_debug.log | head -100
```
### Step 3: コード修正テスト
**TLS SLL push強制ヘッダー書き込み**を試してください:
```c
// core/box/tls_sll_box.h の tiny_tls_sll_push() に追加
static inline bool tiny_tls_sll_push(int class_idx, void* raw_base, uint32_t capacity) {
// GEMINI FIX: Always write header before push
#if HAKMEM_TINY_HEADER_CLASSIDX
if (tiny_class_preserves_header(class_idx)) {
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
__atomic_thread_fence(__ATOMIC_RELEASE);
}
#endif
// 既存のpush処理...
}
```
**テスト**:
```bash
find . -name "*.o" -delete && make shared -j8
# 5回テスト
for i in {1..5}; do
echo "=== Run $i ==="
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench 2>&1 | \
grep -E "TLS_SLL_HDR_RESET|Total elapsed"
done
```
### Step 4: SAFEHEADER検証
```bash
HAKMEM_TINY_SLL_SAFEHEADER=1 HAKMEM_TINY_SLL_VALIDATE_HDR=1 \
HAKMEM_TINY_SLL_RING=1 HAKMEM_DEBUG_LEVEL=3 \
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench \
2>&1 | tee sh8bench_gemini_safeheader.log
# push時の不正検出
grep -E "TLS_SLL_PUSH_BAD_HDR|TLS_SLL_REJECT" sh8bench_gemini_safeheader.log
```
## 期待される成果物
### 1. 根本原因の特定
以下のいずれかを明確に:
- **パターンA**: TLS SLL push時にヘッダー未書き込み
- どの条件でスキップされているか
- 修正箇所の特定
- **パターンB**: 未発見の経路が存在
- どの経路か(コールスタック)
- その経路でのヘッダー復元漏れ
- **パターンC**: マルチスレッド競合
- 競合が発生する箇所
- atomic fence不足の箇所
### 2. 修正コード
修正が必要なファイルと具体的なコード変更を提示してください:
```c
// 例: core/box/tls_sll_box.h
// 修正前:
static inline bool tiny_tls_sll_push(...) {
// 既存コード
}
// 修正後:
static inline bool tiny_tls_sll_push(...) {
// GEMINI FIX: ヘッダー復元を追加
#if HAKMEM_TINY_HEADER_CLASSIDX
if (tiny_class_preserves_header(class_idx)) {
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
__atomic_thread_fence(__ATOMIC_RELEASE);
}
#endif
// 既存のpush処理
}
```
### 3. テスト結果
修正後のsh8bench実行結果
```bash
# 期待される結果
=== Run 1 ===
Total elapsed time for 8 threads: XX.XX (XXX.XXXX CPU)
# [TLS_SLL_HDR_RESET] なし
=== Run 2 ===
Total elapsed time for 8 threads: XX.XX (XXX.XXXX CPU)
# [TLS_SLL_HDR_RESET] なし
... 10回連続でエラーなし
```
## 重要な調査対象ファイル
**最優先**:
- `core/box/tls_sll_box.h` - TLS SLL push/pop実装行450-610
**次点**:
- `core/front/tiny_unified_cache.c` - unified cache実装
- `core/box/tiny_front_cold_box.h` - cold drain処理
- `core/hakmem_tiny_free.inc` - free経路
**参考**:
- `core/tiny_region_id.h` - ヘッダー書き込み設定
- `core/box/tiny_header_box.h` - ヘッダー管理API
## 環境変数・ビルド方法
### デバッグフラグ
```bash
HAKMEM_TINY_SLL_RING=1 # TLS SLLイベントログ
HAKMEM_TINY_SLL_VALIDATE_HDR=1 # push時ヘッダー検証
HAKMEM_TINY_SLL_SAFEHEADER=1 # 不正ヘッダーでpush拒否
HAKMEM_DEBUG_LEVEL=3 # 詳細ログ
HAKMEM_TINY_WRITE_HEADER=1 # ヘッダー書き込み強制既定でON
```
### ビルド
```bash
cd /mnt/workdisk/public_share/hakmem
# クリーンビルド(リリース版)
find . -name "*.o" -delete && find . -name "*.so" -delete
make shared -j8
# デバッグビルド
make shared -j8 EXTRA_CFLAGS="-g -O1 -UHAKMEM_BUILD_RELEASE"
```
## 参考資料
### 関連コミット
- `6154e7656` - unified_cache_refill SEGVAULT根治修正最新
- `4cc2d8add` - LRU registry未登録修正
- `f7d0d236e` - malloc_count最適化17s→10s
- `3c6c76cb1` - box_carve_and_push_with_freelistヘッダー復元
- `a94344c1a` - tiny_drain_freelist_to_sll_onceヘッダー復元
### ドキュメント
- `docs/tls_sll_header_corruption_investigation.md` - ChatGPT初回調査
- `docs/tls_sll_hdr_reset_investigation_v2.md` - 更新版調査指示書
- `docs/sh8bench_debug_instruction.md` - sh8benchデバッグ手順
---
## Geminiへのお願い
1. **Step 1-2で原因を特定**してください
- 特にTLS SLL push実装の精査が重要です
2. **Step 3で修正を実装**してください
- 修正後は必ずsh8benchで10回連続テストしてください
3. **根治であることを証明**してください
- 対処療法ではなく、真の根本原因を解決してください
4. **結果を報告**してください
- 修正したファイル、変更内容、テスト結果を明記してください
よろしくお願いします!🙏