松田研究室
FindingID: p2-s3-iteration-pipelining
Status: stable / task 2026-08 1× 工程表 v2 — AC 復帰後 計測 queue #2' (S3 gate)
← Findings Index
1× 工程表 v2 · S3 · iteration pipelining (並列性能軸)

S3 iteration pipelining depth 2 — 12.5k -18.1% / busy 78 → 91% (default flip)

S2 が forward を 1 CB に畳んだ後も残っていた sync-tax は「CB 完了まで host が次 iteration を組めない」実行形状そのものだった。iteration N の loss/backward CB を commit した直後に <strong>wait せず</strong> iteration N+1 の forward CB を組んで commit し、in-flight command buffer を常に 2 本以下に保つ depth-2 pipelining を入れた。host の重い仕事 (grad 14.7 MB readback / <code>RefineState::accumulate</code> / SSIM の host 総和) はすべて F<sub>N+1</sub> の GPU 実行の影に入る。12.5k Lego の<strong>同一 session 交互 A/B n=3 で 185.21 → 151.70s = -18.1%</strong> (process wallclock 188.33 → 154.0s = -18.2%)、機構は Layer 1 が直接示す — <strong>GPU busy 77.5 → 91.3%、sync-tax 3.244 → 1.136 ms/iter (-65%)、<code>ts_fwd_chain_commit_wait</code> 5.195 → 2.636 ms/iter</strong>。PSNR は n=3 mean 36.202 dB (off 36.185、guard 内)。<strong>msplat 同日等価 gap は 1.105× → 0.907×</strong>。

positiverank: highs3-adopted-default-flip-pipelining-depth2第 1 軸第 3 軸1x-roadmap-v2s3iteration-pipeliningcommand-buffergpu-busysync-taxdouble-bufferingscratch-generationlegounified-memory
Δ PSNR
12.5k **同一 session 交互 A/B** n=3 mean: depth2 **36.202 dB** (36.195 / 36.179 / 36.231) vs off **36.185 dB** (36.178 / 36.192 / 36.186) = **+0.016 dB** (guard 36.167 ± 0.1 の内側、n=3 mean 判定 — n=1 判定なし)。final splats は depth2 406,439 / off 408,874 で **depth2 のほうが 0.6% 少ない** (前段の profile pair では逆に +0.6% で、方向が一致しない = 既存 atomic 非決定性の chaos 増幅の範囲)
Δ Wallclock
12.5k full run **同一 session 交互 A/B n=3 mean: 185.21 → 151.70s = -18.1%** (train elapsed)。process wallclock では **188.33 → 154.00s = -18.2%**。σ は off 3.33% / depth2 1.18% なので有意閾値 max(2σ,1%) = 6.7%、実測 Δ は**その 2.7 倍**。同一 session の off arm は S2 gate 当日の S2 arm (train 184.61s / process 187.65s) を **+0.3% で再現**しており、session の健全性が確認できている。参考: profile=true の 1 対 1 比較では 180.49 → 162.72s = -9.85% (計装自体が host 側 critical path に乗るため S3 の効果を過小評価する)
Impact
1× 工程表 v2 が「S2 後の単独本命」に指定していた S3 を gate し、採用した。S2 までの施策が CB の数を減らすものだったのに対し、S3 は CB の並び方を変える — iteration N の loss/backward CB (BN) を commit したら wait せずに iteration N+1 の forward CB (FN+1) を組んで commit し、wait(BN) の後の host readback / accumulate を FN+1 の GPU 実行の影に置く。12.5k 同一 session 交互 A/B n=3 で 185.21 → 151.70s = -18.1% (閾値 max(2σ,1%) = 6.7% の 2.7 倍)。GPU busy 77.5 → 91.3% / sync-tax 3.244 → 1.136 ms/iter (-65%) で counter session が置いた「busy 100% = 理論上限」への距離は 22.5 pt → 8.7 pt に縮んだ。1k smoke では busy 65.8 → 72.0% にしか上がらず判定不能だった — smoke の splat 数 6.8k では forward の GPU 影 (1.06 ms/iter) が image size 固定の host 仕事 (~1.7 ms/iter) を隠しきれないためで、これは 「pipelining の gate は smoke では代替できない」という harness 上の教訓として残す。残 bubble の内訳も確定した: refine tick の drain 6.04s (43%) > encode(B) 4.66s (33%) > 残差 3.28s (23%) — 次の一手が roadmap の「即効ペア (refine capacity スコープバグ修正)」であることが実測で決まった。msplat 同日等価 gap 1.105× → 0.907×、Phase 0 からの累計 766.07 → 154.0s = -79.9% (全て数学的同値の施策のみ)。
01

