summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorCNugteren <web@cedricnugteren.nl>2015-06-11 07:39:23 +0200
committerCNugteren <web@cedricnugteren.nl>2015-06-11 07:39:23 +0200
commitbdc3444d5c96f71e0c27eb8048346dc28e7b38e2 (patch)
treee18dbe82f59c065a2ea142e3cd08e2e4f2a33f3a /test
parent16c3bb9140bb2a5a6178e05d4757ada1584cb780 (diff)
Added new tester for matrix-vector-vector routines
Diffstat (limited to 'test')
-rw-r--r--test/correctness/testaxy.cc209
-rw-r--r--test/correctness/testaxy.h85
2 files changed, 294 insertions, 0 deletions
diff --git a/test/correctness/testaxy.cc b/test/correctness/testaxy.cc
new file mode 100644
index 00000000..1e01a0e8
--- /dev/null
+++ b/test/correctness/testaxy.cc
@@ -0,0 +1,209 @@
+
+// =================================================================================================
+// 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 TestAXY class (see the header for information about the class).
+//
+// =================================================================================================
+
+#include <algorithm>
+
+#include "correctness/testaxy.h"
+
+namespace clblast {
+// =================================================================================================
+
+// Constructor, initializes the base class tester and input data
+template <typename T>
+TestAXY<T>::TestAXY(const size_t platform_id, const size_t device_id,
+ const std::string &name, const std::vector<std::string> &options,
+ const Routine clblast_lambda, const Routine clblas_lambda):
+ Tester<T>{platform_id, device_id, 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(kMatrixVectorDims.begin(), kMatrixVectorDims.end());
+ auto max_ld = *std::max_element(kMatrixVectorDims.begin(), kMatrixVectorDims.end());
+ auto max_inc = *std::max_element(kIncrements.begin(), kIncrements.end());
+ auto max_offset = *std::max_element(kOffsets.begin(), kOffsets.end());
+
+ // Creates test input data
+ a_source_.resize(max_dim*max_ld + max_offset);
+ x_source_.resize(max_dim*max_inc + max_offset);
+ y_source_.resize(max_dim*max_inc + max_offset);
+ PopulateVector(a_source_);
+ PopulateVector(x_source_);
+ PopulateVector(y_source_);
+}
+
+// ===============================================================================================
+
+// Tests the routine for a wide variety of parameters
+template <typename T>
+void TestAXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
+ TestStart("regular behaviour", name);
+
+ // Computes whether or not the matrix is 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);
+
+ // Iterates over the dimension for the matrix and vectors
+ for (auto &m: kMatrixVectorDims) {
+ args.m = m;
+ for (auto &n: kMatrixVectorDims) {
+ args.n = n;
+
+ // Computes the second dimension of the matrix taking the rotation into account
+ auto a_two = (a_rotated) ? m : n;
+
+ // Iterates over the leading-dimension values and the offsets of the matrix
+ for (auto &a_ld: kMatrixVectorDims) {
+ args.a_ld = a_ld;
+ for (auto &a_offset: kOffsets) {
+ args.a_offset = a_offset;
+
+ // Iterates over the increment-values and the offsets of the vectors
+ for (auto &x_inc: kIncrements) {
+ args.x_inc = x_inc;
+ for (auto &x_offset: kOffsets) {
+ args.x_offset = x_offset;
+ for (auto &y_inc: kIncrements) {
+ args.y_inc = y_inc;
+ for (auto &y_offset: kOffsets) {
+ args.y_offset = y_offset;
+
+ // Computes the buffer sizes
+ auto a_size = a_two * a_ld + a_offset;
+ auto x_size = n * x_inc + x_offset;
+ auto y_size = n * y_inc + y_offset;
+ if (a_size < 1 || x_size < 1 || y_size < 1) { continue; }
+
+ // Creates the OpenCL buffers
+ auto a_mat = Buffer(context_, CL_MEM_READ_WRITE, a_size*sizeof(T));
+ auto x_vec = Buffer(context_, CL_MEM_READ_WRITE, x_size*sizeof(T));
+ auto r_vec = Buffer(context_, CL_MEM_READ_WRITE, y_size*sizeof(T));
+ auto s_vec = Buffer(context_, CL_MEM_READ_WRITE, y_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_);
+ x_vec.WriteBuffer(queue_, x_size*sizeof(T), x_source_);
+ r_vec.WriteBuffer(queue_, y_size*sizeof(T), y_source_);
+ auto status1 = clblas_lambda_(args, a_mat, x_vec, r_vec, queue_);
+
+ // Runs the CLBlast code
+ a_mat.WriteBuffer(queue_, a_size*sizeof(T), a_source_);
+ x_vec.WriteBuffer(queue_, x_size*sizeof(T), x_source_);
+ s_vec.WriteBuffer(queue_, y_size*sizeof(T), y_source_);
+ auto status2 = clblast_lambda_(args, a_mat, x_vec, s_vec, 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(y_size, static_cast<T>(0));
+ std::vector<T> s_result(y_size, static_cast<T>(0));
+ r_vec.ReadBuffer(queue_, y_size*sizeof(T), r_result);
+ s_vec.ReadBuffer(queue_, y_size*sizeof(T), s_result);
+
+ // Checks for differences in the output
+ auto errors = size_t{0};
+ for (auto idn=size_t{0}; idn<n; ++idn) {
+ auto index = idn*y_inc + y_offset;
+ if (!TestSimilarity(r_result[index], s_result[index], kErrorMargin)) {
+ errors++;
+ }
+ }
+
+ // Tests the error count (should be zero)
+ TestErrorCount(errors, 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 TestAXY<T>::TestInvalidBufferSizes(Arguments<T> &args, const std::string &name) {
+ TestStart("invalid buffer sizes", name);
+
+ // Sets example test parameters
+ args.m = kBufferSize;
+ args.n = kBufferSize;
+ args.a_ld = kBufferSize;
+
+ // Iterates over test buffer sizes
+ const std::vector<size_t> kMatrixSizes = {0, kBufferSize*kBufferSize-1, kBufferSize*kBufferSize};
+ const std::vector<size_t> kVectorSizes = {0, kBufferSize - 1, kBufferSize};
+ for (auto &a_size: kMatrixSizes) {
+ for (auto &x_size: kVectorSizes) {
+ for (auto &y_size: kVectorSizes) {
+
+ // Iterates over test increments
+ for (auto &x_inc: kInvalidIncrements) {
+ args.x_inc = x_inc;
+ for (auto &y_inc: kInvalidIncrements) {
+ args.y_inc = y_inc;
+
+ // 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 x = clCreateBuffer(context_(), CL_MEM_READ_WRITE, x_size*sizeof(T), nullptr, nullptr);
+ auto x_vec = Buffer(x);
+ auto r = clCreateBuffer(context_(), CL_MEM_READ_WRITE, y_size*sizeof(T), nullptr, nullptr);
+ auto r_vec = Buffer(r);
+ auto s = clCreateBuffer(context_(), CL_MEM_READ_WRITE, y_size*sizeof(T), nullptr, nullptr);
+ auto s_vec = Buffer(s);
+
+ // Runs the two routines
+ auto status1 = clblas_lambda_(args, a_mat, x_vec, r_vec, queue_);
+ auto status2 = clblast_lambda_(args, a_mat, x_vec, s_vec, queue_);
+
+ // Tests for equality of the two status codes
+ TestErrorCodes(status1, status2, args);
+ }
+ }
+ }
+ }
+ }
+ TestEnd();
+}
+
+// =================================================================================================
+
+// Compiles the templated class
+template class TestAXY<float>;
+template class TestAXY<double>;
+template class TestAXY<float2>;
+template class TestAXY<double2>;
+
+// =================================================================================================
+} // namespace clblast
diff --git a/test/correctness/testaxy.h b/test/correctness/testaxy.h
new file mode 100644
index 00000000..14cc22f4
--- /dev/null
+++ b/test/correctness/testaxy.h
@@ -0,0 +1,85 @@
+
+// =================================================================================================
+// 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 tests any mat-vec-vec (A,X,Y) routine. It contains two types of tests: one testing
+// all sorts of input combinations, and one deliberatly testing with invalid values.
+//
+// =================================================================================================
+
+#ifndef CLBLAST_TEST_CORRECTNESS_TESTAXY_H_
+#define CLBLAST_TEST_CORRECTNESS_TESTAXY_H_
+
+#include <vector>
+#include <string>
+
+#include "correctness/tester.h"
+
+namespace clblast {
+// =================================================================================================
+
+// See comment at top of file for a description of the class
+template <typename T>
+class TestAXY: public Tester<T> {
+ public:
+
+ // Uses several variables from the Tester class
+ using Tester<T>::context_;
+ using Tester<T>::queue_;
+ using Tester<T>::kErrorMargin;
+
+ // Uses several helper functions from the Tester class
+ using Tester<T>::TestStart;
+ using Tester<T>::TestEnd;
+ using Tester<T>::TestSimilarity;
+ using Tester<T>::TestErrorCount;
+ using Tester<T>::TestErrorCodes;
+ using Tester<T>::GetExampleScalars;
+
+ // Test settings for the regular test. Append to this list in case more tests are required.
+ const std::vector<size_t> kMatrixVectorDims = { 7, 64 };
+ const std::vector<size_t> kOffsets = { 0, 10 };
+ const std::vector<size_t> kIncrements = { 1, 2 };
+ const std::vector<T> kAlphaValues = GetExampleScalars();
+ const std::vector<T> kBetaValues = GetExampleScalars();
+
+ // Test settings for the invalid test
+ const std::vector<size_t> kInvalidIncrements = { 0, 1 };
+ const size_t kBufferSize = 64;
+
+ // Shorthand for a BLAS routine
+ using Routine = std::function<StatusCode(const Arguments<T>&,
+ const Buffer&, const Buffer&, const Buffer&,
+ CommandQueue&)>;
+
+ // Constructor, initializes the base class tester and input data
+ TestAXY(const size_t platform_id, const size_t device_id,
+ const std::string &name, const std::vector<std::string> &options,
+ const Routine clblast_lambda, const Routine clblas_lambda);
+
+ // The test functions, taking no inputs
+ void TestRegular(Arguments<T> &args, const std::string &name);
+ void TestInvalidBufferSizes(Arguments<T> &args, const std::string &name);
+
+ private:
+
+ // Source data to test with
+ std::vector<T> a_source_;
+ std::vector<T> x_source_;
+ std::vector<T> y_source_;
+
+ // The routines to test
+ Routine clblast_lambda_;
+ Routine clblas_lambda_;
+};
+
+// =================================================================================================
+} // namespace clblast
+
+// CLBLAST_TEST_CORRECTNESS_TESTAXY_H_
+#endif