松田研究室
FindingID: phase5-step31-encoding-profile
Status: stable / task #5.31
← Findings Index
Phase 5 · #5.31 encoding profile

Phase 5 #5.31 — CPU side profile + queue reuse 効果 + 真の bottleneck 同定

ArgBuffer 当初案は wallclock 寄与 0.5% で reject、代わりに queue reuse 単発で -13.7% を確定。残る host-side loss compute + readback ~10.5 ms/iter が真の bottleneck → 第 3 軸 (unified memory zero-copy) の最強候補 #5.31.x GPU loss を再定義。

mixedrank: highpartial第 2 軸第 3 軸phase-5step-31arg-bufferqueue-reusereadbackunified-memoryencoding-profilem4-max
Δ Wallclock
queue reuse: -13.7% / ArgBuffer: 0.5% (reject)
Impact
ArgBuffer は CPU encoding 寄与 0.5% で 3% gate 不通過 → reject。queue reuse refactor 単独で -13.7% wallclock (1.14 ms/iter 削減が autorelease pool 圧縮を伴って効果増幅)。真の bottleneck は host-side loss compute + readback ~10.5 ms/iter (= 24-26% wallclock potential)、第 3 軸 narrative 最強の #5.31.x GPU loss kernel + no-readback を次着手に再定義。
01

本文

#5.31 ArgBuffer 当初案は CPU encoding の wallclock 寄与が 0.5% (理論上限) で 3% gate 不通過 → reject。代わりに発見した #5.31.0b queue reuse 単独で wallclock -13.7% (95.9s → 82.8s, 2000 iter @ Lego F config)。さらに残る host-side loss compute + readback ~10.5 ms/iter が真の bottleneck → 第 3 軸 (Apple unified memory zero-copy) の最強候補 #5.31.x GPU loss kernel + no-readback pipeline を次着手に再定義。

実施
2026-04-30 (3 phase)、step 30b の _queue / _enc / _readback / phase bucket timer を順次追加
Hardware
M4 Max
設定
F config + L1+SSIM (λ=0.20, K=7) 2000 iter、iter 50 reset、iter 50-2000 集計
Scripts
3dgs-rs/scripts/phase5/run_step31_encoding_profile.sh
Logs
3dgs-rs/runs/phase5-step31-profile/ (gitignored)

TL;DR (3 つの結論)

  1. #5.31 ArgBuffer は dead。CPU encoding の wallclock 寄与は 0.5% (理論上限)、3% gate 不通過確定。_enc 計測値: 0.21 ms/iter / 42.5 ms/iter = 0.5%
  2. #5.31.0b queue reuse 単独で wallclock -13.7% (95.9s → 82.8s, 2000 iter @ Lego F config)。1.14 ms/iter の queue 生成削減が autorelease pool 圧縮も伴って効果増幅
  3. 真の bottleneck は host-CPU 経路 (loss/grad host compute + readback)、合計 ~10-11 ms/iter (= 24-26% wallclock potential)。次着手は loss kernel GPU 化 + no-readback pipeline

Phase 1: per-dispatch encoding 計測 (5.31.0a)

(初版に記載済の通り、ArgBuffer 単独の上限が 0.7% であることを確定)

計測結果 (commit cea364b 直後)

  • Wallclock: 95.9 s / 2000 iter = 49.2 ms/iter
  • GPU compute (sum of record(..)): 31.4 ms/iter
  • CPU side (wallclock - GPU): 17.8 ms/iter
  •   ・queue 生成: 1.14 ms/iter
  •   ・encoder setup: 0.34 ms/iter
  •   ・その他 CPU: 16.0 ms/iter ← 未分解

ArgBuffer は encoder setup の 0.34 ms/iter しか触らないため上限 0.7%、3% gate 不通過確定。

Phase 2: queue reuse refactor (5.31.0b)

10 dispatch site の let queue = self.device.new_command_queue() を全 struct field の self.queue 参照に置換 (commit e2611df)。

効果 (大きく上振れ)

指標before (5.31.0a)after (5.31.0b)delta
Wallclock 2000 iter95.9 s82.8 s-13.7%
ms/iter49.2 ms42.5 ms-6.7 ms

naive 計算 (1.14 ms/iter ≒ 2.3%) を遥かに超える。理由は以下と推測:

  • queue 生成は 80-130 µs を timer 上では取るが、ObjC autoreleasepool 経由で hidden cost 累積
  • 10 queue/iter × 2000 iter = 20000 queue alloc/dealloc が GPU driver / IOService に圧力
  • queue reuse で per-iter autorelease pool が大幅に lighter
Big single-commit win

queue reuse は phase 5 の最大単一コミット効果 (M-2 SIMD reduction の 2.43× per-kernel と同水準の wallclock 効果)。

Phase 3: readback + host-compute 計測 (5.31.0c)

queue reuse 後の 16 ms/iter CPU 側内訳を裏取りするため、_readback ラベル + ts_* phase bucket を追加。

Phase bucket 集計 (per-iter)

phasems/iter含む内容
ts_forward17.52 msproject_soa + emit_pairs + radix×16 + extract + rasterize_f32 + 各 readback
ts_loss_host9.13 msl1_loss + l1_grad + ssim fwd/bwd GPU + ssim_cpu_mean + ssim_grad_readback + grad combine
ts_backward11.62 msrasterize_backwards_simd + backward_rasterize_readback
ts_project_back0.55 msproject_backwards
ts_adam0.95 msadam_step ×5
合計39.77 ms
残: iter overhead2.73 msautoreleasepool + scan_nan + refine accumulate + Rust loop
wallclock42.5 ms

