# 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. **結果を報告**してください - 修正したファイル、変更内容、テスト結果を明記してください よろしくお願いします!🙏