diff options
author | CNugteren <web@cedricnugteren.nl> | 2015-06-21 12:57:38 +0200 |
---|---|---|
committer | CNugteren <web@cedricnugteren.nl> | 2015-06-21 12:57:38 +0200 |
commit | 4c2a166bc5406b194108d3b31238e55ac6b99e3c (patch) | |
tree | 9f136083289546836b810fd7bcb2cad3ad7d6fa3 /test/correctness | |
parent | e3829c1067814c0aa83ab440fa431d98837aeeda (diff) |
Added test infrastructure for AB and AC routines
Diffstat (limited to 'test/correctness')
-rw-r--r-- | test/correctness/testab.cc | 192 | ||||
-rw-r--r-- | test/correctness/testab.h | 85 | ||||
-rw-r--r-- | test/correctness/testac.cc | 191 | ||||
-rw-r--r-- | test/correctness/testac.h | 85 |
4 files changed, 553 insertions, 0 deletions
diff --git a/test/correctness/testab.cc b/test/correctness/testab.cc new file mode 100644 index 00000000..ef03f32f --- /dev/null +++ b/test/correctness/testab.cc @@ -0,0 +1,192 @@ + +// ================================================================================================= +// 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 TestAB class (see the header for information about the class). +// +// ================================================================================================= + +#include <algorithm> + +#include "correctness/testab.h" + +namespace clblast { +// ================================================================================================= + +// Constructor, initializes the base class tester and input data +template <typename T> +TestAB<T>::TestAB(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); + b_source_.resize(max_dim*max_ld + max_offset); + PopulateVector(a_source_); + PopulateVector(b_source_); +} + +// =============================================================================================== + +// Tests the routine for a wide variety of parameters +template <typename T> +void TestAB<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 b_rotated = (args.layout == Layout::kRowMajor); + + // Iterates over the matrix dimensions + for (auto &m: kMatrixDims) { + args.m = m; + for (auto &n: kMatrixDims) { + args.n = n; + + // Computes the second dimensions of the matrices taking the rotation into account + auto a_two = (a_rotated) ? n : n; + auto b_two = (b_rotated) ? m : 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 &b_ld: kMatrixDims) { + args.b_ld = b_ld; + for (auto &b_offset: kOffsets) { + args.b_offset = b_offset; + + // Computes the buffer sizes + auto a_size = a_two * a_ld + a_offset; + auto b_size = b_two * b_ld + b_offset; + if (a_size < 1 || b_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, b_size*sizeof(T)); + auto s_mat = Buffer(context_, CL_MEM_READ_WRITE, b_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_, b_size*sizeof(T), b_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_, b_size*sizeof(T), b_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(b_size, static_cast<T>(0)); + std::vector<T> s_result(b_size, static_cast<T>(0)); + r_mat.ReadBuffer(queue_, b_size*sizeof(T), r_result); + s_mat.ReadBuffer(queue_, b_size*sizeof(T), s_result); + + // Checks for differences in the output + auto errors = size_t{0}; + for (auto idm=size_t{0}; idm<m; ++idm) { + for (auto idn=size_t{0}; idn<n; ++idn) { + auto index = (args.layout == Layout::kRowMajor) ? + idm*args.b_ld + idn + args.b_offset: + idn*args.b_ld + idm + args.b_offset; + if (!TestSimilarity(r_result[index], s_result[index])) { + errors++; + } + } + } + + // Tests the error count (should be zero) + TestErrorCount(errors, m*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 TestAB<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.a_ld = kBufferSize; + args.b_ld = kBufferSize; + args.a_offset = 0; + args.b_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 &b_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, b_size*sizeof(T), nullptr, nullptr); + auto r_mat = Buffer(r); + auto s = clCreateBuffer(context_(), CL_MEM_READ_WRITE, b_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 TestAB<float>; +template class TestAB<double>; +template class TestAB<float2>; +template class TestAB<double2>; + +// ================================================================================================= +} // namespace clblast diff --git a/test/correctness/testab.h b/test/correctness/testab.h new file mode 100644 index 00000000..24a9db7c --- /dev/null +++ b/test/correctness/testab.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-mat (A,B) 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_TESTAB_H_ +#define CLBLAST_TEST_CORRECTNESS_TESTAB_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 TestAB: public Tester<T> { + public: + + // Uses several variables from the Tester class + using Tester<T>::context_; + using Tester<T>::queue_; + using Tester<T>::kLayouts; + using Tester<T>::kTransposes; + + // 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; + using Tester<T>::GetOffsets; + using Tester<T>::PrecisionSupported; + + // Test settings for the regular test. Append to this list in case more tests are required. + const std::vector<size_t> kMatrixDims = { 7, 64 }; + const std::vector<size_t> kOffsets = GetOffsets(); + const std::vector<T> kAlphaValues = GetExampleScalars(); + const std::vector<T> kBetaValues = GetExampleScalars(); + + // Test settings for the invalid test + const size_t kBufferSize = 64; + + // Shorthand for a BLAS routine + using Routine = std::function<StatusCode(const Arguments<T>&, + const Buffer&, const Buffer&, + CommandQueue&)>; + + // Constructor, initializes the base class tester and input data + TestAB(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); + + // 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> b_source_; + + // The routines to test + Routine clblast_lambda_; + Routine clblas_lambda_; +}; + +// ================================================================================================= +} // namespace clblast + +// CLBLAST_TEST_CORRECTNESS_TESTAB_H_ +#endif 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 diff --git a/test/correctness/testac.h b/test/correctness/testac.h new file mode 100644 index 00000000..4ab21e23 --- /dev/null +++ b/test/correctness/testac.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-mat (A,C) 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_TESTAC_H_ +#define CLBLAST_TEST_CORRECTNESS_TESTAC_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 TestAC: public Tester<T> { + public: + + // Uses several variables from the Tester class + using Tester<T>::context_; + using Tester<T>::queue_; + using Tester<T>::kLayouts; + using Tester<T>::kTransposes; + + // 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; + using Tester<T>::GetOffsets; + using Tester<T>::PrecisionSupported; + + // Test settings for the regular test. Append to this list in case more tests are required. + const std::vector<size_t> kMatrixDims = { 7, 64 }; + const std::vector<size_t> kOffsets = GetOffsets(); + const std::vector<T> kAlphaValues = GetExampleScalars(); + const std::vector<T> kBetaValues = GetExampleScalars(); + + // Test settings for the invalid test + const size_t kBufferSize = 64; + + // Shorthand for a BLAS routine + using Routine = std::function<StatusCode(const Arguments<T>&, + const Buffer&, const Buffer&, + CommandQueue&)>; + + // Constructor, initializes the base class tester and input data + 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); + + // 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> c_source_; + + // The routines to test + Routine clblast_lambda_; + Routine clblas_lambda_; +}; + +// ================================================================================================= +} // namespace clblast + +// CLBLAST_TEST_CORRECTNESS_TESTAC_H_ +#endif |