各 phase の non-overlapping 内訳

ts_forward (17.52 ms/iter)
内訳ms/iter
GPU compute (project_soa + emit_pairs + radix×16 + extract + rasterize_f32)~12.6 msrecord(..) 直接計測
readback (project_soa + emit_pairs + radix_sort + extract_offsets + rasterize_f32)~2.1 msrasterize_f32_readback 0.82 ms が最大
residual~2.9 msbuffer alloc (new_buffer_with_data) + CPU radix prefix scan + Rust overhead
ts_loss_host (9.13 ms/iter)
内訳ms/iter
ssim_fwd_bwd (GPU)2.84 ms
ssim_cpu_mean1.28 ms800×800×3 reduce
ssim_grad_readback0.52 ms
residual4.49 msl1_loss + l1_grad + grad combine on rendered Vec (800×800×4 = 2.56 MB)
ts_backward (11.62 ms/iter)
内訳ms/iter
rasterize_backwards_simd (GPU)9.47 ms
backward_rasterize_readback0.12 ms
residual2.03 ms (buffer alloc / dldo upload / Rust)

ROI 比較表 (ranking)

ROI = 期待 wallclock 改善 / 実装工数。

候補削減潜在 (ms/iter)wallclock 改善工数narrative 価値状態
#5.31.0b queue reuse6.7 ms (実測)-13.7%30 mininfrastructure✅ 完了
#5.31.x GPU loss + no-readback~7-8 ms (推定)-16〜19%4-8 hr第 3 軸最強 (= unified memory 直撃)検討中
#5.34 SSIM tile shader~1.5 ms~3.5%3-5 hr第 2 軸+第 3 軸 (Apple TBDR)future work
#5.31.5 dispatch fusion (B-mini)0 ms (確定)0%(実測済 ROI ゼロ)(negative)❌ reject
#5.31 ArgBuffer0.21 ms (実測)0.5%4-6 hr❌ reject

真の bottleneck = ts_loss_host residual + readback

合計 ~10.5 ms/iter の host-CPU 経路:

  1. l1_loss(rendered, target) + l1_loss_grad(...) (~3.5 ms) — 800×800×4 f32 を 2 回 iterate (loss + grad)
  2. grad combine (1-λ)*l1g - λ*ssim_grad (~1 ms) — 同サイズ Vec をもう一度 iterate
  3. rasterize_f32 readback (0.82 ms) — rendered_buf を to_vec()
  4. emit_pairs readback (0.73 ms) — sorted keys の host 経由
  5. radix_sort readback (0.36 ms) — sorted keys を host へ pull
  6. ssim_grad_readback (0.52 ms) — grad を host 経由
  7. その他 readback + buffer alloc (~3.5 ms)

これらは全て:

  • wgpu 抽象 (= brush 路線) の典型 — 各 op の境界で host vec へ readback
  • Apple unified memory が解決する領域.contents() で zero-copy だが .to_vec() で copy 発生
  • 第 3 軸 narrative の核 — 「unified memory を活用していない設計欠陥を remove したらどれだけ速くなるか」

Pivot 決定 (data driven)

#5.31 当初定義 (ArgBuffer) は scope 外

確定: 0.5% wallclock 上限、F/G と同 pre-commit gate culture で reject。docs/roadmap/future-work.md §B-1 を更新、docs/todo.md#5.31 を ❌ に。

採用: #5.31.0b queue reuse (実測 -13.7%)

別 commit e2611df で完了済。findings に M-3 候補として記録。

検討: #5.31.x GPU loss kernel + no-readback pipeline

「真の bottleneck」を解決する Phase 5 後継 step として再定義。第 3 軸 narrative 最強の貢献候補:

  • M4 Max unified memory の zero-copy を実装で示す
  • brush の wgpu 抽象 (= host 経由) との対比が直接立つ
  • 実装: forward_with_state の戻り値を GPU buffer の参照に変更、loss + grad を Metal kernel 化

期待 ROI: -16〜19% wallclock (= 35 ms/iter 圏)、工数 4-8 hr。

Pivot 候補: #5.34 SSIM tile shader

第 2 軸 + 第 3 軸 narrative はあるが ROI 小さい (~3% wallclock)。GPU loss が大きすぎるので後回し。

卒論への活用

本 finding は 「abstract に CPU encoding と呼んでいた overhead を 3 段階の計測で内訳分離した」 方法論的貢献:

  1. step 30 で「~30% が CPU encoding」と推定
  2. step 31.0a で encoder setup は 1.4%、queue 込みでも 3.6% と判明
  3. step 31.0b で queue reuse のみで 13.7% wallclock (期待を上振れ)
  4. step 31.0c で残りは host-side loss compute + readback と判明 → 第 3 軸 narrative の最強候補
Methodology

F (scale_reg) / G (MCMC) と同じ「pre-committed gate で reject + 残作業に valuable narrative を引き継ぐ」negative finding。卒論の方法論章で「ベンチマーク前提の自己検証手順」として収録予定。

03

関連 finding

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