SZ sequences prototype for OpenQMC #103
Replies: 4 comments 3 replies
|
Great stuff! As a further easy optimization, you can look into eq (13) in the paper. Because successive pairs of matrices all form a (0,2) sequence, they obey the following equation: P * SZ[d] == SZ[d ^ 1];Where This means that once you evaluate A bit more advanced is equation (41) in the SZ paper. This saves only a handful of operations at 32-bits (haven't checked 16-bit or 64-bit). The exact speedup may differ based on the architecture. On my Nvidia GPU, eq (41) seems faster, on my laptop (Apple M2 GPU) the straightforward diagonal evaluation (as you wrote up here) is slightly better. I do like the simplicity of the current approach, so its definitely fine for a first pass. Will be very curious to see what results you guys get with this construction in practice and if you notice any particular benefits convergence wise compared to Sobol. In my testing, the difference was fairly subtle and it really depends on what your renderer uses dimensions (2,3) of the pattern for in practice. |
|
Hi @wantonsushi, this is great work. Thanks for opening the discussion. I think we should move forward with the PR. The improved quality of the projections is the big draw for me. And the performance scaling with precision is a fantastic addition. As for the implementation options. Now that the gap between vectorization and non-vectorization has further closed, this might be a good opportunity to simplify the code. I would be tempted to drop the SSE and AVX implementations, and also go with just the szReversedIndexShared() variant (just the !defined(CUDA_ARCH) branch). This would have a few benefits. Code becomes easier to maintain, and it leaves the door open to further caching of the index. Users who are using the library as plug-and-play, are likely not making use of SSE or AVX, as these options are off-by-default. We could even remove those build options and the variants on the CI to make the whole experience easier. But open to other opinions. I'm still on the fence with that. Any thoughts @fpsunflower? |
|
Dropping SSE/AVX definitely makes sense if there is no major performance difference anymore. |
|
Sounds good. So for the PR I'll do scalar only, just the A few clarifications:
|


Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
@fpsunflower @joshbainbridge
Following the discussion in #97, I wrote a standalone prototype for SZ sequences and a benchmarking tool to explore the timings vs Sobol at 16, 32, and 64 bits. It shows that SZ is slower than 16-bit SIMD Sobol, but it's increasingly faster at 32 and 64 bits (scalar only, no SIMD for 32/64 bit Sobol was implemented here).
Files
Files are not wired into the library. They compile against the installed headers (
-I include) and produce anoqmc::SzSamplerbesideoqmc::SobolSampler.sz.h-- theSzSampler. Same Owen scramble / shuffle / rotate wrapper asSobolSampler; only the per-dimension evaluator differs. Includes the input reversal hoist Kulla suggested in the PR discussion (reverse the shared index once and reuse it across all dimensions).sz_directions.h-- the Sobol and SZ direction matrices and closed-form programs at 16/32/64 bits, plus the constructions used to verify them.sz_benchmark.cpp-- correctness, step counts, timings.NB: I had to add a .txt postfix to the .h files because GitHub doesn't support uploading .h files, which seems silly...
To build:
Step counts
Shift-mask-xor steps per dimension, re-derived live by factoring each direction matrix:
This shows Sobol's worst dimension grows linearly whereas SZ's grows logarithmically. At 64-bit it's 15 steps versus 44.
Timings
Full 4D draw, SZ vs Sobol, ns per draw. The 16-bit row uses OpenQMC's SIMD path. OpenQMC has no 32/64-bit path, so I implemented those in scalar. SIMD is untested at those widths and would move the numbers.
Timings on a 13th-gen Intel i7-13700H
Correctness
oqmc::szReversedIndexmatches the SZ construction on alloqmc::sobolReversedIndex.Let me know what you think!
Edit: added a net-property check confirming the output is genuinely SZ. re-uploaded
sz_benchmark.cppAll reactions