本文

counter session (p2-counter-session) と S2 gate (p2-s2-forward-chained) は「残る sync-tax 2.86 ms/iter は command buffer が完了するまで host が次 iteration を組めないという実行形状そのもので、CB をこれ以上畳んでも消えない」と結論していた。S3 はその結論を実装したもの — iteration N の loss/backward CB を commit したら wait せずに iteration N+1 の forward CB を組んで commit し、in-flight command buffer を常に 2 本以下に保つ。host の重い仕事 (grad 14.7 MB readback / RefineState::accumulate / SSIM の host 総和 1.9M 要素) はすべて FN+1 の GPU 実行の影に入る。param / adam state の double buffering は不要 — command queue が 1 本の in-order queue なので BN-1 ≺ FN ≺ BN ≺ FN+1 が保証され、BN の adam write は FN+1 の project read より必ず前に起きる。二重化が要るのは scratch だけ (cross-CB の write-after-read を buffer の同一性ごと消す)。

0. 計測環境 — CPU 汚染で round 1 を全 6 run 破棄している (先に宣言する)

電源 / 機体
AC 接続、M4 Max (36 GB)、macOS 26.5.2 (25F84)。**GPU は本 session が専有**
CPU 側の汚染
同一機体で別プロジェクト (diver_v4) の TypeScript typecheck (`tsc --noEmit` が 385% + 287%)、Gradle daemon (JVM 198〜427%)、wrangler deploy、Xcode `swift-frontend`、Spotlight 再インデックスが**断続的に**走った。session 中の 1 分 load average は **2.0 → 26.7** まで変動
なぜ致命的か (S2 のときより深刻)
S3 の機構は「**host 仕事を GPU 実行の影に隠す**」ことそのもの。CPU が競合すると host 仕事が影からはみ出し、**depth2 arm を選択的に遅くする** (実測: depth2-r2 は load 平均 7.95 で 165.67s、load 平均 2.14 で 152.70s = **+8.5%**)。つまり汚染は S3 に**不利**な方向に効く
**採用した規律**
① 各 run の開始前に 1 分 load が閾値未満になるまで待つ (driver `splat/scripts/s3-gate-abbaab.sh` の quiesce)、② 各 run の前後で load を記録、③ 10s 間隔の独立 sampler で **run 窓内の load 平均 / 最大**を事後計算、④ 汚染 run は破棄して再測
round 1 の破棄 (全 6 run)
23:27〜23:45 の ABBAAB は load 2 → 23 の上昇に直撃され、off σ 4.71% / depth2 σ 2.61% と **arm 間で σ が非対称**になった (汚染の典型的な署名)。Δ は -12.4%。**全 6 run を破棄**し、log は `runs-logs/s3-12500-abbaab-round1-CONTAMINATED-*.log` として残した
round 2 (採用) の run 窓内 load
off: 8.03 / 3.10 / 3.62 (最大 13.28 / 4.04 / 4.34)、depth2: 3.57 / 2.14 / 4.96 (最大 4.22 / 2.58 / 6.94)。**off-r1 だけ平均 8.03 と高い**が、その off-r1 が 3 本中**最速** (179.87s) だったので、残せば off arm を有利に見せる = **S3 に不利な側に倒す**。よって破棄せず採用した
A/B 設計
12.5k は **同一 session 内で交互** (実行順 A B B[破棄] A B A B)。S2 gate と同じ方針で、cross-session の「当日 baseline」は使わない。前段の profile=true 1 対 1 比較 (Layer 1 取得用) は 23:20〜23:26 の**汚染前**に取れている
default flip の副作用 (記録)
`pipelining` default が Depth2 になったため、① 敗者 variant を pin した **train config 12 本**に `pipelining = "off"` を明示追記した (`batched_tail` 4 / `per_kernel` 2 / `loss_path=host` 3 / `forward_submission=per_stage` 系 3)。flip 後に **`splat check` で全 247 config を sweep し、train config 187 本すべて load 成功 / pipelining 起因の validate failure 0** を確認 (残る 60 本は bench/parity config で `splat check` の schema 対象外、うち 1 本 `2026-05-01-0606-smoke-1000iter-stp.toml` は S3 以前からの schema 不整合)。② `splat bench` 側は **raw TOML に `pipelining` を書いていない config を `Off` に落とす** demote を入れた (下の callout)

