Vulkan Linear Math benchmark

Complete F32 and F64 coverage for OA's packed Vulkan-native spatial math, with equivalent arithmetic separated from the validation work that GLM does not perform.

Working-tree qualification50 operations · F32/F64Measured 2026-08-30

All equivalent arithmetic reached parity or better

The expanded harness covers 50 operation families in both precisions: 100 correctness-gated OA/GLM pairs. All 27 families with equivalent valid-input arithmetic were at parity or faster in both F32 and F64. Across those rows, OA used 13.4% less time by geometric mean for F32and 11.9% less for F64 on the qualified host.

Evidence sliceQualified result
Coverage50 operation families × F32/F64; all 100 whole-workload checksum oracles passed
Equivalent arithmetic27/27 families at parity or faster in F32 and 27/27 in F64; parity threshold ≤1.03×
Arithmetic geometric mean0.866× for F32 and 0.881× for F64: 13.4% and 11.9% lower time
Mat4 multiplication0.622× GLM time in F32; 0.975× in F64
TRS composition0.358× GLM time in F32; 0.322× in F64
Translation / scale construction0.418–0.472× GLM time across both precisions
Hardened operations23 checked or fail-closed public routes reported separately from raw GLM peers

This is fixed-host evidence for one compiler, CPU, dataset, packed ABI, and date—not a universal or fastest-library claim. The result retains OA's Vulkan convention, packed value ABI, overflow fallbacks, validation, and fail-closed behavior.

Small host values, one spatial convention

VLM means Vulkan Linear Math. It is OA's immediate host-side spatial-math layer for cameras, UI, rendering, animation, SDK simulation, and format conversion—not a vision-language model and not a second oa::Matrix engine. Values are trivially copyable and functions are stateless; VLM owns no engine, allocation, operation graph, Vulkan handle, or session.

ContractCurrent VLM surface
ValuesVec2/3/4, DVec2/3/4, Quat/DQuat, Mat3/DMat3, and Mat4/DMat4
ABIPacked standard-layout scalar values with exact F32 sizes; no public SIMD alignment
AxesRight-handed; +X right, +Y up, camera-forward −Z
MatricesRow-major storage and row-vector multiplication: transformed = value * matrix
ProjectionVulkan normalized-device-coordinate depth [0, 1]
Raster YSelected once through viewport state; no hidden constructor flip
InteropUnits, axes, handedness, and quaternion order convert once at the boundary

Operators forward to one named implementation in oa::vlm. There is no FnVlm: this is immediate scalar math, unlike schema-owned device work. The surface covers vector geometry, robust quaternion math, all six Euler orders, fixed-shape matrix algebra, checked inverses, affine decomposition, TRS, view and projection families, and top-origin viewport project/unproject.

Optimized without weakening the contract

Implementation seamCurrent routePreserved behavior
NormalizationDirect ordinary-value squared norm; scale-first fallback for finite subnormal or extreme valuesZero/non-finite failure and robust overflow/underflow behavior
Fixed-shape matricesUnrolled Mat3/Mat4 add, transpose, transform, and multiply pathsPacked row-major ABI and row-vector convention
DeterminantFast finite direct formula with guarded out-of-line scaled-pivot fallbackOverflow and non-finite handling retained
Affine workSpecialized affine inverse, translation, scale, and direct TRS compositionChecked singularity, conditioning, and output preservation retained
Geometry and rotationFaster checked projection, angle, look-at, quaternion, and interpolation routesDegenerate geometry and invalid tolerances still fail closed
SIMD evidenceDedicated BenchSimd retains the former FnSimd/xsimd comparisonVLM stays packed scalar math; batch SIMD remains a separate contract

The largest wins come from fixed-shape work: Mat4 multiplication is explicitly unrolled, TRS composition writes the known affine form directly, and translation and scale constructors no longer route through generic matrix work.

Qualified protocol

FieldRecorded value
OA treeDirty qualification tree based on 15b18f0fa1676a5c2c568345fdfc4f22a0256d6f
PeerGLM 1.1.0 source archive; not an OA product or package dependency
Peer manifest2134e2062c2a98ee535a16308780dccfd844f5945d303369a83547a0c8109c49
Executablebin/release/test/core/vlm/benchVlm
Compiler / buildClang 22.1.8; Release; C++20; -O3 -DNDEBUG -march=native
HostIntel Core i5-1145G7; 4 physical cores / 8 threads; Linux 7.1.8
Pinning / powerCPU 2; intel_pstate powersave governor; balanced platform profile
Workload65,536 deterministic values per case; 50 cases; F32 and F64
Inner estimator3 warmups; 15 measured samples; median; alternating OA/GLM order
Outer estimator2 fresh-process warmups; 7 measured fresh processes; 3-second cooldown
Thermal gatePackage temperature ≤65 C before each process; measured starts 58–64 C
CorrectnessWhole-case checksum oracle before timing; all 100 precision/case pairs passed
Stability metricMat4 multiply: 8.714 ns/item median; 1.83% relative MAD; 13.34% min–max spread

