summaryrefslogtreecommitdiff
path: root/test/correctness/testac.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/correctness/testac.cc')
-rw-r--r--test/correctness/testac.cc191
1 files changed, 191 insertions, 0 deletions
diff --git a/test/correctness/testac.cc b/test/correctness/testac.cc
new file mode 100644
index 00000000..e16186d9
--- /dev/null
+++ b/test/correctness/testac.cc
@@ -0,0 +1,191 @@
+
+// =================================================================================================
+// This file is part of the CLBlast project. The project is licensed under the MIT license. This
+// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
+// width of 100 characters per line.
+//
+// Author(s):
+// Cedric Nugteren <www.cedricnugteren.nl>
+//
+// This file implements the TestAC class (see the header for information about the class).
+//
+// =================================================================================================
+
+#include <algorithm>
+
+#include "correctness/testac.h"
+
+namespace clblast {
+// =================================================================================================
+
+// Constructor, initializes the base class tester and input data
+template <typename T>
+TestAC<T>::TestAC(int argc, char *argv[], const bool silent,
+ const std::string &name, const std::vector<std::string> &options,
+ const Routine clblast_lambda, const Routine clblas_lambda):
+ Tester<T>{argc, argv, silent, name, options},
+ clblast_lambda_(clblast_lambda),
+ clblas_lambda_(clblas_lambda) {
+
+ // Computes the maximum sizes. This allows for a single set of input/output buffers.
+ auto max_dim = *std::max_element(kMatrixDims.begin(), kMatrixDims.end());
+ auto max_ld = *std::max_element(kMatrixDims.begin(), kMatrixDims.end());
+ auto max_offset = *std::max_element(kOffsets.begin(), kOffsets.end());
+
+ // Creates test input data
+ a_source_.resize(max_dim*max_ld + max_offset);
+ c_source_.resize(max_dim*max_ld + max_offset);
+ PopulateVector(a_source_);
+ PopulateVector(c_source_);
+}
+
+// ===============================================================================================
+
+// Tests the routine for a wide variety of parameters
+template <typename T>
+void TestAC<T>::TestRegular(Arguments<T> &args, const std::string &name) {
+ if (!PrecisionSupported()) { return; }
+ TestStart("regular behaviour", name);
+
+ // Computes whether or not the matrices are transposed. Note that we assume a default of
+ // column-major and no-transpose. If one of them is different (but not both), then rotated
+ // is considered true.
+ auto a_rotated = (args.layout == Layout::kColMajor && args.a_transpose != Transpose::kNo) ||
+ (args.layout == Layout::kRowMajor && args.a_transpose == Transpose::kNo);
+ auto c_rotated = (args.layout == Layout::kRowMajor);
+
+ // Iterates over the matrix dimensions
+ for (auto &n: kMatrixDims) {
+ args.n = n;
+ for (auto &k: kMatrixDims) {
+ args.k = k;
+
+ // Computes the second dimensions of the matrices taking the rotation into account
+ auto a_two = (a_rotated) ? n : k;
+ auto c_two = (c_rotated) ? n : n;
+
+ // Iterates over the leading-dimension values and the offsets
+ for (auto &a_ld: kMatrixDims) {
+ args.a_ld = a_ld;
+ for (auto &a_offset: kOffsets) {
+ args.a_offset = a_offset;
+ for (auto &c_ld: kMatrixDims) {
+ args.c_ld = c_ld;
+ for (auto &c_offset: kOffsets) {
+ args.c_offset = c_offset;
+
+ // Computes the buffer sizes
+ auto a_size = a_two * a_ld + a_offset;
+ auto c_size = c_two * c_ld + c_offset;
+ if (a_size < 1 || c_size < 1) { continue; }
+
+ // Creates the OpenCL buffers
+ auto a_mat = Buffer(context_, CL_MEM_READ_WRITE, a_size*sizeof(T));
+ auto r_mat = Buffer(context_, CL_MEM_READ_WRITE, c_size*sizeof(T));
+ auto s_mat = Buffer(context_, CL_MEM_READ_WRITE, c_size*sizeof(T));
+
+ // Iterates over the values for alpha and beta
+ for (auto &alpha: kAlphaValues) {
+ args.alpha = alpha;
+ for (auto &beta: kBetaValues) {
+ args.beta = beta;
+
+ // Runs the reference clBLAS code
+ a_mat.WriteBuffer(queue_, a_size*sizeof(T), a_source_);
+ r_mat.WriteBuffer(queue_, c_size*sizeof(T), c_source_);
+ auto status1 = clblas_lambda_(args, a_mat, r_mat, queue_);
+
+ // Runs the CLBlast code
+ a_mat.WriteBuffer(queue_, a_size*sizeof(T), a_source_);
+ s_mat.WriteBuffer(queue_, c_size*sizeof(T), c_source_);
+ auto status2 = clblast_lambda_(args, a_mat, s_mat, queue_);
+
+ // Tests for equality of the two status codes
+ if (status1 != StatusCode::kSuccess || status2 != StatusCode::kSuccess) {
+ TestErrorCodes(status1, status2, args);
+ continue;
+ }
+
+ // Downloads the results
+ std::vector<T> r_result(c_size, static_cast<T>(0));
+ std::vector<T> s_result(c_size, static_cast<T>(0));
+ r_mat.ReadBuffer(queue_, c_size*sizeof(T), r_result);
+ s_mat.ReadBuffer(queue_, c_size*sizeof(T), s_result);
+
+ // Checks for differences in the output
+ auto errors = size_t{0};
+ for (auto idn0=size_t{0}; idn0<n; ++idn0) {
+ for (auto idn1=size_t{0}; idn1<n; ++idn1) {
+ auto index = idn0*args.c_ld + idn1 + args.c_offset;
+ if (!TestSimilarity(r_result[index], s_result[index])) {
+ errors++;
+ }
+ }
+ }
+
+ // Tests the error count (should be zero)
+ TestErrorCount(errors, n*n, args);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ TestEnd();
+}
+
+// =================================================================================================
+
+// Tests the routine for cases with invalid OpenCL memory buffer sizes. Tests only on return-types,
+// does not test for results (if any).
+template <typename T>
+void TestAC<T>::TestInvalidBufferSizes(Arguments<T> &args, const std::string &name) {
+ if (!PrecisionSupported()) { return; }
+ TestStart("invalid buffer sizes", name);
+
+ // Sets example test parameters
+ args.m = kBufferSize;
+ args.n = kBufferSize;
+ args.k = kBufferSize;
+ args.a_ld = kBufferSize;
+ args.c_ld = kBufferSize;
+ args.a_offset = 0;
+ args.c_offset = 0;
+
+ // Iterates over test buffer sizes
+ const std::vector<size_t> kBufferSizes = {0, kBufferSize*kBufferSize-1, kBufferSize*kBufferSize};
+ for (auto &a_size: kBufferSizes) {
+ for (auto &c_size: kBufferSizes) {
+
+ // Creates the OpenCL buffers. Note: we are not using the C++ version since we explicitly
+ // want to be able to create invalid buffers (no error checking here).
+ auto a = clCreateBuffer(context_(), CL_MEM_READ_WRITE, a_size*sizeof(T), nullptr, nullptr);
+ auto a_mat = Buffer(a);
+ auto r = clCreateBuffer(context_(), CL_MEM_READ_WRITE, c_size*sizeof(T), nullptr, nullptr);
+ auto r_mat = Buffer(r);
+ auto s = clCreateBuffer(context_(), CL_MEM_READ_WRITE, c_size*sizeof(T), nullptr, nullptr);
+ auto s_mat = Buffer(s);
+
+ // Runs the two routines
+ auto status1 = clblas_lambda_(args, a_mat, r_mat, queue_);
+ auto status2 = clblast_lambda_(args, a_mat, s_mat, queue_);
+
+ // Tests for equality of the two status codes
+ TestErrorCodes(status1, status2, args);
+ }
+ }
+ TestEnd();
+}
+
+// =================================================================================================
+
+// Compiles the templated class
+template class TestAC<float>;
+template class TestAC<double>;
+template class TestAC<float2>;
+template class TestAC<double2>;
+
+// =================================================================================================
+} // namespace clblast