1. 等価性 — 「同一実装を共有する」ことの構造的保証 + test 5 本

変わらないもの
kernel、dispatch 列、bind 順、数値。loss/backward chain の encode は `pipeline::encode_loss_backward_chain` の **同一実装**を Off / Depth2 が共有する
変わるもの (3 点だけ)
(a) CB の commit と wait の位置、(b) forward scratch の世代 (2 世代 ping-pong)、(c) host が消費しない forward readback の省略 (`splats2d` / `tile_offsets` / `final_t`)
順序保証 (a)
**単一 in-order queue**。`Device` は command queue を 1 本しか持たず commit 順に実行されるので `B_{N-1} ≺ F_N ≺ B_N ≺ F_{N+1}`。これが「param / adam state の double buffering 不要」の根拠 — B_N の adam write は F_{N+1} の project read より必ず前
順序保証 (b)
**forward scratch の 2 世代化**。F_{N+1} を encode する時点で B_N はまだ GPU 実行中で `splats2d` / `sorted_idx` / `tile_offsets` / `rendered` / `final_t` / `last_contrib` を読んでいる。世代を分けて write-after-read を buffer の同一性ごと消す。世代の取り違えは `finish_forward_chained` の `debug_assert_eq!` が pin する (**debug build でのみ有効なので test は debug で走らせる規約**)
順序保証 (c)
**backward scratch の 2 世代化**。1 世代でも「loop body の 2 文の順序」を人間が守れば足りるが、readback を encode の下に動かしても panic せず loss と grad が静かに壊れる。2 世代化でこの規約が**世代 index の不一致という構造**に変わる
grad buffer は 1 世代のまま
書き手も読み手も B_k CB の内側に閉じている (blit zero → project_backwards の accumulate → adam が同一 CB の encoder 列)。host が grad を触る唯一の経路 (scale_reg / MCMC L1 の RMW) は先行 encode を skip する iteration
test何を pin するか結果
`pipelining_depth2_matches_off_byte_exact_1iter`1 iteration の全 param が Off と byte 一致**PASS**
`pipelining_depth2_matches_off_byte_exact_2iter`2 iteration (= 世代 ping-pong が 1 周) で byte 一致**PASS**
`pipelining_depth2_matches_off_across_refine_ticks`refine tick (= 逐次点) を跨いでも byte 一致**PASS**
`pipelining_depth2_grad_rmw_order_preserved_scale_reg`grad への CPU RMW がある iteration で Off と同じ逐次順序**PASS**
`pipelining_off_never_leaves_scratch_generation_zero``pipelining = off` は slot 0 固定 (S2 と bit-exact)**PASS**
`pipeline::tests` 8 本逐次点 cadence (refine / relocation / opacity reset / checkpoint / grad RMW / MCMC noise) と in-flight limiter**PASS**
workspace 全体debug (`-p splat-train-v1` 70 本、`debug_assert` 有効) + release 全 crate**PASS / warning 0**
「bit-exact」の射程 — kernel は同一だが end-to-end は既存の非決定性を継承する

