Files
hakmem/docs/analysis/PHASE13_HEADER_WRITE_ELIMINATION_1_DESIGN.md
Moe Charm (CI) cbb35ee27f Phase 13 v1 + E5-2 retest: Both NEUTRAL, freeze as research boxes
Phase 13 v1: Header Write Elimination (C7 preserve header)
- Verdict: NEUTRAL (+0.78%)
- Implementation: HAKMEM_TINY_C7_PRESERVE_HEADER ENV gate (default OFF)
- Makes C7 nextptr offset conditional (0→1 when enabled)
- 4-point matrix A/B test results:
  * Case A (baseline): 51.49M ops/s
  * Case B (WRITE_ONCE=1): 52.07M ops/s (+1.13%)
  * Case C (C7_PRESERVE=1): 51.36M ops/s (-0.26%)
  * Case D (both): 51.89M ops/s (+0.78% NEUTRAL)
- Action: Freeze as research box (default OFF, manual opt-in)

Phase 5 E5-2: Header Write-Once retest (promotion test)
- Verdict: NEUTRAL (+0.54%)
- Motivation: Phase 13 Case B showed +1.13%, re-tested with dedicated 20-run
- Results (20-run):
  * Case A (baseline): 51.10M ops/s
  * Case B (WRITE_ONCE=1): 51.37M ops/s (+0.54%)
- Previous test: +0.45% (consistent with NEUTRAL)
- Action: Keep as research box (default OFF, manual opt-in)

Key findings:
- Header write tax optimization shows consistent NEUTRAL results
- Neither Phase 13 v1 nor E5-2 reaches GO threshold (+1.0%)
- Both implemented as reversible ENV gates for future research

Files changed:
- New: core/box/tiny_c7_preserve_header_env_box.{c,h}
- Modified: core/box/tiny_layout_box.h (C7 offset conditional)
- Modified: core/tiny_nextptr.h, core/box/tiny_header_box.h (comments)
- Modified: core/bench_profile.h (refresh sync)
- Modified: Makefile (add new .o files)
- Modified: scripts/run_mixed_10_cleanenv.sh (add C7_PRESERVE ENV)
- Docs: PHASE13_*, PHASE5_E5_2_HEADER_WRITE_ONCE_* (design/results)

Next: Phase 14 (Pointer-chase reduction, tcache-style intrusive LIFO)

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 00:32:25 +09:00

6.1 KiB
Raw Blame History

Phase 13: Header Write Elimination v1C7 Header-Preserving Freelist

Date: 2025-12-14
Status: DESIGNPhase 13 kickoff NEUTRAL (+0.78%)research box freeze, default OFF


0. Executive Summary1枚

Phase 12 の比較で system malloc (glibc) が hakmem より +63.7% 速いことが判明し、次の大きい構造差として “steady-state のヘッダ書き込みwrite tax が最優先仮説になった。

ただし hakmem は free の hot path で HEADER_MAGIC を前提に ヘッダを読むため、ヘッダを “無くす/壊す” と安全性が崩れる。

そこで Phase 13 v1 は「ヘッダ自体は維持」しつつ、C7 の freelist でヘッダを上書きしない設計に寄せて、既存の E5-2 (Header write-once)C7 にも適用可能にする

狙い:

  • C1-C6 は既に write-once で “alloc 時ヘッダ書き込み” をスキップ可能
  • C7 は現状 “free の next がヘッダを潰す” ため、alloc で毎回ヘッダ再書き込みが必要
  • C7 の next を **base+1user 先頭)**へ移すとヘッダが保持され、write-once で alloc 側の再書き込みを削れる

1. 現状(なぜ C7 だけ毎回書いているのか)

1.1 重要な前提(現行の正)

  • Free hot path例: core/front/malloc_tiny_fast.hfree_tiny_fast())は、
    • ptr-1HEADER_MAGIC を検証し
    • class_idx を header から抽出している
      ヘッダの正しさは safety と fast path の前提

1.2 E5-2 (Header write-once) の適用範囲

  • core/box/tiny_header_box.htiny_header_finalize_alloc() が、
    • HAKMEM_TINY_HEADER_WRITE_ONCE=1 かつ
    • tiny_class_preserves_header(class_idx)=trueC1-C6 のとき、alloc 時の tiny_region_id_write_header() をスキップする。

