Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions examples/sarbp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ real/imag, row-major), written to `output_image.raw` in this example.
| `-u N` | Range upsample factor via zero-padding (default: 1) |
| `-w {hamming,none}` | Window for range compression (default: hamming) |
| `--bulk-mocomp` | Apply bulk motion compensation to FX-domain input using the per-pulse `range_to_mcp` values stored by the CPHD converter |
| `-b {auto,all,0,N}` | Pulses per processing block. `auto` uses the GPU L2 cache size to choose a block size; `all` and `0` use all pulses (default: auto) |
| `--image-tiles N` | Process the image as N x N tiles during backprojection (default: 1) |
| `-b {auto,all,0,N}` | Pulses per processing block. `auto` jointly tunes pulse blocking and automatic image tiling for the GPU's L2 cache; `all` and `0` use all pulses (default: auto) |
| `--image-tiles {auto,N}` | Process the image as an N x N grid. `auto` jointly tunes image tiling and automatic pulse blocking for the GPU's L2 cache (default: auto) |
| `--taylor-fast-third-order` | Add the third-order range term when using `--precision taylor_fast` |
| `--precision {double,float,fltflt,mixed,taylor_fast}` | Backprojection compute precision (default: mixed) |
| `--precision {double,float,fltflt,mixed,taylor_fast}` | Backprojection compute precision (default: taylor_fast) |
| `--pixel-z {variable,zero,fixed}` | Compile-time assumption for the pixel Z coordinate. `zero` skips per-pixel Z work and is valid (and faster) for a flat, Z=0 image grid like this example's (default: variable) |
| `--warmup` | Warmup GPU kernels and FFT plans before timed run |
| `--gold FILE` | Validate the output against a golden image (raw `complex<float>`, same format the example writes) and report accuracy metrics (3x3-window correlation and signal-to-error ratio) |
Expand All @@ -133,7 +133,7 @@ in an incorrect phase reference.
The `--precision` flag controls the arithmetic used by the `sar_bp` operator. For spaceborne SAR, `float` does not provide enough precision to store fractional wavelengths at the range-to-MCP magnitudes (hundreds of km), so pure `float` is not sufficient to produce focused images. The available modes are:

- `double` -- full double-precision arithmetic. Most accurate.
- `mixed` -- double-precision for range computation, single-precision elsewhere. Default. Close to `double` in image quality with slightly higher throughput on GPUs with reduced double-precision throughput. Among the reference-quality modes it is the fastest on hardware with full-throughput double-precision (e.g., A100, H100/H200, B200); the approximate `taylor_fast` mode is faster still.
- `mixed` -- double-precision for range computation, single-precision elsewhere. Close to `double` in image quality with slightly higher throughput on GPUs with reduced double-precision throughput. Among the reference-quality modes it is the fastest on hardware with full-throughput double-precision (e.g., A100, H100/H200, B200); the approximate `taylor_fast` mode is faster still.
- `fltflt` -- float-float evaluation using two `float` values for the high-precision range math. Significantly higher throughput on GPUs where `double` throughput is reduced (e.g., RTX PROs, Jetson Orin/Thor, gaming GPUs).
- `taylor_fast` -- local Taylor approximation of the pulse-to-pixel range about a centered per-thread-block reference point. Highest-throughput experimental mode for spaceborne SAR geometries where moderate approximation error is acceptable.
- `float` -- single-precision throughout. Fastest but not accurate enough for most spaceborne data.
Expand Down Expand Up @@ -193,7 +193,7 @@ All results use the Umbra open-data collection referenced above, processed into
| 8192 x 8192 | ~5.73 km | 0.699 m | 1.0° | 11,566 | 776 |
| 20800 x 20800 | ~8.22 km | 0.395 m | 2.0° | 23,178 | 10,028 |

