-
Notifications
You must be signed in to change notification settings - Fork 2
Benchmarks
vszipcl vs its installed reference filter at 1080p YUV420 in three sample types
(u16 = YUV420P16, f16 = YUV420PH, f32 = YUV420PS). All numbers are frames/second
(higher is better), produced by the repo's benchmark/
harness.
Reproduce with:
pwsh benchmark/run.ps1 # sweeps u16/f16/f32 x num_streams {1,2}, 2000 frames each- Hardware: NVIDIA GeForce RTX 3070 Ti (OpenCL / CUDA). The EEDI3 CPU reference runs on an AMD Ryzen 7 5700X3D (8C/16T). Same machine for all rows.
-
Build:
zig build -Doptimize=ReleaseFast; VapourSynth R77. -
Filter-bound source: a flat 1080p
BlankClip(decode ≈ 0; none of these filters early-out on flat content, so the fps is the filter's own throughput). -
Timing: each
*.vpysets one output node and is rendered withvspipe file.vpy .(output discarded) over 2000 frames; the fps is vspipe's own.core.num_threads = 8, so vspipe pulls frames concurrently — that is what letsnum_streams(GPU) and CPU threads scale. -
num_streams: shown at 1 and 2 where the filter/reference exposes the knob. References
without it (
placebo,knlm, CPUvszip) show a single row. - — means the reference does not accept that sample type (see per-filter notes).
-
Matched work: vszipcl was ported to mirror each reference, so both run equivalent params
(listed per filter). vszipcl's default
num_streamsis 1.
One machine's numbers; ratios matter more than absolutes, and a different GPU/driver will shift them. GPU boost clocks drift ~±5% run to run.
sigma_spatial=3, sigma_color=0.02
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| vszipcl (s=1) | 312.8 | 296.0 | 205.6 |
| vszipcl (s=2) | 391.1 | 391.3 | 289.9 |
| bilateralgpu (s=1) | 99.3 | — | 199.9 |
| bilateralgpu (s=2) | 181.2 | — | 244.6 |
vszipcl is ~2.2× bilateralgpu on u16 (it moves 1 byte/sample and converts on-device, while
bilateralgpu converts on the CPU and moves f32 over PCIe) and ~1.2× on f32. bilateralgpu rejects
half-float, so f16 is vszipcl-only. This is also the filter where num_streams=2 helps most
(+25–41% for vszipcl, up to +82% for bilateralgpu on u16).
iterations=1, threshold=4, radius=16, grain=6
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| vszipcl (s=1) | 882.8 | 889.3 | 458.3 |
| vszipcl (s=2) | 877.2 | 887.3 | 458.7 |
| placebo | 569.5 | 585.9 | 337.2 |
vszipcl is ~1.35–1.55× placebo across formats. The single deband kernel already saturates the
GPU, so num_streams=2 is neutral (placebo has no streams knob).
Three sigmas:
sigma=1 is the fused small-radius smem kernel; sigma=100/250 take the large separable path.
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| sigma=1 (s=1) | 522.2 | 544.2 | 320.9 |
| sigma=1 (s=2) | 501.8 | 503.6 | 326.7 |
| sigma=100 (s=1) | 266.1 | 264.1 | 203.8 |
| sigma=100 (s=2) | 268.2 | 273.4 | 213.5 |
| sigma=250 (s=1) | 148.1 | 153.0 | 128.7 |
| sigma=250 (s=2) | 153.4 | 156.3 | 133.8 |
Throughput falls with radius (larger kernel = more work per pixel). num_streams=2 is neutral for
the saturated small-sigma kernel and gives only a few percent on the large separable path.
field=1, mdis=40, nrad=3
EEDI3 (vertical)
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| vszipcl (s=1) | 76.1 | 76.3 | 69.9 |
| vszipcl (s=2) | 78.3 | 77.9 | 73.6 |
| vszip (CPU) | — | — | 54.2 |
EEDI3H (horizontal)
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| vszipcl (s=1) | 76.2 | 76.6 | 70.4 |
| vszipcl (s=2) | 79.5 | 78.7 | 75.3 |
| vszip (CPU) | — | — | 56.1 |
vszipcl is ~1.35× the CPU EEDI3. The barrier-bound DP means a second stream adds little (~+3–5%).
d=1, a=2, s=4, h=1.2
| Implementation | u16 | f16 | f32 |
|---|---|---|---|
| vszipcl (s=1) | 151.0 | 145.8 | 117.8 |
| vszipcl (s=2) | 155.3 | 154.7 | 121.2 |
| nlm_cuda (s=1) | 83.2 | — | 64.3 |
| nlm_cuda (s=2) | 88.3 | — | 73.3 |
| knlm | 75.8 | 75.5 | 62.4 |
vszipcl is ~1.65–1.76× nlm_cuda and ~1.95–2.05× knlm on the shared formats. nlm_cuda
rejects half-float (f16 is vszipcl-vs-knlm only); knlm has no streams knob.
-
When
num_streams>1helps: occupancy/transfer-bound filters — Bilateral most of all (+25–41% for vszipcl, up to +82% for bilateralgpu on u16), then NLMeans and large-σ GaussBlur (a few percent). Deband and small-σ GaussBlur are neutral (a single kernel already saturates the GPU), and EEDI3's barrier-bound DP scales little (~+3–5%). That's why the default is 1 — raise it where it pays. -
Narrow io wins:
u16/f16beatf32for the transfer-bound filters because vszipcl moves the wire format end-to-end and converts on-device (half the PCIe/VRAM traffic). - vszipcl leads every head-to-head comparison here; the remaining gap to native CUDA (Bilateral
f32) is inherent — NVIDIA's OpenCL compiler vs
nvccplus CUDA's async smem loads.