1.3 C7 が write-once にならない理由(根本)

  • core/box/tiny_layout_box.htiny_nextptr_offset()
    • C7 は next_off=0= base+0 に next を書く)
      → free 時に ヘッダ領域を next pointer で上書きする
      → alloc で必ず tiny_region_id_write_header() を実行し直す必要がある

C0 も同じだが、C0 は stride 8B のため base+1 に 8B next を置けない制約がある)


2. 提案Phase 13 v1

2.1 変更のコア

C7 の next pointer を base+1user 先頭)に移す:

  • Before現行:
    • C7: next_off=0*(void**)base = next(ヘッダ破壊)
  • AfterPhase 13 v1:
    • C7: next_off=1memcpy(base+1, &next, 8)(ヘッダ保持)

これにより C7 が “header-preserving class” になり、E5-2 の write-once が C7 にも効く。

2.2 Box Theory箱割り

L0: tiny_c7_preserve_header_env_box  (ENV gate, A/B, refresh)
  ↓
L1: tiny_layout_box                  (tiny_nextptr_offset の SSOT)
  ↓
L2: tiny_nextptr                     (next load/store は SSOT を参照)
  ↓
L3: tiny_header_box                  (class_preserves_header → write-once 適用)

境界は 1 箇所:

  • 「C7 の next オフセット決定」= tiny_nextptr_offset() に集約(他で分岐しない)

2.3 戻せるA/B

  • ENV: HAKMEM_TINY_C7_PRESERVE_HEADER=0/1default: 0
  • まずは research box として導入し、GO なら preset 昇格

3. Safety / InvariantsFail-Fast

3.1 不変条件

  • tiny_next_store/load常に tiny_nextptr_offset() を参照(直書き禁止)
  • tiny_class_preserves_header(class_idx) は offset!=0 で決まる(ハードコード禁止)
  • C7 preserve ON のとき:
    • free 後も *(uint8_t*)base == HEADER_MAGIC|cls が保持される(ヘッダ破壊が起きない)

3.2 Fail-Fastdebug 限定)

  • デバッグのみ、C7 preserve ON のときに:
    • tiny_header_validate(base, 7, ...) の mismatch をワンショットで出す
  • release では常時ログ無し、必要なら stats カウンタのみ

4. A/B 計測計画(同一バイナリ)

この変更は “freelist next の配置” を変えるため、本来は layout 差になるが、Phase 13 v1 は ENV で切替できるようにして同一バイナリ A/B を維持するPhase 5-7 の教訓)。

4.1 4点マトリクス必須

Case HAKMEM_TINY_C7_PRESERVE_HEADER HAKMEM_TINY_HEADER_WRITE_ONCE 意味
A 0 0 現行 baseline
B 0 1 E5-2 のみC1-C6
C 1 0 C7 next を user に移す(ヘッダは毎回書く)
D 1 1 Phase 13 v1 本命C1-C7 を write-once

4.2 GO/NO-GOMixed 10-run

  • GO: mean +1.0% 以上
  • NO-GO: mean -1.0% 以下
  • NEUTRAL: ±1.0% → freezeresearch box

5. リスクと対策

リスク 1: C7 next が unaligned になり memcpy 経由で遅くなる

  • 対策: Case Cwrite-once 無しを必ず測り、layout 変更単体のコストを分離する
  • もし C が大きく負ける場合:
    • “C7 next offset=8aligned” の派生案を検討Phase 13 v1b

リスク 2: class_idx ハードコードが残っていて壊れる

  • 対策: rg "== 7|!= 7|C7 uses offset 0" を掃除し、SSOTtiny_layout_box)参照に寄せる

リスク 3: ENV refresh が bench_profile putenv に追従しない

  • 対策: Phase 8 と同様に *_env_refresh_from_env() を用意し、bench_profile.h から呼ぶ

6. 次Phase 13 以降の視界)

Phase 13 v1 は「ヘッダを “消す”」ではなく「steady-state のヘッダ再書き込みを減らす」に寄せる。

もし system malloc との差がまだ大きい場合、次の大テーマは:

  • Thread cachetcache 相当の構造)を TinyUnifiedCache に移植するPhase 14 候補)