S3 は新しい計算を 1 つも足していないので、test 5 本が示すとおり同一 seed・同一 iteration での結果は Off と byte 一致する。しかし end-to-end の 12.5k run が run 間で bit-exact になるわけではない — rasterize backward の atomic<float> 加算順序に由来する既存の非決定性を S3 もそのまま継承する (p2-s2-forward-chained と同じ)。実際 1k smoke の final loss は off 6.582768e-2 / depth2 6.568347e-2 と一致せず、12.5k の final splats も off 408,874 / depth2 406,439 とズレる。だから PSNR guard (n=3 mean ±0.1) は実質的な検査として機能している。

2. 1k smoke は判定に使えなかった — 「pipelining の gate は smoke で代替できない」

指標 (1k smoke、profile=true、最終 6,826 splats)offdepth2読み方
GPU busy%65.8%72.0%**期待した 95% 圏に遠く届かない**
sync-tax (ms/iter)1.5731.270-19% しか減らない
wallclock (s)4.6014.545**-1.2% = 判定不能**
`ts_fwd_chain_commit_wait` (ms/iter)1.2520.176**-86% — 機構自体は完全に効いている**
`ts_chain_commit_wait` (ms/iter)2.1352.411+13% (forward 待ちが loss chain 待ちへ移動しただけ)
原因は splat 数 — 「隠す先の影」が短すぎた

1k smoke の最終 splat 数は 6,826 (12.5k run は 407k)。forward の GPU 実行時間はおよそ 1.06 ms/iter しかなく、これが「host 仕事を隠す影」の全長になる。一方 host 側で隠したい仕事のうち SSIM の host 総和 (1.9M 要素) は image size にしか依存せず splat 数で縮まない (~1.7 ms/iter)。したがって smoke では影より仕事のほうが長く、原理的に隠しきれない。12.5k (407k splats) では forward の影が 4〜5 ms/iter に伸びるので全部入る。この構造から「iteration pipelining は smoke で gate できない」という harness 上の一般則が出る — S3 は 12.5k を 2 本 (profile=true の 1 対 1) 追加で走らせて判定に進んだ。

3. 12.5k の実測 — 同一 session 交互 A/B n=3 (round 2、採用)

実行順armtrain elapsed (s)process wallclock (s)PSNR (dB)final splatsrun 窓内 load1 平均 / 最大
1off (A)179.8718336.178406,4008.03 / 13.28
2depth2 (B)149.6315236.195405,0843.57 / 4.22
—depth2 (破棄)(165.67)(169)(36.280)(407,650)**7.95 / 15.16**
3off (A)191.9519536.192409,0113.10 / 4.04
4depth2 (B)152.7015536.179407,6772.14 / 2.58
5off (A)183.8018736.186411,2113.62 / 4.34
6depth2 (B)152.7715536.231406,5554.96 / 6.94
**mean****off****185.21** (σ 3.33%)**188.33****36.185**408,8744.92
**mean****depth2****151.70** (σ 1.18%)**154.00****36.202**406,4393.56
**Δ**—**-18.09%****-18.23%****+0.016**-0.6%—
有意性 — 閾値 max(2σ, 1%) を 2.7 倍超過。σ の非対称そのものが機構の証拠

σ は off 3.33% / depth2 1.18%、したがって有意閾値は max(2σ, 1%) = 6.7%。実測 Δ -18.1% はその 2.7 倍。加えて σ の非対称自体が S3 の機構を裏づける — depth2 は GPU busy 91.3% でほぼ GPU 律速なので host 側 jitter に鈍く、off は host 往復が critical path に乗っているので jitter をそのまま拾う。同一 session の off arm (train 185.21s / process 188.33s) は S2 gate 当日の S2 arm (184.61 / 187.65) を +0.3% で再現しており、session の健全性も別途確認できている。期待帯 (roadmap v2 再見積り: busy 96% 圏 / ms/iter -13〜16%) に対しては busy は下振れ (91.3%) / wallclock は上振れ (-18.1%) で着弾した。

