Status: current · RTX PRO 6000 Blackwell Max-Q (sm_120), threadripper02, DPC++ 7.2.0 (intel/llvm b87b3566), AdaptiveCpp 25.10.0 generic SSCP (LLVM 20), CUDA 13.2, driver 595.71.05 · measured 2026-10-09
The same source tree built with DPC++ and with AdaptiveCpp (acpp), measured interleaved on one GPU. Auto picks the same route in both trees in all 90 Auto cells. Vendor calls (geo-mean 1.00-1.04) and double gemm (1.00) match DPC++. Float native kernels are slower on acpp in most families, up to 1.70x (geqrf blocked) and 1.56x (getrf tiny); double native kernels lose up to 1.23x outside the 48 KiB cells. The fused small-n syev kernel is faster on acpp, 0.54-0.81x. Every eigenvalue is bit-identical across the two trees. Design and phases: Two SYCL implementations: DPC++ and AdaptiveCpp.
acpp / DPC++ time per call, geometric mean over the cells of the grid. Auto is the shipped route, native the pinned BatchLAS families, vendor the cuBLAS/cuSOLVER family through impl::run_native.
| op | dtype | Auto | native families (min-max) | vendor |
|---|---|---|---|---|
| gemm | float | 1.026 | 1.053 (0.87-1.33) | 1.025 |
| gemm | double | 1.026 | 1.003 (0.97-1.04) | 1.001 |
| potrf | float | 1.076 | 1.175 (0.88-2.30) | 1.028 |
| potrf | double | 1.016 | 1.071 (0.98-1.23) | 1.006 |
| getrf | float | 1.124 | 1.052 (0.61-1.52) | 1.015 |
| getrf | double | 1.017 | 0.935 (0.36-2.47) | 1.018 |
| geqrf | float | 1.263 | 1.188 (0.97-1.68) | 1.036 |
| geqrf | double | 1.052 | 1.076 (0.84-2.66) | 1.012 |
| syev (Auto) | float | 0.950 (0.54-1.37) | ||
| syev (Auto) | double | 1.018 (1.00-1.06) | ||
| steqr_cta | float / double | 1.217 (1.07-1.41) / 1.113 (1.00-1.21) | ||
| syev_cta | float / double | 1.230 (1.04-1.53) / 1.113 (1.00-1.20) | ||
| syev_cta_fused | float / double | 0.661 (0.54-0.81) / 1.089 (0.98-1.19) | ||
| stedc | float / double | 1.096 (1.05-1.14) / 1.013 (1.00-1.03) |
| Item | DPC++ (A) | AdaptiveCpp (B) |
|---|---|---|
| Compiler | /opt/dpcpp-cuda/bin/clang++, DPC++ 7.2.0 pre-release, intel/llvm b87b3566 | /opt/adaptivecpp-25.10.0-cuda13.2/bin/acpp, 25.10.0+git.9f842c7, Ubuntu clang 20.1.2 |
| Tree | build-dpcpp, Release, targets nvptx64-nvidia-cuda (sm_120) + spir64_x86_64 | build-acpp-rel, Release, --acpp-targets=generic (SSCP, PTX JIT at first launch) |
| fp | contract on (driver default), FTZ off | -ffp-contract=on (A11), FTZ off |
| Variant | nolb: as A from a source copy whose BATCHLAS_LAUNCH_BOUNDS is empty (0 .minnctapersm in its PTX; A has 152) | optin: as B plus -DBATCHLAS_ACPP_SLM_OPTIN=ON (build-acpp-rel-optin, budget 97,280 B as on DPC++) |
| Runtime | LD_LIBRARY_PATH=/opt/dpcpp-cuda/lib:/opt/lib | same, plus ACPP_ADAPTIVITY_LEVEL=1, ACPP_RT_SCHEDULER=direct, one ACPP_APPDB_DIR per campaign |
| Source | acpp-dual-build at ddf07744; src/ and include/ unchanged since; uncommitted harness changes (gemm_transpose_benchmark gained BATCHLAS_BENCH_LD_PAD) | same |
Machine: threadripper02, 4x RTX PRO 6000 Blackwell Max-Q (sm_120, 300 W, no display), one NUMA node, CUDA 13.2 from HPC SDK 26.5.
benchviz pins only native/vendor, so the campaign used a dedicated driver (not kept in the repository) over the benchmark binaries: one process per (cell, implementation), each under a GPU guard, coverage on.
Note: reps 0-2 and the first 140 processes of rep 3 ran on GPU 3. At 21:49 another user's job took GPUs 0 and 3 at 300 W, so the rest of reps 3-9 ran on GPU 2 with a guard that tolerates an idle foreign context. The paired acpp/DPC++ ratio moved by a median of 0.000 (p05-p95 0.987-1.018, 425 cells) between the two cards; DPC++ absolute times by +0.6%. Other sessions ran ctest on GPUs 0-1 during 2,538 of the processes. One process that saw the foreign job start was dropped.
acpp / DPC++ time per family; n/a = acpp cannot run it (49,920 B of local memory, A2); empty = not measured at that n. Auto's route is the same in both trees.
float, NN, ld = rows + 3
| n | batch | Auto | vendor | tiled | reg 128x128x8 | reg 64x64x16 | reg 128x64x32 u4 | wide 64x64x16 | small | direct | DPC++ Auto ms | Auto route |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 64 | 4096 | 1.09 | 1.09 | 1.18 | 1.33 | 1.00 | n/a | 1.11 | 1.10 | 1.00 | 0.1828 | vendor |
| 128 | 1024 | 1.03 | 1.04 | 1.17 | 1.08 | 1.01 | n/a | 1.09 | 1.04 | 0.2023 | vendor | |
| 256 | 512 | 1.03 | 1.02 | 1.19 | 1.03 | 0.98 | n/a | 1.03 | 0.593 | vendor | ||
| 512 | 256 | 1.02 | 1.02 | 1.19 | 1.04 | 1.00 | n/a | 1.02 | 1.555 | vendor | ||
| 1024 | 128 | 1.00 | 1.00 | 1.19 | 0.98 | 1.02 | n/a | 1.01 | 6.104 | vendor |
float, NN, ld = rows (packed)
| n | batch | Auto | vendor | reg 128x128x8 | reg 128x64x32 u4 | wide 64x64x16 | DPC++ Auto ms | Auto route |
|---|---|---|---|---|---|---|---|---|
| 64 | 4096 | 1.01 | 1.01 | 1.26 | n/a | 1.01 | 0.1599 | vendor |
| 128 | 1024 | 1.01 | 1.01 | 1.04 | n/a | 1.00 | 0.1795 | vendor |
| 256 | 512 | 1.01 | 1.00 | 1.07 | n/a | 1.00 | 0.5043 | vendor |
| 512 | 256 | 1.00 | 1.00 | 1.08 | n/a | 1.00 | 1.49 | vendor |
| 1024 | 128 | 1.00 | 1.00 | 1.08 | n/a | 1.01 | 5.727 | vendor |
float, TN, ld = rows + 3
| n | batch | Auto | vendor | tiled | reg 64x64x16 | reg 128x32x32 | wide 64x64x16 | direct | DPC++ Auto ms | Auto route |
|---|---|---|---|---|---|---|---|---|---|---|
| 64 | 4096 | 1.09 | 1.10 | 1.17 | 1.02 | 1.02 | 0.99 | 0.87 | 0.1784 | vendor |
| 128 | 1024 | 1.04 | 1.03 | 1.18 | 1.04 | 1.00 | 0.96 | 0.94 | 0.2241 | vendor |
| 256 | 512 | 1.03 | 1.03 | 1.19 | 1.01 | 1.01 | 0.95 | 0.6224 | vendor | |
| 512 | 256 | 1.02 | 1.02 | 1.19 | 1.03 | 1.02 | 0.95 | 1.923 | vendor | |
| 1024 | 128 | 1.00 | 1.00 | 1.19 | 1.04 | 1.03 | 0.98 | 7.693 | vendor |
double (ld = rows + 3 unless marked)
| n | batch | form | Auto | vendor | tiled | wide 64x64x16 | small | direct | DPC++ Auto ms | Auto route |
|---|---|---|---|---|---|---|---|---|---|---|
| 64 | 4096 | NN | 1.03 | 1.00 | 1.03 | 0.98 | 1.01 | 0.97 | 1.366 | tiled |
| 128 | 1024 | NN | 1.02 | 1.00 | 1.02 | 0.99 | 0.97 | 2.606 | tiled | |
| 256 | 512 | NN | 1.03 | 1.00 | 1.03 | 1.00 | 10.81 | tiled | ||
| 512 | 256 | NN | 1.03 | 1.00 | 1.03 | 1.00 | 43.33 | tiled | ||
| 1024 | 128 | NN | 1.04 | 1.00 | 1.03 | 1.00 | 171 | tiled | ||
| 64 | 4096 | TN | 1.03 | 1.00 | 1.03 | 0.98 | 0.98 | 1.362 | tiled | |
| 128 | 1024 | TN | 1.02 | 1.00 | 1.02 | 0.99 | 0.98 | 2.588 | tiled | |
| 256 | 512 | TN | 1.03 | 1.00 | 1.03 | 0.99 | 10.65 | tiled | ||
| 512 | 256 | TN | 1.04 | 1.00 | 1.03 | 1.00 | 42.53 | tiled | ||
| 1024 | 128 | TN | 1.04 | 1.00 | 1.04 | 1.00 | 167.8 | tiled | ||
| 64 | 4096 | NN packed | 1.04 | 1.00 | 0.99 | 1.434 | tiled | |||
| 256 | 512 | NN packed | 1.00 | 1.00 | 1.00 | 10.03 | wide:m=64:n=64:k=16 | |||
| 1024 | 128 | NN packed | 1.00 | 1.00 | 1.00 | 157.3 | wide:m=64:n=64:k=16 |
acpp / DPC++ per pinned family (· = runnable in neither tree, n/a = DPC++ only). Auto columns: the DPC++ time, the route (identical in DPC++, acpp and the opt-in tree), and the acpp and opt-in ratios. geqrf vendor is not run at n >= 256 (cuSOLVER loops over the batch: 0.42 s per call at float n = 512).
potrf float
| n | batch | blocked | cta | lpanel 8 | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 1.25 | 1.27 | 1.01 | 1.24 | 1.08 | 0.01021 | tiny | 1.20 | 1.25 |
| 16 | 16384 | 1.27 | 1.29 | 0.93 | 1.03 | 1.04 | 0.02004 | tiny | 1.02 | 1.07 |
| 32 | 16384 | 1.06 | 1.06 | 0.88 | 0.93 | 0.99 | 0.09037 | tiny | 0.92 | 0.92 |
| 64 | 4096 | 2.30 | n/a | 0.98 | · | 1.04 | 0.1411 | lpanel:panel=8 | 0.95 | 0.95 |
| 128 | 1024 | 1.45 | · | 1.01 | · | 1.02 | 0.1745 | lpanel:panel=8 | 1.00 | 1.00 |
| 256 | 512 | 1.61 | · | 1.36 | · | 0.97 | 0.5152 | lpanel:panel=8 | 1.36 | 1.37 |
| 512 | 256 | 0.99 | · | n/a | · | 1.09 | 1.537 | vendor | 1.00 | 1.00 |
| 1024 | 128 | 1.22 | · | · | · | 1.00 | 4.011 | blocked | 1.23 | 1.06 |
potrf double
| n | batch | blocked | cta | lpanel 8 | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 1.18 | 1.18 | 1.12 | 1.04 | 1.02 | 0.03919 | tiny | 1.04 | 1.04 |
| 16 | 16384 | 1.04 | 1.03 | 1.07 | 1.02 | 1.01 | 0.176 | tiny | 1.01 | 1.01 |
| 32 | 16384 | 1.03 | 1.03 | 1.06 | 1.00 | 1.00 | 0.7648 | lpanel:panel=8 | 1.05 | 1.05 |
| 64 | 4096 | 1.02 | n/a | 1.15 | · | 1.00 | 0.7539 | vendor | 1.00 | 1.00 |
| 128 | 1024 | 1.05 | · | 1.23 | · | 1.00 | 0.9247 | vendor | 1.00 | 1.00 |
| 256 | 512 | 1.04 | · | n/a | · | 1.00 | 2.957 | vendor | 1.00 | 1.00 |
| 512 | 256 | 0.98 | · | · | · | 1.00 | 10.59 | blocked | 1.01 | 1.05 |
| 1024 | 128 | 1.10 | · | · | · | 1.00 | 34.03 | vendor | 1.00 | 1.00 |
getrf float
| n | batch | blocked | cta | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 0.61 | 1.14 | 1.16 | 1.12 | 0.01236 | tiny | 1.16 | 1.16 |
| 16 | 16384 | 0.67 | 1.13 | 1.22 | 1.06 | 0.02504 | tiny | 1.23 | 1.23 |
| 32 | 16384 | 1.00 | 1.05 | 1.52 | 1.00 | 0.1202 | tiny | 1.49 | 1.49 |
| 64 | 4096 | 1.19 | n/a | · | 0.99 | 0.6445 | vendor | 1.00 | 1.00 |
| 128 | 1024 | 1.20 | · | · | 0.99 | 0.9312 | vendor | 1.01 | 1.00 |
| 256 | 512 | 1.08 | · | · | 0.96 | 1.378 | blocked | 1.09 | 1.08 |
| 512 | 256 | 1.07 | · | · | 1.00 | 5.246 | blocked | 1.06 | 1.06 |
| 1024 | 128 | 1.04 | · | · | 1.00 | 20.51 | blocked | 1.03 | 1.02 |
getrf double
| n | batch | blocked | cta | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 0.36 | 1.01 | 1.05 | 1.11 | 0.04029 | vendor | 1.11 | 1.11 |
| 16 | 16384 | 0.50 | 1.01 | 0.98 | 1.01 | 0.1663 | vendor | 1.02 | 1.01 |
| 32 | 16384 | 0.94 | 2.47 | 0.94 | 1.01 | 0.8469 | vendor | 1.01 | 1.01 |
| 64 | 4096 | 0.94 | n/a | · | 1.00 | 1.429 | vendor | 1.00 | 1.00 |
| 128 | 1024 | 0.95 | · | · | 1.00 | 2.405 | vendor | 1.00 | 1.00 |
| 256 | 512 | 1.01 | · | · | 1.00 | 7.244 | vendor | 1.00 | 1.00 |
| 512 | 256 | 1.02 | · | · | 1.00 | 31.21 | vendor | 1.00 | 1.00 |
| 1024 | 128 | 1.02 | · | · | 1.00 | 108.9 | vendor | 1.00 | 1.00 |
geqrf float
| n | batch | blocked | cta | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 1.13 | 1.15 | 1.19 | 1.15 | 0.01392 | tiny | 1.18 | 1.25 |
| 16 | 16384 | 1.12 | 1.11 | 1.00 | 1.03 | 0.05019 | tiny | 0.98 | 1.00 |
| 32 | 16384 | 0.99 | 0.97 | 1.17 | 1.00 | 0.3906 | tiny | 1.13 | 1.13 |
| 64 | 4096 | 1.28 | 1.03 | · | 1.01 | 1.472 | cta | 1.03 | 1.04 |
| 128 | 1024 | 1.68 | · | · | 1.00 | 2.16 | blocked | 1.70 | 1.70 |
| 256 | 512 | 1.52 | · | · | not run | 4.076 | blocked | 1.52 | 1.53 |
| 512 | 256 | 1.37 | · | · | not run | 10.99 | blocked | 1.37 | 1.41 |
| 1024 | 128 | 1.35 | · | · | not run | 29.59 | blocked | 1.35 | 1.35 |
geqrf double
| n | batch | blocked | cta | tiny | vendor | Auto DPC++ ms | Auto route | Auto A/D | Auto opt-in/D |
|---|---|---|---|---|---|---|---|---|---|
| 8 | 16384 | 0.93 | 0.99 | 0.84 | 1.06 | 0.09766 | vendor | 1.08 | 1.08 |
| 16 | 16384 | 0.99 | 0.99 | 1.00 | 1.01 | 0.5599 | vendor | 1.01 | 1.01 |
| 32 | 16384 | 0.96 | 2.66 | 1.08 | 1.00 | 3.835 | vendor | 1.00 | 1.00 |
| 64 | 4096 | 0.97 | n/a | · | 1.00 | 5.499 | vendor | 1.02 | 1.00 |
| 128 | 1024 | 1.11 | · | · | 0.98 | 6.288 | blocked | 1.11 | 1.11 |
| 256 | 512 | 1.12 | · | · | not run | 15.34 | blocked | 1.12 | 1.12 |
| 512 | 256 | 1.04 | · | · | not run | 50.28 | blocked | 1.04 | 1.05 |
| 1024 | 128 | 1.05 | · | · | not run | 174.2 | blocked | 1.05 | 1.05 |
The real-kernel A/B rule for the SscpBackend of sg_partition (design: JIT-time target dispatch): n = 5..32, batch 16384, eigenvectors. Each kernel is called directly, so the route is the function.
| kernel | dtype | n = 5 | 8 | 12 | 16 | 24 | 32 | DPC++ ms at n = 16 |
|---|---|---|---|---|---|---|---|---|
| steqr_cta | float | 1.41 | 1.29 | 1.24 | 1.23 | 1.07 | 1.07 | 0.300 |
| steqr_cta | double | 1.15 | 1.16 | 1.19 | 1.21 | 1.00 | 1.00 | 7.87 |
| syev_cta (sytrd_cta + steqr_cta + back-transform) | float | 1.52 | 1.36 | 1.23 | 1.21 | 1.06 | 1.04 | 0.418 |
| syev_cta | double | 1.16 | 1.18 | 1.17 | 1.20 | 1.00 | 1.00 | 8.53 |
| syev_cta_fused | float | 0.81 | 0.78 | 0.68 | 0.65 | 0.57 | 0.54 | 0.536 |
| syev_cta_fused | double | 1.10 | 1.13 | 1.16 | 1.19 | 0.98 | 0.99 | 8.49 |
Paired 95% CIs are within +-0.02 of every ratio.
| op | dtype | n | batch | DPC++ ms | acpp / DPC++ | opt-in / DPC++ | route (both) |
|---|---|---|---|---|---|---|---|
| stedc | float | 64 / 128 / 256 / 512 / 1024 | 4096 .. 128 | 1.415 / 1.273 / 2.312 / 4.340 / 9.134 | 1.10 / 1.14 / 1.11 / 1.08 / 1.05 | 1.10 / 1.14 / 1.11 / 1.08 / 1.05 | merge Auto |
| stedc | double | 64 / 128 / 256 / 512 / 1024 | 4096 .. 128 | 32.0 / 21.9 / 35.3 / 52.4 / 110.9 | 1.00 / 1.01 / 1.00 / 1.02 / 1.03 | 1.00 / 1.01 / 1.00 / 1.02 / 1.03 | merge Auto |
| syev Auto | float | 8 / 16 / 32 | 16384 | 0.069 / 0.536 / 3.24 | 1.06 / 0.65 / 0.54 | 1.07 / 0.65 / 0.54 | jacobi / cta_fused / cta_fused |
| syev Auto | float | 64 / 256 | 4096 / 512 | 4.16 / 13.4 | 1.29 / 1.36 | 1.29 / 1.37 | blocked |
| syev Auto | float | 1024 | 128 | 280 | 1.12 | 1.12 | two_stage |
| syev Auto | double | 8 / 16 / 32 | 16384 | 0.875 / 5.34 / 44.8 | 1.01 / 1.00 / 1.01 | same | jacobi |
| syev Auto | double | 64 / 256 | 4096 / 512 | 41.7 / 87.3 | 1.02 / 1.06 | same | blocked |
| syev Auto | double | 1024 | 128 | 962 | 1.00 | 1.00 | vendor |
The float blocked syev (1.29-1.36) and two_stage syev (1.12) are the second-largest Auto losses after geqrf float. In two_stage the acpp tree's sub-routes differ only in geqrf cta vs blocked panels (the 48 KiB budget); the opt-in tree matches DPC++'s sub-routes and the same ratio.
acpp drops [[intel::max_work_group_size, min_work_groups_per_cu]] (the JIT emits .maxntid from the launch, no .minnctapersm). The nolb DPC++ tree isolates the attribute: the same compiler with the macro empty. The tiny kernels run at batch 32768 (the batch their bounds were tuned at).
| kernel | dtype | n = 16 | 24 | 32 | DPC++ ms at n = 32 |
|---|---|---|---|---|---|
| getrf tiny, DPC++ no bounds / DPC++ | float / cfloat | 1.01 / 1.00 | 1.00 / 1.01 | 1.00 / 1.00 | 0.238 / 0.624 |
| getrf tiny, acpp / DPC++ | float / cfloat | 1.17 / 0.99 | 1.25 / 1.10 | 1.56 / 1.13 | |
| gesv tiny, DPC++ no bounds / DPC++ | float / cfloat | 1.03 / 1.00 | 1.00 / 1.00 | 1.01 / 1.00 | 0.330 / 0.834 |
| gesv tiny, acpp / DPC++ | float / cfloat | 1.16 / 1.07 | 1.30 / 1.12 | 1.33 / 1.09 | |
| posv tiny, DPC++ no bounds / DPC++ | float / cfloat | 1.03 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 | 0.258 / 0.879 |
| posv tiny, acpp / DPC++ | float / cfloat | 1.15 / 0.98 | 1.29 / 1.10 | 1.34 / 1.11 |
gemm reg 128x128x8 (kMinGroupsPerCu = 2), float NN: DPC++ without bounds / DPC++ = 0.99-1.00 at n = 256, 512, 1024 in both layouts; acpp / DPC++ = 0.98-1.08.
acpp 25.10 caps a launch at 48 KiB of local memory (design: the local-memory budget). can_run routes around it, so a family is n/a, and blocked drivers derive smaller blocks from the 45,056 B budget. The opt-in tree restores the 97,280 B budget; every one of its sub-routes then equals DPC++'s.
| cell | family | acpp / DPC++ | opt-in / DPC++ |
|---|---|---|---|
| potrf float n = 64 | blocked | 2.30 | 1.03 |
| potrf float n = 128 / 256 / 1024 | blocked | 1.45 / 1.61 / 1.22 | 1.20 / 1.07 / 1.06 |
| potrf float n = 1024 | Auto (blocked) | 1.23 | 1.06 |
| potrf float n = 64 | cta | n/a | 1.02 |
| potrf float n = 512, double n = 256 | lpanel 8 | n/a | 1.19, 1.20 |
| getrf float n = 64 | cta | n/a | 1.01 |
| getrf double n = 32 | cta | 2.47 | 1.02 |
| geqrf double n = 32 / 64 | cta | 2.66 / n/a | 0.99 / 0.91 |
| gemm float NN ld+3, n = 64..1024 | reg 128x64x32 u4 | n/a | 1.34-1.75 |
| gemm float NN packed, n = 64 / 128 / 256 / 512 / 1024 | reg 128x64x32 u4 | n/a | 1.19 / 0.98 / 0.86 / 0.80 / 0.77 |
The vendor family is the same cuBLAS/cuSOLVER call in both trees; only the submission differs (DPC++ get_native + create_event_after_external_work, acpp AdaptiveCpp_enqueue_custom_operation).
Saturation. 18 cells re-run at twice the batch (4 reps): per-item time at 2x / 1x.
| cell | family | batch | DPC++ | acpp | acpp/DPC++ at 1x -> 2x |
|---|---|---|---|---|---|
| gemm float NN ld+3 n = 1024 | Auto, reg 128x128x8, tiled | 128 | 1.10, 1.09, 1.01 | 1.09, 1.07, 1.01 | 1.00 -> 1.00, 0.99 -> 0.96, 1.19 -> 1.19 |
| gemm double n = 1024 | wide, vendor (TN) | 128 | 1.00, 1.00 | 1.00, 1.00 | 1.00 -> 1.00 |
| potrf float n = 512 | blocked, vendor | 256 | 0.87, 1.00 | 0.92, 0.96 | 0.99 -> 1.04, 1.09 -> 1.05 |
| potrf double n = 1024 | blocked, vendor | 128 | 1.03, 0.96 | 0.98, 0.96 | 1.10 -> 1.05, 1.00 -> 1.00 |
| getrf float n = 512 / double n = 1024 | blocked | 256 / 128 | 1.04 / 1.03 | 0.98 / 1.02 | 1.07 -> 1.01 / 1.02 -> 1.02 |
| geqrf float n = 512 | blocked | 256 | 0.80 | 0.68 | 1.37 -> 1.17 |
| geqrf double n = 1024 | blocked | 128 | 0.99 | 0.97 | 1.05 -> 1.03 |
| stedc float n = 1024 / double n = 512 | 128 / 256 | 0.96 / 0.97 | 0.95 / 0.97 | 1.05 -> 1.03 / 1.02 -> 1.02 | |
| syev Auto float n = 1024 / double n = 256 | 128 / 512 | 0.85 / 0.97 | 0.81 / 0.92 | 1.12 -> 1.07 / 1.06 -> 1.00 | |
| steqr_cta float / syev_cta double / fused float, n = 16 | 16384 | 0.92 / 0.95 / 0.95 | 0.89 / 0.94 / 0.95 | 1.24 -> 1.20 / 1.20 -> 1.19 / 0.65 -> 0.65 |
geqrf float n = 512, potrf float n = 512 (blocked) and syev float n = 1024 gain more than 10% per item at twice the batch, so they are below saturation at the grid's batch. Their acpp losses shrink with the batch (geqrf 1.37 -> 1.17). Elsewhere the ratio moves by at most 0.06.
Adaptivity level 2 (ACPP_ADAPTIVITY_LEVEL=2, its own JIT database, three throwaway passes; the JIT warning stopped after the second; 6 reps). Every process reuses one shape, which is what level 2 specializes for, so this flatters acpp against AOT DPC++.
| cell | family | DPC++ ms | acpp L1 / DPC++ | acpp L2 / DPC++ |
|---|---|---|---|---|
| gemm float NN ld+3 n = 256 / 1024 | reg 128x128x8 | 0.665 / 7.62 | 1.03 / 0.98 | 0.96 / 0.98 |
| gemm double NN ld+3 n = 256 | wide | 10.1 | 1.00 | 0.99 |
| potrf float n = 32 | blocked / cta / lpanel 8 / tiny | 0.182 / 0.166 / 0.131 / 0.077 | 1.06 / 1.07 / 0.88 / 0.92 | 0.82 / 0.79 / 0.79 / 1.18 |
| getrf float n = 32 | blocked / cta / tiny | 0.188 / 0.368 / 0.111 | 0.99 / 1.05 / 1.54 | 0.78 / 0.89 / 1.17 |
| steqr_cta float n = 16 | 0.294 | 1.26 | 1.21 | |
| syev_cta_fused float n = 16 / syev_cta double n = 8 | 0.538 / 1.52 | 0.65 / 1.18 | 0.62 / 1.18 | |
| stedc double n = 256 | 35.4 | 1.01 | 1.02 |
Level 2 moves the n = 32 factorization cells by up to 0.28 in either direction (potrf cta 1.07 -> 0.79, potrf tiny 0.92 -> 1.18) and the other cells by at most 0.07. Level 1 is the reported setting.
The tables are keyed by device (tuned/*.sm_120.txt), not implementation (design: the performance protocol). For each of the 78 cell groups with two or more runnable pinned families, compare the fastest family per tree:
| group | DPC++ fastest | acpp fastest | DPC++'s pick on acpp | acpp's pick on DPC++ |
|---|---|---|---|---|
| gemm double TN ld+3 n = 128 | tiled | wide 64x64x16 | 1.028x slower | 1.004x slower |
| getrf double n = 8 | vendor | tiny | 1.043x | 1.018x |
| potrf double n = 1024 | blocked | vendor | 1.095x | 1.003x |
Three changes, each a near-tie on DPC++. Auto took the same route in all 90 cells. The data does not support per-implementation tables. The acpp losses are per-kernel code generation, not ranking inversions, and the opt-in tree removes the only systematic ranking effect (A2).
Measured 2026-10-09 on GPU 2 (build-dpcpp against build-acpp-tests, RelWithDebInfo; accuracy does not depend on the build type). scripts/impl_diff.py run runs one accuracy harness in both trees on the same graded inputs (--seed=1234, log10 cond 0..10 in 0.1 bins, 128 matrices per bin, batch 128) and pairs the rows per sample.
| Family (shared inputs) | dtype | n | Bit-identical | B/A median per cond decade | Paired geo-mean B/A | Max paired rel. diff | Flags (t = 2) |
|---|---|---|---|---|---|---|---|
| steqr_accuracy: steqr, steqr_cta, stedc, cuSOLVER syev, NETLIB steqr/sterf/stedc/syev32 (eigenvalues) | float, double | 8, 16, 32 | 100% | 1 | 1 | 0 | 0 |
| eigensolver_accuracy: steqr_cta, stedc, syev_cta, syev_blocked, syevx, syev Auto (eigenvalues) | float, double | 8-256 | 100% | 1 | 1 | 0 | 0 |
| same: residual R, orthogonality O | double | 8-256 | 100% (R), 100.0% (O) | 1 | 1 | 1.2e-12 | 0 |
| same: R, O | float | 8-256 | 81% (R), 83% (O) | 1 | 1 | 2.1e-7 (<= 2 ulp) | 0 |
| orthogonality_accuracy: eigenvectors of steqr, steqr_cta, stedc, syev | double / float | 16-128 | 100.0% / 83% | 1 | 1 | 1.6e-12 / 2.1e-7 | 0 |
| ortho Chol2, Cholesky, ShiftChol3, Householder | double / float | 16-128 | 100% / 82% | 1 | 1 | 6.4e-12 / 2.2e-7 | 0 |
| ortho SVQB, SVQB2 | double | 16-128 | 50% (100% at n <= 32, 0% at n >= 64) | 0.87-1.09 | 0.93-1.05 | 6.7e3 | 0 |
| ortho SVQB, SVQB2 | float | 16-128 | 39% | 0.87-1.04 | 0.89-1.01 | 5.1e3 | 1: SVQB2 n = 64, 1e5, max only (B/A 2.05) |
| ortho CGS2 | float, double | 16-128 | < 1% | 0.98-1.05 | 0.98-1.04 | 2.1 | 0 |
scripts/route_diff.sh capture (ctest -LE slow, GPU 2) in build-dpcpp, build-acpp-tests and the opt-in control build-acpp-slm-optin; decisions paired on the full shape key (op, scalar, m, n, k, batch, uplo, side, diag, trans).
| Comparison | Decision keys | Same algo set | Changed | Only DPC++ | Only acpp |
|---|---|---|---|---|---|
| DPC++ vs acpp (45,056 B budget) | 10,303 / 10,236 | 9,844 | 34 | 425 | 358 |
| DPC++ vs acpp + opt-in (97,280 B) | 10,303 / 10,282 | 10,273 | 1 | 29 | 8 |