diff options
-rw-r--r-- | CMakeLists.txt | 12 | ||||
-rw-r--r-- | test/correctness/testaxy.cc | 209 | ||||
-rw-r--r-- | test/correctness/testaxy.h | 85 |
3 files changed, 305 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f93079d9..b6697ac3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,8 +96,9 @@ include_directories(${clblast_SOURCE_DIR}/include ${OPENCL_INCLUDE_DIRS}) set(KERNELS copy pad transpose padtranspose xaxpy xgemv xgemm) set(SAMPLE_PROGRAMS sgemm) set(ROUTINES_XY xaxpy) +set(ROUTINES_AXY ) set(ROUTINES_ABC xgemm xsymm) -set(ROUTINES ${ROUTINES_XY} ${ROUTINES_ABC}) +set(ROUTINES ${ROUTINES_XY} ${ROUTINES_AXY} ${ROUTINES_ABC}) # ================================================================================================== @@ -169,6 +170,7 @@ if(TESTS) # Creates the common correctness-tests objects (requires CMake 2.8.8) add_library(test_correctness_common OBJECT test/correctness/tester.cc) add_library(test_correctness_xy OBJECT test/correctness/testxy.cc) + add_library(test_correctness_axy OBJECT test/correctness/testaxy.cc) add_library(test_correctness_abc OBJECT test/correctness/testabc.cc) # Compiles the correctness-tests @@ -180,6 +182,14 @@ if(TESTS) target_link_libraries(test_${ROUTINE} clBLAS clblast ${OPENCL_LIBRARIES}) install(TARGETS test_${ROUTINE} DESTINATION bin) endforeach() + foreach(ROUTINE ${ROUTINES_AXY}) + add_executable(test_${ROUTINE} + $<TARGET_OBJECTS:test_correctness_common> + $<TARGET_OBJECTS:test_correctness_axy> + test/correctness/routines/${ROUTINE}.cc) + target_link_libraries(test_${ROUTINE} clBLAS clblast ${OPENCL_LIBRARIES}) + install(TARGETS test_${ROUTINE} DESTINATION bin) + endforeach() foreach(ROUTINE ${ROUTINES_ABC}) add_executable(test_${ROUTINE} $<TARGET_OBJECTS:test_correctness_common> 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 |