破棄した round 1 (全 6 run) — 数値を残して監査可能にする

23:27〜23:45 の ABBAAB は off 182.32 / 188.90 / 200.06s (mean 190.43、σ 4.71%)、depth2 166.74 / 162.49 / 171.19s (mean 166.81、σ 2.61%)、Δ -12.4%。この間に別プロジェクトの tsc / Gradle / wrangler が立ち上がり 1 分 load が 2 → 23 まで上がった。破棄の理由は Δ の大小ではなく arm 間で σ が非対称になったことで、S3 のように「host 仕事を影に隠す」施策では CPU 競合が depth2 側を選択的に殴るため、汚染下の Δ (-12.4%) は真値より小さく出る。実際 clean 条件で取り直すと -18.1% に伸びた。同じ現象は単一 run 単位でも観測できる — depth2-r2 は load 平均 7.95 で 165.67s、load 平均 2.14 で 152.70s (+8.5%)。

4. 機構の帰属 — Layer 1 (GPU busy / sync-tax) が直接示す

指標 (12.5k、profile=true、汚染前に取得)offdepth2Δ
**GPU busy%**77.5%**91.3%****+13.8 pt**
**GPU busy (s)**139.854148.436+6.1%
**sync-tax (s / ms per iter)**40.556 / 3.244**14.206 / 1.136****-65.0%**
train elapsed (s)180.49162.72-9.85%
`[pipelining]` 計器—`peak_in_flight=2` / `sync_iters=121 / 12500` (99.0% で先行 encode)in-flight CB が仕様どおり 2 本以下
final splats407,489410,011+0.6%
self-eval PSNR (dB)36.12736.247+0.120
`sync_iters = 121 / 12500` が逐次点の設計どおりであることの検算

先行 encode を止める iteration 数は 121。refine tick は start_iter=500 / every=100 / stop_iter=12500 なので (12500 − 500) / 100 + 1 = 121 で完全一致する。1k smoke でも sync_iters = 6 = (1000 − 500) / 100 + 1 で一致。param_mutated_after_step が refine tick でだけ発火し、それ以外の想定外の drain が 1 度も起きていないことの直接証拠になる (本 config は MCMC noise / relocation / opacity reset / checkpoint をすべて無効にしているので、期待される逐次点は refine tick のみ)。

label (µs/call、12.5k profile=true)offdepth2読み方
**`ts_fwd_chain_commit_wait`** (forward CB の wait)**5,195.0****2,636.0****-49.3%** — S3 の機構そのもの。forward の待ちが B_{N-1} の実行と重なって消える
`ts_forward` (forward 全体)5,509.02,640.0-52.1% (上の wait が支配的)
**`ts_chain_commit_wait`** (loss/backward CB の wait)**6,684.0****7,109.0****+6.4%** — forward 待ちが減ったぶん GPU 律速がここに集まる (期待どおり)
`ts_refine_accumulate`323.4493.2+52.5% だが **gpu_ms 0 → 1,871.9** = F_{N+1} の影で走っていることの計器上の証拠
`ts_ssim_fwd_grad` (encode)83.3127.1+52.6%
`ts_backward_raster` (encode)72.8115.1+58.2%
`ts_raster_bwd_alloc`56.688.9+57.1%
`ts_zero_grads`8.618.6+115.7%
`ts_raster_bwd_upload`8.613.9+60.9%
`ts_adam` (encode)2.43.5+49.7%
`ts_refine` (µs / tick)43,06649,888+15.8% (121 tick)
S3 が持ち出す代金 — encode コストが systematic に +50〜115% 上がる

