When running some tests for onemath armpl, we noticed a probable issue with cblas_sdot function, which returns wrong values when input size is large. The failure is reproducible and deterministic, and was seen with armpl 24.10 to 26.7 versions on several SVE and Neon platforms (grace, ampere altra, cix p1)
The same failure also occurs with the **single-threaded** library (`-larmpl`, not just `-larmpl_mp`), so this is not an OpenMP threading issue, even if OpenMP variant is also impacted in the same way (with 2 threads, results fails the same as sequential when size is twice larger, so size/thread is the same).
`cblas_ddot` and `cblas_dsdot` are unaffected.
Reproducer :
g++ repro.cpp -I /path/to/armpl_26.07_gcc/include/ -L /path/to/armpl_26.07_gcc/lib/ -larmpl_mp -fopenmp -o repro
// repro.cpp #include <stdio.h> #include <stdlib.h> #include <cmath> #include <cstdint> #include "armpl.h" template <typename T> void run_dot(const int64_t iNumElements) { const size_t src_size_bytes = (size_t)iNumElements * sizeof(T); T* srcA = (T*) malloc(src_size_bytes); T* srcB = (T*) malloc(src_size_bytes); if (!srcA || !srcB) { printf("> ERROR: malloc failed for %zu bytes\n", src_size_bytes); exit(EXIT_FAILURE); } double sum = 0.0; for (int64_t i = 0; i < iNumElements; ++i) { T v = (T)(sqrt(65504.0 / (double)iNumElements)); srcA[i] = v; srcB[i] = v; sum += (double)v * (double)v; } T result; const int n = (int)iNumElements; if constexpr (std::is_same<T, float>::value) { result = cblas_sdot(n, srcA, 1, srcB, 1); } else { result = cblas_ddot(n, srcA, 1, srcB, 1); } printf("Host (double accum): %lf ArmPL cblas_%cdot: %lf\n", sum, std::is_same<T, float>::value ? 's' : 'd', (double)result); printf("%s\n\n", (fabs((double)result - sum) < 1e-2 * sum + 1e-3) ? "PASS" : "FAIL"); free(srcA); free(srcB); } int main(int argc, char** argv) { if (argc != 2) { printf("Usage: %s <number of elements>\n", argv[0]); printf("Example: %s 268435456\n", argv[0]); return 1; } const int64_t iNumElements = atoll(argv[1]); printf("Elements: %lld\n", (long long)iNumElements); printf("OMP_NUM_THREADS should be set in the environment before running.\n\n"); printf("FP64 dot (cblas_ddot)\n"); run_dot<double>(iNumElements); printf("FP32 dot (cblas_sdot)\n"); run_dot<float>(iNumElements); return EXIT_SUCCESS; }
Fails OMP_NUM_THREADS=1 ./repro 268435456 Elements: 268435456 Host (double accum): 65504.000000 ArmPL cblas_ddot: 65504.000000 PASS FP32 dot (cblas_sdot) Host (double accum): 65503.996094 ArmPL cblas_sdot: 32768.000000 FAIL
Passes OMP_NUM_THREADS=2 ./repro 268435456 Elements: 268435456 Host (double accum): 65504.000000 ArmPL cblas_ddot: 65504.000000 PASS FP32 dot (cblas_sdot) Host (double accum): 65503.996094 ArmPL cblas_sdot: 65535.949219 PASS
Fails with OpenMP OMP_NUM_THREADS=2 ./repro 128000000 Elements: 128000000 Host (double accum): 65503.999820 ArmPL cblas_ddot: 65503.999998 PASS FP32 dot (cblas_sdot) Host (double accum): 65504.002156 ArmPL cblas_sdot: 62726.730469 FAIL