松田研究室
FindingID: a-7-icb-batching-plan
Status: draft / task A.7
← Findings Index
Plan · simpler batching

A.7 #5.32 ICB / per-iter command buffer commit reduction — 実装プラン

per-iter で 25+ 件の cmd.commit() があり、Apple Silicon GPU の schedule overhead (~0.3-0.7ms × N) が iter 全体の 20-50% を占める可能性。simpler batching (forward chain と backward chain をそれぞれ 1 cmd buffer に集約) を Option<&CommandBuffer> opt-in 形式で実装する計画。

neutralrank: midinvestigative第 3 軸phase-5icbcommand-bufferbatchingmetalapple-siliconplan
Δ Wallclock
target -10% (未検証)
Impact
forward / backward の各 chain を 1 cmd buffer に集約する simpler batching plan。期待効果 +15-30% wallclock 改善 (commit overhead 20-50% を集約)。スタイル A (Option<&CommandBuffer> opt-in) で既存テスト 23 件を touch せず実装。target -10% wallclock / PSNR drift < 0.05 dB。
01

本文

status: plan 起草 (2026-05-23)、実装 subagent 投入予定 (A.6 完了後)。user 判断: A.7 は「scope を縮小して simpler batching として実装」 (full ICB は thesis-scope 外)。

観測された問題

splat-train-v1/src/train_loop.rs の per-iter で、projector.project_soa, binner.emit_pairs, binner.radix_sort, binner.extract_offsets, rasterize.forward, loss.compute_l1_combine_ssim (or l1_only), rasterize.backward, project_backwards, adam.stepすべて個別に new_command_buffer() + commit + wait_until_completed している:

grep -rn "new_command_buffer\|cmd.commit" splat/crates/splat-metal/src/kernels/

で 25+ 件の cmd.commit() が確認できる (project: 3, tile_bin: 5, rasterize: 2, ssim: 2 x 2、loss: 多数、adam: 1)。

各 commit に Apple Silicon GPU の schedule overhead (~0.3-0.7 ms M4 Max 実測) が乗るため、iter ~25 ms のうち overhead 寄与は 5-12 ms (20-50%) が見込まれる。これを集約すれば +15-30% wallclock 改善の余地。

scope (simpler batching、full ICB は別案件)

やる:

  • forward path (project → tile_bin chain → rasterize forward) を 1 cmd buffer に統合
  • backward path (rasterize backward → project_backwards) を 1 cmd buffer に統合
  • adam を 1 cmd buffer (現状 1 commit なので touch しない)

やらない:

  • 真の ICB (MTLIndirectComputeCommandEncoder で dispatch 配列を pre-encoded buffer に保存して reuse) — 卒研範囲外、変動 splat 数で win が弱い
  • forward と backward を 同 cmd buffer に する (forward の rendered_buf を host loss path で読む必要がある場合がある、現状 GPU loss path で host readback ない → 可能だが複雑性増える、stretch)

実装方針

各 kernel method に「encode-only variant」を追加する。3 つのスタイルがあり:

スタイル A (推奨): Option<&CommandBuffer> parameter

impl Projector {
    pub fn project_soa(&self, param: &Param, cam: &Camera) -> GpuProjectResult {
        self.project_soa_in_cmd(param, cam, None)  // 旧 path
    }
    pub fn project_soa_in_cmd(
        &self,
        param: &Param,
        cam: &Camera,
        cmd: Option<&CommandBufferRef>,  // None なら内部で作って commit
    ) -> GpuProjectResult {
        // cmd.is_none() → 旧 behavior
        // cmd.is_some() → encode のみ、commit は呼び出し側
    }
}

利点: 既存の test / call site は変更不要、新 path は opt-in。欠点: API surface が増える。

スタイル B: enum DispatchMode

pub enum DispatchMode<'a> { Sync, Pipelined(&'a CommandBufferRef) }

forward() などに mode: DispatchMode を渡す。Sync で旧 path、Pipelined(cmd) で encode のみ。利点: 引数 1 個、call site は明示的に意図を書ける。欠点: 既存 call site に追加が必要。

結論

A 推奨。理由: 既存テスト 23 件 (cargo test -p splat-metal --lib) を一切 touch せずに済む。

対象 kernel と作業量

kernel現状 commit/iterencode-only API 必要
project::project_soa1yes (forward chain)
project::project_soa_buf1(将来 stretch)
tile_bin::emit_pairs1yes
tile_bin::radix_sort1 (× ~5 passes)yes
tile_bin::extract_offsets1yes
rasterize::forward1yes
rasterize::backward1yes (backward chain)
project::project_backwards1yes
ssim::forward_and_grad_buf2(将来 stretch、L1Ssim 系で)
loss::compute_l1_combine_ssim多数(将来 stretch)
adam::step1no (1 commit のみ)

forward chain は 4-5 commit / iter → 1 commit に集約見込み。

test 計画

  1. 既存 cargo test (23 件) が全 pass (encode-only path を opt-in にしてあれば自動的に通る)
  2. 新 batched path 用の test を追加 (e.g., forward_batched_matches_unbatched): 同 input で旧 path と新 path を実行、結果が bit-identical か近似一致
  3. smoke 500-iter (lego sh=3) で loss が変動しない確認 (A.10 Kahan で見たような compiler 最適化挙動の有無を check)

bench 計画

A.4 完了後の GPU 空き時間で:

  1. baseline: M-3.x lego 30k = 24.842 dB / 23m40s
  2. ICB ON: 30k = ? / ? (target -10% wallclock or better)
  3. PSNR drift < 0.05 dB (なければ commit OK)

想定リスク

  • 1 cmd buffer に複数 encoder を入れる場合、各 encoder の end_encoding() を忘れると Metal が panic、慎重に
  • wait_until_completed() を呼ぶタイミング: encode-only path では呼ばない、最後の commit で呼ぶ
  • ssim / loss の中間 readback (host) が必要なら chain breakable、最初は forward / backward 単独 chain に絞る

卒論への含意

第 3 軸 (Apple Silicon 固有最適化) の追加 row。M-3.x baseline 23m40s → ICB ICB X m Y s と書ければ評価表が 1 行充実。

正の効果なら第 3 軸論を補強 (commit overhead は Apple Silicon の特徴)。負の効果なら「commit overhead は M4 Max では既に十分小さく、batching 効果は marginal」という finding として記録 (A.10 と同レベルの honest negative finding)。

関連

  • A.10 Kahan Negative finding: a-10-kahan-negative.md
  • A.5 final ablation 表 第 3 軸: final-ablation-table.md
  • A.9 f16 forward prototype 実装済 (env SPLAT_F16_FORWARD=1 切替): bench は A.4 完了後
02

関連する run

この finding が観測された / 言及している実験 run。

03

関連 finding

© 2026 大竹律輝 — 松田研究室