depth2 では すべての encode scope が 1.5〜2.2 倍に膨らむ (1k smoke でも同じ比率で観測できたので splat 数に依らない構造的なコスト)。原因は「GPU が別の CB を実行している最中に host が encode している」ことで、driver 側の lock 競合と unified memory の帯域競合の両方が効いていると考えられる。総額は encode(B) 合計で 0.236 → 0.373 ms/iter (+0.137)。module doc が置いていた「残る bubble は encode(B) のみ ~0.3 ms/iter」という見積りはこの膨張を織り込んでいなかったので、実測値 0.373 に訂正する。同様に GPU busy 時間そのものが +6.1% (139.85 → 148.44s) 増えている — splat 数の差 (+0.6%) では説明できず、① 2 世代化した scratch (+275 MB) の ping-pong による SLC/L2 局所性の悪化、② CB を隙間なく詰めたことで GPUStartTime/GPUEndTime の union に scheduling latency が算入されるようになった計測上の artifact、の 2 つが候補。どちらであっても回収額 (sync-tax -26.35s) が代金 (+8.58s) を 3 倍以上上回るので判定は変わらないが、切り分けは Xcode capture の残件に積む。

5. 残 bubble の内訳 — 次の一手が実測で決まった

残 sync-tax の内訳 (depth2、12.5k、profile=true、合計 14.206s)sms/itershare解消手段
**refine tick の drain** (`ts_refine` + `ts_opacity_decay`、121 tick)**6.26**0.501**44%**roadmap の**即効ペア** (`refine()` capacity スコープバグ修正 ~2.1GB/tick → ~0.85GB)。tick 中は先行 encode を止めるので GPU が完全に空く
**encode(B)** (zero_grads → ssim → l1 → backward → project_back → adam)**4.66**0.373**33%**構造上ここは埋まらない (depth 3 以上か encode の並列化が必要)。ただし上の「encode 膨張」を抑えられれば 0.236 相当まで下がる余地
残差 (影に収まりきらない readback / driver overhead)3.280.26323%Xcode capture で CB 内 occupancy を見る残件
理論上限の更新 — 「busy 100% = 148.17s」は書き換えが必要

counter session は「busy 100% なら 216.12 → 148.17s」という上限を置いていたが、これは S2 時点の busy ms/iter を固定した計算だった。S3 は busy 時間自体を +6.1% 押し上げているので上限も動く。本 gate の実測 (profile=true で busy 91.3%) をそのまま profile=false の 151.70s に当てると 残 bubble 8.7% = 約 13.2s、busy 100% の床は ~138.5s。ただし profile=true / false で busy 時間が同じという保証は無い (計装は host 側にも GPU 側にも乗る) ため、これは推定であって実測ではない。確定させるには profile=false 相当の busy を別経路で取る必要があり、Xcode capture の残件と同じ袋に入れる。

6. harness / 規約への影響

`splat bench` は S3 を測れない — hard error + demote の 2 段構え

splat bench は train_step を直接叩く replay harness で、iteration 境界を持たない。したがって pipelining は原理的に測れない (黙って Off 相当で走ると「S3 の replay 差分が 0」という誤った測定になる)。そこで build_trainer が pipelining != off を hard error にしてある。一方で本 gate の default flip 後は、pipelining を書いていない既存 bench config 47 本 + parity candidate 11 本が全部この hard error に落ちるため、raw TOML に pipelining キーが無い config は Off に落とす demote を BenchTomlConfig::from_path と run_parity の両方に入れた (validate() より前に走らせる必要がある — 敗者 variant を pin した config は validate 側で先に落ちるため)。明示的に depth2 と書いた場合だけ hard error に到達する。

