# TINY_C7_ULTRA_DESIGN ## 目的 - C7 (1024B) 向け mimalloc 型超高速パス(ULTRA)を用意し、Mixed 16–1024B を mimalloc の 5 割近辺まで寄せる。 - 学習層や stats の仕組みは残しつつ、C7 同一スレッドのホットパスからは極力それらを排除する。 ## 箱構造 - Hot: TinyC7UltraBox(TLS freelist + C7 専用セグメントを握る同一スレッド専用箱) - Cold: C7UltraSegmentBox(C7 専用セグメント管理。現段階では設計のみで未実装) - 既存 Cold: Superslab / WarmPool / Guard / Remote / Stats は既存の箱のまま。ULTRA は原則触らない。 ## 決定事項(芯) 1. C7 専用ページ源 - ULTRA は「C7 専用セグメント」からページを取る(将来は mmap で 2〜4MiB 単位)。 - v3/v4/Tiny v1 が握る C7 ページとは混ざらない前提。 - UF-1 時点では C7UltraSegmentBox は未実装で、C7 ページ供給は既存 v3 経由の stub とする。 2. free 時の ptr→page - ULTRA が扱う C7 ページは C7 専用セグメント上にのみ存在すると決める。 - 将来像: - seg = p & ~(SEG_SIZE-1) で segment 基底。 - seg が ULTRA 管理表にあれば offset / page_idx / page_meta から class=7 を取得し、ヘッダなしで freelist push。 - 管理表に無ければ既存 v3/v4 free(ヘッダあり)にフォールバック。 3. ULTRA と v3/v4 の責務分離 - ULTRA ON: C7 アロケーションはすべて ULTRA 管理(v3/v4 は C7 ページを新規に取らない)。 - ULTRA OFF: C7 は v3(現行本命)か v4 が処理する。 - free: 「まず ULTRA セグメントか?」を判定し、ULTRA 管理外なら常に v3/v4 free へ落とすオーバーレイ構造。 - Remote/cross-thread free は ULTRA 非対応。ULTRA は同一スレッド C7 専用 TLS box として設計。 4. Fail-Fast ポリシー - ULTRA が扱わないポインタは必ず v3/v4 側でヘッダ検証・範囲チェックを行う。 - ULTRA 内部不整合(将来フェーズ)は stats+ワンショットログで可視化し、可能なら v3/v4 へフォールバック。 ## セグメント前提(UF-3 仕様) - SEG_SIZE: 2MiB (pow2)。seg_base = ptr & ~(SEG_SIZE-1) で判定可能にする。 - セグメント構造(イメージ): - base, seg_size (=2MiB), page_size (=TINY_PAGE_SIZE 想定), num_pages (=seg_size/page_size) - page_meta[num_pages](freelist/used/capacity だけを持つ軽量構造) - free 時の判定: - seg = p & ~(SEG_SIZE-1) で ULTRA 管理セグメントか確認。 - 管理外 → v3 free(ヘッダ付き経路)へフォールバック。 - 管理内 → page_idx = (p - seg_base) >> PAGE_SHIFT で page_meta を取得し、ヘッダ無しで freelist push。 - Remote/cross-thread free は UF-3 でも非対応(同一スレッド C7 専用のまま)。 ## UF-4: C7 ULTRA header light(研究箱) - 目的: C7 ULTRA の alloc/free から tiny_region_id_write_header の毎回実行を外し、carve 時だけに寄せる。 - 手段: freelist の next をヘッダ直後に格納してヘッダを保持し、ENV `HAKMEM_TINY_C7_ULTRA_HEADER_LIGHT` (default 0) ON のときだけ carve 時に一括書き込み。alloc はヘッダ済みならスキップ。 - Fail-Fast: ULTRA 管理外 ptr は従来どおり v3 free 経路へ落とす。 ## フェーズ - UF-1: 箱・ENV・front フックだけ stub で入れる(中身は v3 C7 経由、挙動変化なし)。 - UF-2: ULTRA TLS freelist を実装(C7 ページ 1 枚を TLS で握る。同一スレッドのみ)。C7 ページ供給は当面 v3/v4 経由。 - UF-3: C7UltraSegmentBox を実装し、ptr→segment mask でヘッダレス free に寄せる(セグメント 1 枚のみでも可)。 - UF-4: C7 ULTRA header light を研究箱として追加し、ON/OFF A/B(Mixed / C7-only 両方)で評価する。 --- ## Phase PERF-ULTRA-ALLOC-OPT-1: C7 ULTRA alloc 内部最適化(実装予定) ### 背景(Phase PERF-ULTRA-REBASE-1 の発見) 2025-12-11 の perf 計測(C4-C7 ULTRA 全て ON)で以下が判明: **ホットパス分析結果** (allocator 内部, self%): - **C7 ULTRA alloc: 7.66%** ← **新しい最大ボトルネック** - C4-C7 ULTRA free群: 5.41% - gate/front前段: 2.51% ← **既に十分薄い** - header: < 0.17% ← **ULTRA 経路での削減効果が出ている** ### 結論 **v6/v5/v4 のような新世代追加ではなく、既に当たりが出ている ULTRA 内部を薄くする方針に転換**。 - v6/v5 の C5/C4 拡張は -12〜33% の大幅回帰を招いた - header や gate/front は既に改善済み(許容範囲) - **C7 ULTRA alloc の 7.66% を 5-6% に削れば、全体で 2-3% の効果が期待できる** ### 実装施策 **ターゲット**: `tiny_c7_ultra_alloc()` の hot path を直線化 1. **TLS ヒットパスの直線化** - env check が残っていないか確認(lazy init 後は ENV 参照すべきではない) - snapshot 取得が hot path に含まれていないか確認 - fast path を完全に直線化(分岐最小化) 2. **TLS freelist レイアウト最適化** - freelist[], count などのホットデータが 1 cache line に収まるか確認 - alloc ホットデータ(freelist[], count)の配置を L1 キャッシュ友好的に再配置 3. **segment / page_meta アクセスの確認** - segment learning / page_meta access が本当に slow path(キャッシュミス時)だけか確認 - hot path に余分なメモリアクセスが混入していないか確認 ### 計測戦略 **A/B テスト**: - C7-only(1024B固定)と Mixed(16-1024B)の両方で計測 - enabler: HAKMEM_TINY_C7_ULTRA_FREE_ENABLED=1 **perf 計測**: - 最適化前後で `perf report --stdio` により self% が 7.66% → 5-6% まで落ちるか確認 - throughput 改善量(ops/s)を測定 ### 期待値 - **alloc パス**: 5-10% の削減(self% 2% 削減で全体効果 2-3%) - **全体 Mixed throughput**: +2-3M ops/s(31.6M ops/s → 33-35M ops/s 想定) ### 次ステップ 1. 実装完了後、perf 再計測で効果を検証 2. self% が 5-6% に達したら次フェーズ(C4-C7 ULTRA free群 5.41% の軽量化)へ 3. それ以上の改善は narrow point(page_of/segment 判定, so_alloc系)の検討が必要 --- ## Phase PERF-ULTRA-ALLOC-OPT-1 実装完了 (2025-12-11) ### 設計判断 **方針転換**: 寄生型の C7 ULTRA_FREE_BOX は設計的に不整合と判断し撤去 - C7 ULTRA は C4/C5/C6 ULTRA と異なり、専用 segment + TLS を持つ独立サブシステム - 寄生型パターンは他の ULTRA クラスには適用可能だが、C7 には不適合 - **C7 は tiny_c7_ultra.c 内部だけで最適化する方針に切り替え** ### 実装内容 1. **寄生型パスの削除** - `core/box/tiny_c7_ultra_free_box.{h,c}` を削除 - `core/box/tiny_c7_ultra_free_env_box.h` を削除 - Makefile から `tiny_c7_ultra_free_box.o` を削除 - malloc_tiny_fast.h を元の `tiny_c7_ultra_alloc()` / `tiny_c7_ultra_free()` 呼び出しに戻す 2. **TLS 構造の最適化** (`tiny_c7_ultra_box.h`) - **count を struct の先頭に移動** (L1 cache locality 向上) - 配列ベース TLS キャッシュに変更(capacity=128, C6 と同じ) - freelist: linked-list → BASE pointer 配列に変更 - cold フィールド(seg_base/seg_end/segment meta)を後方に配置 3. **alloc の純 TLS pop 化** (`tiny_c7_ultra.c`) - **hot path: 1 分岐のみ** (count > 0) - TLS access は 1 回のみ(ctx に cache) - ENV check を呼び出し側(malloc_tiny_fast.h)に移動 - segment/page_meta アクセスは refill 時(cold path)のみ 4. **free の UF-3 segment learning 維持** - 最初の free で segment 学習(seg_base/seg_end を TLS に記憶) - 以降は seg_base/seg_end 範囲チェック → TLS push - 範囲外は v3 free にフォールバック ### 実測値 (Mixed 16-1024B, 1M iter, ws=400) **Perf profile (self%)**: - `tiny_c7_ultra_alloc`: **7.66%** (維持 - 既に最適化済み) - `tiny_c7_ultra_free`: **3.50%** - Throughput: **43.5M ops/s** (1M iterations) **注**: 今回の実装で内部構造を array-based に変更し、pure TLS pop パターンに統一したが、 perf self% は baseline と同等。これは元の linked-list 実装も既に効率的だったことを示す。 今後の最適化は refill ロジック(segment 取得部分)や page_meta 管理の軽量化が必要。 ### 評価 **部分達成**: - 寄生型パターンの撤回による設計一貫性の回復: **成功** - Array-based TLS cache への移行: **成功** - pure TLS pop パターンへの統一: **成功** - perf self% 削減(7.66% → 5-6%): **未達成** (既に最適) **次のアクション**: 1. refill path の最適化(segment 取得の軽量化) 2. page_meta 管理の簡略化(bitmap 化など) 3. C4-C7 ULTRA free 群(5.41%)の最適化に移行 --- ## 設計整理: C7 独立 vs C4/C5/C6 寄生 **C7 ULTRA**: 独立サブシステム(tiny_c7_ultra.c に閉じた segment + TLS) - 専用の segment 管理(2MiB Segment / 64KiB Page) - 独自の TLS context(freelist + page_meta + segment pointers) - alloc/free/refill が全て tiny_c7_ultra.c 内で完結 - 既存 allocator(v1/v3/pool)には依存しない(fallback 時を除く) **C4/C5/C6 ULTRA**: 寄生型(既存 allocator 上の TLS cache) - 専用 segment は持たない - 既存 allocator(v1/v3/pool)に「寄生」して TLS キャッシュだけ追加 - free 時に TLS push、alloc 時に TLS pop(キャッシュミス時は既存 allocator へ fallback) - minimal overhead で既存パスに統合可能 次フェーズ(PERF-ULTRA-FREE-OPT-1)では、これら ULTRA の free 側(TLS push パス)を統一された形に薄くする。