A later full repeat reached 45.8% absolute timing spread under laptop throttling and was rejected. The tables retain the earlier thermally stable seven-process campaign. The Mat3-addition row is a focused seven-process follow-up after its fixed-width unroll; it supersedes that one full-suite row without changing the other 49 cases.

Equivalent arithmetic

Each time cell reports OA then GLM median nanoseconds per item. Ratios divide OA time by GLM time, so lower is better; values through 1.03× are classified as parity.

OperationF32 OA / GLM nsF32 ratioF64 OA / GLM nsF64 ratio
Vec2 add1.003 / 1.0031.000×1.011 / 1.0140.997×
Vec2 dot1.003 / 1.0031.000×0.986 / 1.0220.965×
Vec3 add0.935 / 0.9960.938×1.962 / 1.9900.986×
Vec3 component multiply0.973 / 1.0040.969×1.804 / 1.9000.950×
Vec3 dot1.005 / 1.0041.001×1.604 / 1.6580.967×
Vec3 cross1.076 / 1.1300.952×1.815 / 1.8360.988×
Vec3 reflect1.871 / 2.1480.871×2.481 / 2.6170.948×
Vec3 lerp1.134 / 1.3800.822×1.942 / 2.0910.929×
Vec3 refract3.084 / 3.0860.999×3.363 / 3.5100.958×
Vec4 add1.147 / 1.1241.020×3.145 / 3.1830.988×
Vec4 dot1.038 / 1.0910.951×2.660 / 2.6790.993×
Quaternion multiply2.572 / 2.5221.020×3.470 / 3.7820.918×
Mat3 × Vec32.406 / 2.6040.924×4.936 / 5.1960.950×
Mat3 add3.813 / 3.8580.988×6.909 / 6.9730.991×
Mat3 transpose1.927 / 1.8841.023×4.398 / 4.4410.990×
Mat3 multiply5.392 / 5.7530.937×7.754 / 8.7150.890×
Mat3 determinant1.611 / 1.5951.010×4.464 / 4.4181.010×
Mat4 × Vec44.820 / 5.0430.956×8.153 / 8.4470.965×
Mat4 add7.595 / 7.6780.989×11.921 / 12.1050.985×
Mat4 transpose4.928 / 5.1060.965×8.543 / 8.5411.000×
Mat4 multiply8.714 / 14.0150.622×13.530 / 13.8800.975×
Mat4 determinant5.830 / 5.6791.026×9.499 / 9.2941.022×
Transform point4.777 / 4.8920.977×8.353 / 8.5780.974×
Transform direction4.726 / 4.8750.969×8.323 / 8.7780.948×
Compose TRS8.263 / 23.0680.358×11.437 / 35.4690.322×
Translation matrix0.912 / 2.1830.418×0.940 / 1.9920.472×
Scale matrix0.960 / 2.1200.453×1.031 / 2.2820.452×

Checked and fail-closed operations

These rows are deliberately separate. OA normalizes non-unit quaternions, handles finite subnormal and extreme magnitudes, rejects invalid tolerances and degenerate geometry, estimates inverse conditioning, verifies inverse residuals, preserves outputs on failure, and fails closed from direct APIs. The GLM peer performs its raw valid-input operation. A ratio above one measures current safety cost, not an equivalent-work regression.

OperationF32 OA / GLM nsF32 ratioF64 OA / GLM nsF64 ratio
Vec2 normalize2.197 / 1.5071.457×2.677 / 2.7280.981×
Vec3 length1.836 / 1.0251.791×1.894 / 1.5121.252×
Vec3 distance1.197 / 1.2200.981×2.080 / 2.0351.022×
Vec3 normalize3.145 / 2.1021.496×3.177 / 2.7911.138×
Vec3 project · checked3.229 / 2.0721.558×3.656 / 2.6331.388×
Vec3 angle · checked16.780 / 14.4371.162×14.348 / 13.2501.083×
Vec4 normalize3.710 / 2.5361.463×3.598 / 2.9781.208×
Quaternion inverse · checked8.688 / 3.1122.792×10.554 / 4.1812.524×
Quaternion normalize3.452 / 2.3891.445×3.538 / 2.8351.248×
Quaternion rotate4.518 / 3.7021.220×4.963 / 3.8841.278×
Quaternion nlerp7.889 / 3.2522.426×10.309 / 4.6952.196×
Quaternion slerp31.960 / 19.9921.599×46.304 / 38.0701.216×
Quaternion to Mat45.658 / 4.7751.185×8.895 / 4.9311.804×
Mat3 inverse · checked24.288 / 6.1183.970×28.541 / 7.6383.737×
Mat4 inverse · checked33.801 / 30.6001.105×38.523 / 26.7981.438×
Affine inverse · checked48.343 / 11.1104.351×54.682 / 13.1954.144×
Normal matrix · checked30.341 / 6.2174.880×36.227 / 8.0454.503×
Decompose TRS · checked76.976 / 61.5031.252×85.118 / 71.0211.198×
Look at · checked29.614 / 15.6841.888×35.753 / 17.8672.001×
Perspective · checked22.175 / 11.5591.918×21.546 / 9.9282.170×
Project point · checked4.496 / 3.3581.339×5.321 / 3.5971.479×
Viewport project · checked12.442 / 6.8971.804×14.192 / 6.8302.078×
Viewport unproject · checked78.807 / 4.52817.404×86.966 / 31.7132.742×

