perf: rasterizer and pipeline optimizations - #8
Open
rayanht wants to merge 2 commits into
Open
Conversation
Two changes to nd_rasterize_forward_kernel and rasterize_backward_kernel. Read batch data straight from threadgroup memory. Every lane reads the same index and the hardware broadcasts that, so routing it through lane 0 plus four simd_broadcast shuffles was overhead. Returns the same value bit for bit. Compact candidates against the block's own pixel box. tile_bins is BLOCK_X/Y (16x16) but a threadgroup covers RAST_BLOCK_X/Y (8x8), so each pixel was testing every gaussian in a tile four times its footprint, ~94% of which fail the per-pixel sigma test. Each gaussian is now tested once at load time: sigma < 5.55 confines it to an ellipse with axis-aligned half-extents sqrt(11.1 * cov_ii), cov = inverse(conic). Survivors are compacted in depth order via simd_prefix_exclusive_sum. Only gaussians that fail for every pixel in the block are dropped, so output is unchanged; degenerate conics (det <= 0) fall through to the per-pixel test. Pinned workload (garden, 1535033 gaussians, 1297x840, SH degree 3): rast_fwd 1.674 -> 1.202 ms -28% rast_bwd 4.453 -> 3.223 ms -28% total 12.50 -> 10.78 ms -14% Full 7000-iteration runs, quality unchanged: --num-downscales 0 77.7s -> 76.1s PSNR 25.720 -> 25.714 SSIM 0.7838 -> 0.7841 --num-downscales 2 32.4s -> 30.3s PSNR 24.912 -> 24.921 SSIM 0.7151 -> 0.7151 The chunked kernels are untouched.
Gaussian index order is whatever densification's compaction produced, so the stages that address memory by gaussian id read unrelated cache lines from neighbouring lanes, and visible/culled gaussians are interleaved inside a simdgroup rather than uniform across it. Sorting by Morton code of position fixes both. A counting sort over an 18-bit Morton bucket (6 bits per axis, 262144 buckets) reusing the prefix-sum kernels densification already runs, then the permutation is applied to all 18 buffers. Reordering permutes an unordered set, so the scene is unchanged. Pinned workload (1535033 gaussians, offline-reordered PLY, isolates the effect): proj_sh_fwd 0.853 -> 0.654 -23% sort/scatter 1.366 -> 1.206 -12% grad_stats 0.120 -> 0.064 -47% adam 2.884 -> 2.787 -3% rast_fwd/bwd unchanged (they read packed_* in sorted order, already coherent) sum 10.743 -> 10.221 -4.9% Full 7000-iteration runs, 2 reps each: --num-downscales 0 71.0s -> 67.7s PSNR 25.685 -> 25.684 --num-downscales 2 30.1s -> 29.4s PSNR 24.952 -> 24.927 Runs at each refine step, so it also keeps order fresh as split/dup children are appended at the tail.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
garden, 1535033 gaussians, 1297x840, SH degree 3, densification off.
9s/run, +/-0.2%.
Landed
6b81971)simd_broadcast(3) is measured on an offline-reordered PLY to isolate it: proj_sh_fwd 0.853 -> 0.654,
sort 1.366 -> 1.206, grad_stats 0.120 -> 0.064, adam 2.884 -> 2.787. The rasterizers
do not move; they read
packed_*in sorted order and were already coherent.Full runs, v1.1.4 -> head of branch:
--num-downscales 0--num-downscales 2nd0 PSNR spread across runs is 0.12, nd2 0.05.
Breakdown
rast_bwd ablations (post-compaction, 3.199ms)
floor 1.105 (34.5%) / gradient math 1.113 (34.8%) / reductions 0.692 (21.6%) / atomics 0.289 (9.0%).
Compaction cut the floor 2.83 -> 1.105; atomics and reductions unchanged in absolute terms.
sort/scatter/pack ablations (1.376ms)
1.88M
atomic_fetch_addonto 4346 tile counters. Contention ruled out (see below);the 1.139ms is bbox iteration plus 1.88M x 8B writes into
prealloc_bins.Queue
loss_intermediates+ssim_h_bufare [H,W,15], ~65MB each, ~260MB round-trip vs ~0.65ms roofline.Ruled out
simd_sumwhen 1 lane is validproject_and_sh_forward, which costs back most of the saving.proj_sh_bwd_adam is bandwidth bound: 507K visible x 1284B = 651MB/iter.
Notes
metal_tensor.hppchangessizeof(MTensor). Incremental builds across it produce a mixed-ODR binary that trains to garbage.rm -rf buildafter any header change.