gate 手順への追加 (規約)
**iteration pipelining 系の施策は 1k smoke で gate できない**。smoke は「配線が生きているか」(`peak_in_flight` / `sync_iters` の計器) と「loss 曲線が壊れていないか」の確認に限定し、**性能判定は必ず本番 scale で行う**
gate driver
`splat/scripts/s3-gate-abbaab.sh` を追加 (quiesce 待ち + run 前後 load 記録 + arm 引数)。以後の full run gate はこれを土台にする
**σ の再測が必要**
`p2-bench-harness-calibration` の σ 0.83% は replay harness の値で、**full run の σ ではない**。本 gate で観測した full run の σ は off 3.33% / depth2 1.18% (n=3)。今後 full run で判定するときはこちらを使う
profile=true は S3 を過小評価する
同一条件の 1 対 1 比較で profile=true は -9.85%、profile=false は -18.1%。計装 (timer / completedHandler / CB timestamp 読み) 自体が host 側 critical path に乗るため。**Layer 1 の busy% は profile=true でしか取れないが、wallclock 判定は profile=false で行う**という使い分けを維持する

7. 位置づけ — msplat 等価 gap と累計

段階Lego 12.5k (s)msplat 169.77s 比備考
Phase 0766.074.51×—
S1261.551.54×—
W1241.411.42×warp sparse skip
W2219.511.29×chained submission (loss chain 1 CB)
S2187.651.105×forward 1 CB + hierarchical scan
**S3****154.00****0.907×****iteration pipelining depth 2**
「msplat に勝った」とは書かない — 断面が揃っていない

process wallclock 154.00s は msplat 同日実測 169.77s の 0.907× で、数字の上では初めて 1.0× を割った。しかしこれは matched 断面ではない — 本実装 Lego 12.5k の PSNR は 36.202 dB、msplat 30K の native val は 36.539 dB で 0.34 dB 低い。roadmap v2 も最終段に「**msplat 等価比較の再実施 (matched 断面込み)**」を残しており、そこを通すまでは「等価 gap 0.907×」という指標値としてのみ扱う。卒論本文に「速い」と書けるのは matched 断面を取った後。

メモリ代価 — scratch 2 世代化で +275 MB (36 GB の 0.8%)

内訳は BinArena 172 MB (うち radix keys/idx が 156 MB)、SSIM work 56 MB、projector 16 MB、rasterize forward 15 MB、splats_grad 15 MB。P2 調査時の見積り「~81 MB」は radix の keys/idx を数え落としていたので 3 倍以上の乖離がある。実効的には pair capacity = num_splats × 16 の係数がそのままメモリ代価に効くので、将来 capacity hint を下げれば同じ割合で減る。Lego 12.5k で実際に peak RSS が問題になった場面は無い。

8. 次の一手 (本 gate で優先度が確定したもの)

  • **即効ペア (refine capacity スコープバグ修正 + zero_grads GPU blit 化) が単独の本命に格上げ** — 残 sync-tax 14.206s のうち **6.26s (44%) が refine tick の drain**。tick あたり 49.9 ms、121 tick。roadmap では -1〜2% 見込みだったが、S3 後の内訳では**それ以上の射程**がある
  • **encode(B) の膨張 (+58%) を抑える施策** — depth2 では encode が GPU 実行と競合して 1.5〜2.2 倍に膨らむ。setBytes 化の徹底 / encoder 再利用 / pre-encode した CB の使い回しが候補。総額 4.66s (33%)
  • **W3a/W3b/W4/W5 の旨みがさらに増した** — busy 91.3% になったので、busy 側 (11.9 ms/iter) を削る施策がほぼそのまま wallclock に落ちる。S3 後の breakdown を取り直して優先度を確定する
  • **S2 follow-up (radix reduce の histogram fold) は defer 継続** — dispatch overhead の全額が +0.20 ms/iter 未満と実測済みで、S3 後もその判断は変わらない
  • **残件**: Xcode capture (CB 内 occupancy、busy +6.1% の切り分け) / msplat 側 busy% 実測 / matched 断面での msplat 再比較
02

関連する run

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

03

関連 finding

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