Mesh (flat arrays, neighbours) → Two passes (angles, then curvature): read
Benchmarks (bench.json, on the page) → Two passes (angles, then curvature): times every version
Two passes (angles, then curvature) → OpenMP (sequential and parallel): same functions
Two passes (angles, then curvature) → OpenCL (double precision): as kernels
Two passes (angles, then curvature) → CUDA (double and single): same passes
Benchmarks
The same curvature, computed by each version on tori from 50,000 to 3.2 million triangles; median time, adjacency already built, copies to the graphics card included.
Measured on Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz (6 OpenMP threads on 12 logical processors), graphics card NVIDIA GeForce GTX 1660, under WSL 2; median of 7 runs.
Time on 3,198,732 triangles (shorter is better)
Triangles
Sequential C++
OpenMP, 6 threads
OpenCL (processor, PoCL)
CUDA, double precision
CUDA, single precision
49,728
6.95 ms ×1.0
2.60 ms ×2.7
7.54 ms ×0.9
4.13 ms ×1.7
3.18 ms ×2.2
199,362
30.4 ms ×1.0
8.91 ms ×3.4
21.6 ms ×1.4
10.6 ms ×2.9
12.3 ms ×2.5
799,236
112 ms ×1.0
32.2 ms ×3.5
60.9 ms ×1.8
32.4 ms ×3.4
23.9 ms ×4.7
3,198,732
531 ms ×1.0
178 ms ×3.0
332 ms ×1.6
110 ms ×4.8
85.5 ms ×6.2
On the graphics card, in double precision: 33.8 ms copying to the card, 30.5 ms computing, 11.9 ms back, and 33.7 ms on the processor (allocations). In single precision the computation alone drops to 1.94 ms: this consumer card has 32 times fewer double-precision units than single-precision ones. For a single curvature the copies are what costs: computing on the card pays off when the data stays there.
Single precision strays by at most 1.2e-6 on an angle defect: enough to show colours, not to check Gauss-Bonnet to the millionth.
Why OpenMP is not six times faster: the vertex pass reads a lot of memory for little computation, and the bandwidth of this machine under WSL tops out at 5 to 6 GB/s whatever the number of threads (measured); the face pass, for its part, runs 4.5 times faster on 6 cores. With 12 threads, the ones spinning while they wait on the logical cores slow the others down: one thread per physical core is faster here.