Checked viewport unprojection is the clearest remaining optimization seam because it performs a checked general inverse for every point. The correct next route is a checked precomputed-inverse or bulk-unproject contract—not deleting singularity, finiteness, residual, or output-preservation guarantees. Conditioned Mat3, affine inverse, and normal-matrix paths remain visible for the same reason.

Correctness before timing

BenchVlm executes each complete OA and GLM workload before timing, compares whole-workload checksums, and rejects non-finite or mismatched results. Timed samples alternate OA-first and GLM-first order. Unknown arguments fail instead of silently changing the workload.

GateScopeRecorded result
ReleaseTestVlm, TestCamera, TestScene, TestTransform, TestSkeleton5 / 5 executables passed
ASANThe same five VLM and direct-consumer executables5 / 5 passed; no sanitizer report
UBSANThe same five VLM and direct-consumer executables5 / 5 passed; no sanitizer report
VLM contractF32/F64 ABI, geometry, quaternion, matrix, affine, projection, and viewport behavior39 / 39 TestVlm cases passed
Benchmark oracle50 operation families in F32 and F64100 / 100 whole-workload pairs passed before timing
Source hygieneChanged VLM source, harness, tests, and evidencegit diff --check passed

Failure and precision behavior remains explicit

OperationCurrent behavior
NormalizationOrdinary finite values use the direct path; subnormal/extreme values use scale-first arithmetic; zero and non-finite inputs fail closed
Checked outputInvalid or undefined checked operations leave output unchanged; successful aliasing is supported where specified
InverseRejects singular, non-finite, poorly conditioned, or residual-failing results rather than returning an unchecked matrix
Projection / viewRejects invalid ranges, non-finite inputs, singular poses, and degenerate camera bases
Matrix to quaternionRejects scale, shear, reflection, singularity, and non-finite input before private extraction
Euler conversionNames radians or degrees and one of six explicit application orders; no default interchange order
Scalar divisionUses ordinary IEEE floating-point behavior

The public VLM value surface is C++ only today. There is no dedicated Python VLM binding, and the benchmark is CPU evidence—not evidence about GPU oa::Matrixexecution or oa::FnSimd batch arrays.

Reproduce the comparison

Use the GLM 1.1.0 archive matching the manifest above. Preserve the item count, precision matrix, alternating order, process count, cooldown, thermal gate, and whole-case correctness contract when refreshing the result.

Vlm benchmark terminal

cmake -S . -B build/release \
-DOA_VLM_GLM_ROOT=/absolute/path/to/glm-1.1.0
cmake --build build/release --target BenchVlm TestVlm
python3 tools/diagnostics/oaBench.py \
--output var/benchmark/vlm-glm.json \
--name core.vlm_glm_suite \
--command-id benchVlm_glm_1_1_0_f32_f64 \
--contract peer=glm-1.1.0 --contract precision=f32-f64 \
--contract cases=50 --contract items=65536 \
--contract oracle=whole-case-checksum --contract order=alternating \
--warmup 2 --runs 7 --cooldown 3 --timeout 300 \
--thermal-limit-celsius 65 --thermal-sensor-regex 'Package id 0' \
--thermal-timeout 300 \
--metric-regex 'PAIR precision=f32 case=mat4_mul contract=arithmetic oa_ns=([0-9.]+)' \
--metric-name mat4_mul_oa --metric-unit ns/op \
--require-regex 'BENCHMARK oracle=PASS' \
--cmake-cache build/release/CMakeCache.txt -- \
taskset -c 2 bin/release/test/core/vlm/benchVlm \
--items 65536 --warmups 3 --samples 15 --precision both

Run the focused gates

Vlm verification terminal

cmake --build build/release --target \
TestVlm TestCamera TestScene TestTransform TestSkeleton
ctest --test-dir build/release \
-R '^(TestVlm|TestCamera|TestScene|TestTransform|TestSkeleton)$' \
--output-on-failure
cmake --build build/asan --target \
TestVlm TestCamera TestScene TestTransform TestSkeleton
ctest --test-dir build/asan \
-R '^(TestVlm|TestCamera|TestScene|TestTransform|TestSkeleton)$' \
--output-on-failure
cmake --build build/ubsan --target \
TestVlm TestCamera TestScene TestTransform TestSkeleton
ctest --test-dir build/ubsan \
-R '^(TestVlm|TestCamera|TestScene|TestTransform|TestSkeleton)$' \
--output-on-failure

This remains a working-tree qualification. Installed-package, compiler-matrix, shader-boundary, source-audit automation, and exact external-format fixtures retain their own release gates.