A backprojection is the unit of computation required for a single pixel-pulse contribution. For the "small" scene, there are 8192 x 8192 x 11566 = 776.18 billion backprojections, or ~776 giga backprojections. Both scenarios are X-band (9.6 GHz), ~770 km slant range, ~43° grazing angle. All runs use `--warmup` and `--pixel-z zero` (the image grid is planar at Z=0, so `zero` is exact here and is a few percent faster than `variable`). Throughput is reported with the optimal `--image-tiles` for each configuration and the default `-b auto`, which selects a 256-pulse block for this data on every GPU tested (see [Image Tiling](#image-tiling)). As the [Pulse-block size](#pulse-block-size) section shows, `-b` is itself a significant knob, so a manually tuned `(--image-tiles, -b)` pair can exceed these `-b auto` rates on some GPUs.
A backprojection is the unit of computation required for a single pixel-pulse contribution. For the "small" scene, there are 8192 x 8192 x 11566 = 776.18 billion backprojections, or ~776 giga backprojections. Both scenarios are X-band (9.6 GHz), ~770 km slant range, ~43° grazing angle. All runs use `--warmup`, `--pixel-z zero` (the image grid is planar at Z=0, so `zero` is exact here and is a few percent faster than `variable`), a 256-pulse block (`-b 256`), and the optimal `--image-tiles` for each configuration.

> **Note:** All compute types except `double` use the phase lookup-table (PhaseLUT) optimization, which precomputes the per-range-bin phase ramp once and then applies a per-pixel per-pulse correction. `double` runs without PhaseLUT as it operates as the reference for accuracy comparisons.

Expand Down Expand Up @@ -249,7 +249,7 @@ This makes the benefit a function of L2 size vs. scene size:
![Image-tiling speedup vs. tile count, taylor_fast 2nd order, across GPUs](tiling_performance.png)

- Smaller L2 -> larger benefit. On the 20800 x 20800 scene, `taylor_fast` recovers about +61% on the DGX Spark (24 MiB L2) and +22% on Thor (32 MiB), a milder +11% on the H200 (60 MiB), and nothing on the RTX PRO 6000 (128 MiB).
- The benefit also depends on scene size. The smaller 8192 x 8192 frame has a smaller working set, so only the DGX Spark (with the smallest L2 cache) gains from tiling there (+16%); Thor, H200, and PRO 6000 are flat because their larger L2 already holds it. Tiling matters most when the scene working set exceeds L2. Although the range profiles are most important in terms of L2 hit rates, note that `PhaseLUT` entries and image pixels will also be stored in L2 cache, so it is best to test multiple tiling factors on a given GPU rather than simply compute the range profile working set size and compare that to the L2 cache to determine optimal tiling.
- The benefit also depends on scene size. The smaller 8192 x 8192 frame has a smaller working set, so only the DGX Spark (with the smallest L2 cache) gains from tiling there (+16%); Thor, H200, and PRO 6000 are flat because their larger L2 already holds it. Tiling matters most when the scene working set exceeds L2. The `PhaseLUT` has the same footprint as one per-pulse range profile, and tiling reduces the actively used range-bin span of both. Image pixels also occupy L2, so it is best to test multiple tiling factors on a given GPU rather than simply compare the estimated working set to the L2 size.
- It only helps the memory-bound modes. `taylor_fast`, `float`, and (partly) `fltflt` benefit; the compute-bound `double`/`mixed` are flat because their FP64/extended-precision work already hides the memory latency.
- Over-tiling hurts. Once L2 pressure is relieved, finer tiling only adds launch overhead and other inefficiencies.

Expand All @@ -267,13 +267,15 @@ Because both compete for the same L2, the optimal block size depends on the tili
![Pulse-block size sweep at several tiling factors on the DGX Spark](pulse_block_performance.png)

- While pulse blocking alone may be sufficient for GPUs with more L2 cache, both image tiling and pulse blocking are beneficial for smaller L2 caches.
- The current auto-blocking (`-b auto`) logic chooses a minimum of 256 pulses, but without image tiling 128 pulses would be more optimal on DGX Spark. The most optimal point in this sweep uses 4 x 4 image tiling and 256 pulses per pulse block.
- Sweeps on GH200 and DGX Spark did not show a benefit below 256 pulses. The backprojection kernel amortizes work in 256-pulse units, so automatic selection uses 256 pulses as both its minimum and its block-size granularity. If that minimum creates too much L2 pressure, the heuristic increases image tiling instead of selecting a smaller pulse block.

By default, `-b auto` and `--image-tiles auto` auto selects both values. For an N x N image grid, the heuristic estimates the reusable working set as `(phase lookup table + pulse-profile working set) / N`, since each tile covers approximately 1/N of the range-bin span. The automatic heuristic attempts to trade off working set sizes (smaller for better L2 hit rates) and kernel launch overhead (smaller for fewer launches). An explicit value for either option is preserved while the other automatic option is selected around it.

The automatic pulse blocking / image tiling logic in the `sarbp` example may change over time, but users can always manually sweep using `--image-tiles` and `-b`.

## Appendix: Per-configuration run times

Full-frame backprojection run times in seconds for every GPU and ComputeType, using the optimal `--image-tiles` per configuration and the default `-b auto` (see [Image Tiling](#image-tiling)). Each cell is `pixel-z variable / pixel-z zero`; `zero` is exact for this planar Z=0 grid and is the value plotted in the figure above. Throughput in Gbp/s can be recovered as (work) / (run time), where the work is 776.2 Gbp for the 8192 x 8192 frame and 10,027.7 Gbp for the 20800 x 20800 frame. `n/r` = not run (`double` at 20k on Thor would take ~3.5 hours).
Full-frame backprojection run times in seconds for every GPU and ComputeType, using a 256-pulse block (`-b 256`) and the optimal `--image-tiles` per configuration (see [Image Tiling](#image-tiling)). Each cell is `pixel-z variable / pixel-z zero`; `zero` is exact for this planar Z=0 grid and is the value plotted in the figure above. Throughput in Gbp/s can be recovered as (work) / (run time), where the work is 776.2 Gbp for the 8192 x 8192 frame and 10,027.7 Gbp for the 20800 x 20800 frame. `n/r` = not run (`double` at 20k on Thor would take ~3.5 hours).

<h4 align="center">8192 x 8192 pixels, 11,566 pulses</h4>

Expand Down
Loading