Files
hakmem/docs/tls_sll_hdr_reset_for_gemini.md
2025-12-03 10:34:39 +09:00

11 KiB
Raw Blame 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)

    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)

    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.htiny_tls_sll_push()

確認すべきこと:

  1. push時に本当にヘッダーを書き込んでいるか

    *(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
    
  2. 書き込み順序は正しいか?

    • next pointer書き込みのにヘッダー書き込み
    • atomic fence有無
  3. 条件分岐で書き込みをスキップしていないか?

調査方法:

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に入る直前で破損していないか

調査方法:

# 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の配置は適切か

調査方法:

# TLS SLL実装の同期機構確認
grep -n "thread_fence\|atomic\|mutex\|lock" core/box/tls_sll_box.h

具体的な調査手順

Step 1: TLS SLL push実装の精査

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: 詳細ログで経路追跡

# デバッグビルド
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強制ヘッダー書き込みを試してください:

// 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処理...
}

テスト:

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検証

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. 修正コード

修正が必要なファイルと具体的なコード変更を提示してください:

// 例: 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実行結果

# 期待される結果
=== 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

環境変数・ビルド方法

デバッグフラグ

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

ビルド

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. 結果を報告してください

    • 修正したファイル、変更内容、テスト結果を明記してください

よろしくお願いします!🙏