Merge pull request #5 from CNugteren/improved_testing

Improved testing infrastructure
This commit is contained in:
Cedric Nugteren 2015-06-20 17:02:23 +02:00
commit e19893ff15
17 changed files with 172 additions and 113 deletions

View file

@ -1,17 +1,18 @@
Development version (next release)
- Added support for complex conjugate transpose
- Some host-code performance improvements
- Several host-code performance improvements
- Improved testing infrastructure and coverage
- Added level-2 routines:
SGEMV/DGEMV/CGEMV/ZGEMV
* SGEMV/DGEMV/CGEMV/ZGEMV
- Added level-3 routines:
CGEMM/ZGEMM
CSYMM/ZSYMM
* CGEMM/ZGEMM
* CSYMM/ZSYMM
Version 0.1.0
- Initial preview version release to GitHub
- Supported level-1 routines:
SAXPY/DAXPY/CAXPY/ZAXPY
* SAXPY/DAXPY/CAXPY/ZAXPY
- Supported level-3 routines:
SGEMM/DGEMM
SSYMM/DSYMM
* SGEMM/DGEMM
* SSYMM/DSYMM

View file

@ -225,5 +225,4 @@ To-do list before release of version 1.0
- Further reduce the likelihood of crashes:
* Add checks for proper command-line arguments in the tuner, tester and client
* Add checks for valid database parameters
* Distinguish between short (smoke) and long tests
* Test in multi-threaded environments

View file

@ -29,10 +29,6 @@ namespace clblast {
class Routine {
public:
// Khronos OpenCL extensions
const std::string kKhronosHalfPrecision = "cl_khr_fp16";
const std::string kKhronosDoublePrecision = "cl_khr_fp64";
// The cache of compiled OpenCL programs, along with some meta-data
struct ProgramCache {
Program program;

View file

@ -31,6 +31,10 @@ namespace clblast {
using float2 = std::complex<float>;
using double2 = std::complex<double>;
// Khronos OpenCL extensions
const std::string kKhronosHalfPrecision = "cl_khr_fp16";
const std::string kKhronosDoublePrecision = "cl_khr_fp64";
// =================================================================================================
// The routine-specific arguments in string form
@ -64,6 +68,9 @@ constexpr auto kArgStepSize = "step";
constexpr auto kArgNumSteps = "num_steps";
constexpr auto kArgNumRuns = "runs";
// The client-specific arguments in string form
constexpr auto kArgFullTest = "full_test";
// The common arguments in string form
constexpr auto kArgPlatform = "platform";
constexpr auto kArgDevice = "device";
@ -105,6 +112,8 @@ struct Arguments {
size_t step = 1;
size_t num_steps = 0;
size_t num_runs = 10;
// Tester-specific arguments
bool full_test = false;
// Common arguments
size_t platform_id = 0;
size_t device_id = 0;
@ -143,6 +152,10 @@ bool CheckArgument(const int argc, char *argv[], std::string &help, const std::s
// Returns a random number to be used as a seed
unsigned int GetRandomSeed();
// Test/example data lower and upper limit
constexpr auto kTestDataLowerLimit = -2.0;
constexpr auto kTestDataUpperLimit = 2.0;
// Populates a vector with random data
template <typename T>
void PopulateVector(std::vector<T> &vector);

View file

@ -159,16 +159,21 @@ Precision GetPrecision(const int argc, char *argv[]) {
bool CheckArgument(const int argc, char *argv[], std::string &help,
const std::string &option) {
// Updates the help message
help += " -"+option+"\n";
// Parses the argument. Note that this supports both the given option (e.g. -device) and one with
// an extra dash in front (e.g. --device).
auto return_value = false;
for (int c=0; c<argc; ++c) {
auto item = std::string{argv[c]};
if (item.compare("-"+option) == 0 || item.compare("--"+option) == 0) { ++c; return true; }
if (item.compare("-"+option) == 0 || item.compare("--"+option) == 0) {
++c;
return_value = true;
}
}
return false;
// Updates the help message and returns
help += " -"+option+" ";
help += (return_value) ? "[true]\n" : "[false]\n";
return return_value;
}
// =================================================================================================
@ -182,8 +187,10 @@ unsigned int GetRandomSeed() {
// Create a random number generator and populates a vector with samples from a random distribution
template <typename T>
void PopulateVector(std::vector<T> &vector) {
auto lower_limit = static_cast<T>(kTestDataLowerLimit);
auto upper_limit = static_cast<T>(kTestDataUpperLimit);
std::mt19937 mt(GetRandomSeed());
std::uniform_real_distribution<T> dist(static_cast<T>(-2.0), static_cast<T>(2.0));
std::uniform_real_distribution<T> dist(lower_limit, upper_limit);
for (auto &element: vector) { element = dist(mt); }
}
template void PopulateVector<float>(std::vector<float>&);
@ -192,14 +199,18 @@ template void PopulateVector<double>(std::vector<double>&);
// Specialized versions of the above for complex data-types
template <>
void PopulateVector(std::vector<float2> &vector) {
auto lower_limit = static_cast<float>(kTestDataLowerLimit);
auto upper_limit = static_cast<float>(kTestDataUpperLimit);
std::mt19937 mt(GetRandomSeed());
std::uniform_real_distribution<float> dist(-2.0f, 2.0f);
std::uniform_real_distribution<float> dist(lower_limit, upper_limit);
for (auto &element: vector) { element.real(dist(mt)); element.imag(dist(mt)); }
}
template <>
void PopulateVector(std::vector<double2> &vector) {
auto lower_limit = static_cast<double>(kTestDataLowerLimit);
auto upper_limit = static_cast<double>(kTestDataUpperLimit);
std::mt19937 mt(GetRandomSeed());
std::uniform_real_distribution<double> dist(-2.0, 2.0);
std::uniform_real_distribution<double> dist(lower_limit, upper_limit);
for (auto &element: vector) { element.real(dist(mt)); element.imag(dist(mt)); }
}

View file

@ -46,19 +46,13 @@ void XaxpyTest(int argc, char *argv[], const bool silent, const std::string &nam
return static_cast<StatusCode>(status);
};
// Selects the platform and device on which to test (command-line options)
auto help = std::string{"Options given/available:\n"};
const auto platform_id = GetArgument(argc, argv, help, kArgPlatform, size_t{0});
const auto device_id = GetArgument(argc, argv, help, kArgDevice, size_t{0});
if (!silent) { fprintf(stdout, "\n* %s\n", help.c_str()); }
// Initializes the other arguments relevant for this routine
// Initializes the arguments relevant for this routine
auto args = Arguments<T>{};
const auto options = std::vector<std::string>{kArgN, kArgXInc, kArgYInc,
kArgXOffset, kArgYOffset, kArgAlpha};
// Creates a tester
TestXY<T> tester{platform_id, device_id, name, options, clblast_lambda, clblas_lambda};
TestXY<T> tester{argc, argv, silent, name, options, clblast_lambda, clblas_lambda};
// Runs the tests
const auto case_name = "default";

View file

@ -56,13 +56,7 @@ void XgemmTest(int argc, char *argv[], const bool silent, const std::string &nam
return static_cast<StatusCode>(status);
};
// Selects the platform and device on which to test (command-line options)
auto help = std::string{"Options given/available:\n"};
const auto platform_id = GetArgument(argc, argv, help, kArgPlatform, size_t{0});
const auto device_id = GetArgument(argc, argv, help, kArgDevice, size_t{0});
if (!silent) { fprintf(stdout, "\n* %s\n", help.c_str()); }
// Initializes the other arguments relevant for this routine
// Initializes the arguments relevant for this routine
auto args = Arguments<T>{};
const auto options = std::vector<std::string>{kArgM, kArgN, kArgK, kArgLayout,
kArgATransp, kArgBTransp,
@ -70,7 +64,7 @@ void XgemmTest(int argc, char *argv[], const bool silent, const std::string &nam
kArgAOffset, kArgBOffset, kArgCOffset};
// Creates a tester
TestABC<T> tester{platform_id, device_id, name, options, clblast_lambda, clblas_lambda};
TestABC<T> tester{argc, argv, silent, name, options, clblast_lambda, clblas_lambda};
// Loops over the test-cases from a data-layout point of view
for (auto &layout: tester.kLayouts) {

View file

@ -50,20 +50,14 @@ void XgemvTest(int argc, char *argv[], const bool silent, const std::string &nam
return static_cast<StatusCode>(status);
};
// Selects the platform and device on which to test (command-line options)
auto help = std::string{"Options given/available:\n"};
const auto platform_id = GetArgument(argc, argv, help, kArgPlatform, size_t{0});
const auto device_id = GetArgument(argc, argv, help, kArgDevice, size_t{0});
if (!silent) { fprintf(stdout, "\n* %s\n", help.c_str()); }
// Initializes the other arguments relevant for this routine
// Initializes the arguments relevant for this routine
auto args = Arguments<T>{};
const auto options = std::vector<std::string>{kArgM, kArgN, kArgLayout, kArgATransp,
kArgALeadDim, kArgXInc, kArgYInc,
kArgAOffset, kArgXOffset, kArgYOffset};
// Creates a tester
TestAXY<T> tester{platform_id, device_id, name, options, clblast_lambda, clblas_lambda};
TestAXY<T> tester{argc, argv, silent, name, options, clblast_lambda, clblas_lambda};
// Loops over the test-cases from a data-layout point of view
for (auto &layout: tester.kLayouts) {

View file

@ -56,13 +56,7 @@ void XsymmTest(int argc, char *argv[], const bool silent, const std::string &nam
return static_cast<StatusCode>(status);
};
// Selects the platform and device on which to test (command-line options)
auto help = std::string{"Options given/available:\n"};
const auto platform_id = GetArgument(argc, argv, help, kArgPlatform, size_t{0});
const auto device_id = GetArgument(argc, argv, help, kArgDevice, size_t{0});
if (!silent) { fprintf(stdout, "\n* %s\n", help.c_str()); }
// Initializes the other arguments relevant for this routine
// Initializes the arguments relevant for this routine
auto args = Arguments<T>{};
const auto options = std::vector<std::string>{kArgM, kArgN, kArgLayout,
kArgSide, kArgTriangle,
@ -70,7 +64,7 @@ void XsymmTest(int argc, char *argv[], const bool silent, const std::string &nam
kArgAOffset, kArgBOffset, kArgCOffset};
// Creates a tester
TestABC<T> tester{platform_id, device_id, name, options, clblast_lambda, clblas_lambda};
TestABC<T> tester{argc, argv, silent, name, options, clblast_lambda, clblas_lambda};
// Loops over the test-cases from a data-layout point of view
for (auto &layout: tester.kLayouts) {

View file

@ -20,10 +20,10 @@ namespace clblast {
// Constructor, initializes the base class tester and input data
template <typename T>
TestABC<T>::TestABC(const size_t platform_id, const size_t device_id,
TestABC<T>::TestABC(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>{platform_id, device_id, name, options},
Tester<T>{argc, argv, silent, name, options},
clblast_lambda_(clblast_lambda),
clblas_lambda_(clblas_lambda) {
@ -46,6 +46,7 @@ TestABC<T>::TestABC(const size_t platform_id, const size_t device_id,
// Tests the routine for a wide variety of parameters
template <typename T>
void TestABC<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
@ -133,7 +134,7 @@ void TestABC<T>::TestRegular(Arguments<T> &args, const std::string &name) {
auto index = (args.layout == Layout::kRowMajor) ?
idm*args.c_ld + idn + args.c_offset:
idn*args.c_ld + idm + args.c_offset;
if (!TestSimilarity(r_result[index], s_result[index], kErrorMargin)) {
if (!TestSimilarity(r_result[index], s_result[index])) {
errors++;
}
}
@ -161,6 +162,7 @@ void TestABC<T>::TestRegular(Arguments<T> &args, const std::string &name) {
// does not test for results (if any).
template <typename T>
void TestABC<T>::TestInvalidBufferSizes(Arguments<T> &args, const std::string &name) {
if (!PrecisionSupported()) { return; }
TestStart("invalid buffer sizes", name);
// Sets example test parameters

View file

@ -31,7 +31,6 @@ class TestABC: public Tester<T> {
// Uses several variables from the Tester class
using Tester<T>::context_;
using Tester<T>::queue_;
using Tester<T>::kErrorMargin;
using Tester<T>::kLayouts;
using Tester<T>::kTransposes;
@ -42,10 +41,12 @@ class TestABC: public Tester<T> {
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 = { 0 };
const std::vector<size_t> kOffsets = GetOffsets();
const std::vector<T> kAlphaValues = GetExampleScalars();
const std::vector<T> kBetaValues = GetExampleScalars();
@ -58,7 +59,7 @@ class TestABC: public Tester<T> {
CommandQueue&)>;
// Constructor, initializes the base class tester and input data
TestABC(const size_t platform_id, const size_t device_id,
TestABC(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);

View file

@ -20,10 +20,10 @@ 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,
TestAXY<T>::TestAXY(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>{platform_id, device_id, name, options},
Tester<T>{argc, argv, silent, name, options},
clblast_lambda_(clblast_lambda),
clblas_lambda_(clblas_lambda) {
@ -47,6 +47,7 @@ TestAXY<T>::TestAXY(const size_t platform_id, const size_t device_id,
// Tests the routine for a wide variety of parameters
template <typename T>
void TestAXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
if (!PrecisionSupported()) { return; }
TestStart("regular behaviour", name);
// Iterates over the dimension for the matrix and vectors
@ -125,7 +126,7 @@ void TestAXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
auto errors = size_t{0};
for (auto idm=size_t{0}; idm<m_real; ++idm) {
auto index = idm*y_inc + y_offset;
if (!TestSimilarity(r_result[index], s_result[index], kErrorMargin)) {
if (!TestSimilarity(r_result[index], s_result[index])) {
errors++;
}
}
@ -151,6 +152,7 @@ void TestAXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
// does not test for results (if any).
template <typename T>
void TestAXY<T>::TestInvalidBufferSizes(Arguments<T> &args, const std::string &name) {
if (!PrecisionSupported()) { return; }
TestStart("invalid buffer sizes", name);
// Sets example test parameters

View file

@ -31,7 +31,6 @@ class TestAXY: public Tester<T> {
// Uses several variables from the Tester class
using Tester<T>::context_;
using Tester<T>::queue_;
using Tester<T>::kErrorMargin;
using Tester<T>::kLayouts;
using Tester<T>::kTransposes;
@ -42,10 +41,12 @@ class TestAXY: public Tester<T> {
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> kMatrixVectorDims = { 61, 512 };
const std::vector<size_t> kOffsets = { 0, 10 };
const std::vector<size_t> kOffsets = GetOffsets();
const std::vector<size_t> kIncrements = { 1, 2 };
const std::vector<T> kAlphaValues = GetExampleScalars();
const std::vector<T> kBetaValues = GetExampleScalars();
@ -60,7 +61,7 @@ class TestAXY: public Tester<T> {
CommandQueue&)>;
// Constructor, initializes the base class tester and input data
TestAXY(const size_t platform_id, const size_t device_id,
TestAXY(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);

View file

@ -17,7 +17,6 @@
#include <vector>
#include <iostream>
#include <cmath>
#include <limits>
namespace clblast {
// =================================================================================================
@ -35,25 +34,41 @@ template <> const std::vector<Transpose> Tester<double2>::kTransposes = {Transpo
// General constructor for all CLBlast testers. It prints out the test header to stdout and sets-up
// the clBLAS library for reference.
template <typename T>
Tester<T>::Tester(const size_t platform_id, const size_t device_id,
Tester<T>::Tester(int argc, char *argv[], const bool silent,
const std::string &name, const std::vector<std::string> &options):
platform_(Platform(platform_id)),
device_(Device(platform_, kDeviceType, device_id)),
help_("Options given/available:\n"),
platform_(Platform(GetArgument(argc, argv, help_, kArgPlatform, size_t{0}))),
device_(Device(platform_, kDeviceType, GetArgument(argc, argv, help_, kArgDevice, size_t{0}))),
context_(Context(device_)),
queue_(CommandQueue(context_, device_)),
full_test_(CheckArgument(argc, argv, help_, kArgFullTest)),
error_log_{},
num_passed_{0},
num_skipped_{0},
num_errors_{0},
num_failed_{0},
print_count_{0},
tests_failed_{0},
tests_passed_{0},
tests_skipped_{0},
tests_failed_{0},
options_{options} {
// Prints the help message (command-line arguments)
if (!silent) { fprintf(stdout, "\n* %s\n", help_.c_str()); }
// Prints the header
fprintf(stdout, "* Running on OpenCL device '%s'.\n", device_.Name().c_str());
fprintf(stdout, "* Starting tests for the %s'%s'%s routine. Legend:\n",
fprintf(stdout, "* Starting tests for the %s'%s'%s routine.",
kPrintMessage.c_str(), name.c_str(), kPrintEnd.c_str());
// Checks whether the precision is supported
if (!PrecisionSupported()) {
fprintf(stdout, "\n* All tests skipped: %sUnsupported precision%s\n",
kPrintWarning.c_str(), kPrintEnd.c_str());
return;
}
// Prints the legend
fprintf(stdout, " Legend:\n");
fprintf(stdout, " %s -> Test produced correct results\n", kSuccessData.c_str());
fprintf(stdout, " %s -> Test returned the correct error code\n", kSuccessStatus.c_str());
fprintf(stdout, " %s -> Test produced incorrect results\n", kErrorData.c_str());
@ -73,14 +88,13 @@ Tester<T>::Tester(const size_t platform_id, const size_t device_id,
// Destructor prints the summary of the test cases and cleans-up the clBLAS library
template <typename T>
Tester<T>::~Tester() {
fprintf(stdout, "* Completed all test-cases for this routine. Results:\n");
fprintf(stdout, " %lu test(s) succeeded\n", tests_passed_);
if (tests_failed_ != 0) {
fprintf(stdout, " %s%lu test(s) failed%s\n",
kPrintError.c_str(), tests_failed_, kPrintEnd.c_str());
}
else {
fprintf(stdout, " %lu test(s) failed\n", tests_failed_);
if (PrecisionSupported()) {
fprintf(stdout, "* Completed all test-cases for this routine. Results:\n");
fprintf(stdout, " %lu test(s) passed\n", tests_passed_);
if (tests_skipped_ > 0) { fprintf(stdout, "%s", kPrintWarning.c_str()); }
fprintf(stdout, " %lu test(s) skipped%s\n", tests_skipped_, kPrintEnd.c_str());
if (tests_failed_ > 0) { fprintf(stdout, "%s", kPrintError.c_str()); }
fprintf(stdout, " %lu test(s) failed%s\n", tests_failed_, kPrintEnd.c_str());
}
fprintf(stdout, "\n");
clblasTeardown();
@ -103,7 +117,7 @@ void Tester<T>::TestStart(const std::string &test_name, const std::string &test_
error_log_.clear();
num_passed_ = 0;
num_skipped_ = 0;
num_errors_ = 0;
num_failed_ = 0;
print_count_ = 0;
}
@ -112,7 +126,9 @@ void Tester<T>::TestStart(const std::string &test_name, const std::string &test_
template <typename T>
void Tester<T>::TestEnd() {
fprintf(stdout, "\n");
if (error_log_.size() == 0) { tests_passed_++; } else { tests_failed_++; }
tests_passed_ += num_passed_;
tests_failed_ += num_skipped_;
tests_failed_ += num_failed_;
// Prints details of all error occurences for these tests
for (auto &entry: error_log_) {
@ -146,7 +162,7 @@ void Tester<T>::TestEnd() {
}
// Prints a test summary
auto pass_rate = 100*num_passed_ / static_cast<float>(num_passed_ + num_skipped_ + num_errors_);
auto pass_rate = 100*num_passed_ / static_cast<float>(num_passed_ + num_skipped_ + num_failed_);
fprintf(stdout, " Pass rate %s%5.1lf%%%s:", kPrintMessage.c_str(), pass_rate, kPrintEnd.c_str());
fprintf(stdout, " %lu passed /", num_passed_);
if (num_skipped_ != 0) {
@ -155,11 +171,11 @@ void Tester<T>::TestEnd() {
else {
fprintf(stdout, " %lu skipped /", num_skipped_);
}
if (num_errors_ != 0) {
fprintf(stdout, " %s%lu failed%s\n", kPrintError.c_str(), num_errors_, kPrintEnd.c_str());
if (num_failed_ != 0) {
fprintf(stdout, " %s%lu failed%s\n", kPrintError.c_str(), num_failed_, kPrintEnd.c_str());
}
else {
fprintf(stdout, " %lu failed\n", num_errors_);
fprintf(stdout, " %lu failed\n", num_failed_);
}
}
@ -168,34 +184,34 @@ void Tester<T>::TestEnd() {
// Compares two floating point values and returns whether they are within an acceptable error
// margin. This replaces GTest's EXPECT_NEAR().
template <typename T>
bool Tester<T>::TestSimilarity(const T val1, const T val2, const double margin) {
bool Tester<T>::TestSimilarity(const T val1, const T val2) {
const auto difference = std::fabs(val1 - val2);
// Shortcut, handles infinities
if (val1 == val2) {
return true;
}
// The values are zero or both are extremely close to it relative error is less meaningful
else if (val1 == 0 || val2 == 0 || difference < std::numeric_limits<T>::min()) {
return difference < (static_cast<T>(margin) * std::numeric_limits<T>::min());
// The values are zero or very small: the relative error is less meaningful
else if (val1 == 0 || val2 == 0 || difference < static_cast<T>(kErrorMarginAbsolute)) {
return (difference < static_cast<T>(kErrorMarginAbsolute));
}
// Use relative error
else {
return (difference / (std::fabs(val1) + std::fabs(val2))) < static_cast<T>(margin);
return (difference / (std::fabs(val1)+std::fabs(val2))) < static_cast<T>(kErrorMarginRelative);
}
}
// Specialisations for complex data-types
template <>
bool Tester<float2>::TestSimilarity(const float2 val1, const float2 val2, const double margin) {
auto real = Tester<float>::TestSimilarity(val1.real(), val2.real(), margin);
auto imag = Tester<float>::TestSimilarity(val1.imag(), val2.imag(), margin);
bool Tester<float2>::TestSimilarity(const float2 val1, const float2 val2) {
auto real = Tester<float>::TestSimilarity(val1.real(), val2.real());
auto imag = Tester<float>::TestSimilarity(val1.imag(), val2.imag());
return (real && imag);
}
template <>
bool Tester<double2>::TestSimilarity(const double2 val1, const double2 val2, const double margin) {
auto real = Tester<double>::TestSimilarity(val1.real(), val2.real(), margin);
auto imag = Tester<double>::TestSimilarity(val1.imag(), val2.imag(), margin);
bool Tester<double2>::TestSimilarity(const double2 val1, const double2 val2) {
auto real = Tester<double>::TestSimilarity(val1.real(), val2.real());
auto imag = Tester<double>::TestSimilarity(val1.imag(), val2.imag());
return (real && imag);
}
@ -258,19 +274,43 @@ void Tester<T>::TestErrorCodes(const StatusCode clblas_status, const StatusCode
// routines. This function is specialised for the different data-types.
template <>
const std::vector<float> Tester<float>::GetExampleScalars() {
return {0.0f, 1.0f, 3.14f};
if (full_test_) { return {0.0f, 1.0f, 3.14f}; }
else { return {3.14f}; }
}
template <>
const std::vector<double> Tester<double>::GetExampleScalars() {
return {0.0, 1.0, 3.14};
if (full_test_) { return {0.0, 1.0, 3.14}; }
else { return {3.14}; }
}
template <>
const std::vector<float2> Tester<float2>::GetExampleScalars() {
return {{0.0f, 0.0f}, {1.0f, 1.3f}, {2.42f, 3.14f}};
if (full_test_) { return {{0.0f, 0.0f}, {1.0f, 1.3f}, {2.42f, 3.14f}}; }
else { return {{2.42f, 3.14f}}; }
}
template <>
const std::vector<double2> Tester<double2>::GetExampleScalars() {
return {{0.0, 0.0}, {1.0, 1.3}, {2.42, 3.14}};
if (full_test_) { return {{0.0, 0.0}, {1.0, 1.3}, {2.42, 3.14}}; }
else { return {{2.42, 3.14}}; }
}
// Retrieves the offset values to test with
template <typename T>
const std::vector<size_t> Tester<T>::GetOffsets() {
if (full_test_) { return {0, 10}; }
else { return {0}; }
}
// =================================================================================================
template <> bool Tester<float>::PrecisionSupported() const { return true; }
template <> bool Tester<float2>::PrecisionSupported() const { return true; }
template <> bool Tester<double>::PrecisionSupported() const {
auto extensions = device_.Extensions();
return (extensions.find(kKhronosDoublePrecision) == std::string::npos) ? false : true;
}
template <> bool Tester<double2>::PrecisionSupported() const {
auto extensions = device_.Extensions();
return (extensions.find(kKhronosDoublePrecision) == std::string::npos) ? false : true;
}
// =================================================================================================
@ -287,7 +327,7 @@ void Tester<T>::ReportSkipped() {
template <typename T>
void Tester<T>::ReportError(const ErrorLogEntry &error_log_entry) {
error_log_.push_back(error_log_entry);
num_errors_++;
num_failed_++;
}
// =================================================================================================

View file

@ -44,7 +44,8 @@ class Tester {
static constexpr auto kStatusError = -1.0f;
// Set the allowed error margin for floating-point comparisons
static constexpr auto kErrorMargin = 1.0e-2;
static constexpr auto kErrorMarginRelative = 1.0e-2;
static constexpr auto kErrorMarginAbsolute = 1.0e-10;
// Constants holding start and end strings for terminal-output in colour
const std::string kPrintError{"\x1b[31m"};
@ -75,7 +76,7 @@ class Tester {
// Creates an instance of the tester, running on a particular OpenCL platform and device. It
// takes the routine's names as an additional parameter.
explicit Tester(const size_t platform_id, const size_t device_id,
explicit Tester(int argc, char *argv[], const bool silent,
const std::string &name, const std::vector<std::string> &options);
~Tester();
@ -84,7 +85,7 @@ class Tester {
void TestEnd();
// Compares two floating point values for similarity. Allows for a certain relative error margin.
static bool TestSimilarity(const T val1, const T val2, const double margin);
static bool TestSimilarity(const T val1, const T val2);
// Tests either an error count (should be zero) or two error codes (must match)
void TestErrorCount(const size_t errors, const size_t size, const Arguments<T> &args);
@ -96,6 +97,15 @@ class Tester {
// Retrieves a list of example scalars of the right type
const std::vector<T> GetExampleScalars();
// Retrieves a list of offset values to test
const std::vector<size_t> GetOffsets();
// Returns false is this precision is not supported by the device
bool PrecisionSupported() const;
// The help-message
std::string help_;
// The OpenCL objects (accessible by derived classes)
Platform platform_;
Device device_;
@ -112,18 +122,22 @@ class Tester {
// Prints the error or success symbol to screen
void PrintTestResult(const std::string &message);
// Whether or not to run the full test-suite or just a smoke test
bool full_test_;
// Logging and counting occurrences of errors
std::vector<ErrorLogEntry> error_log_;
size_t num_passed_;
size_t num_skipped_;
size_t num_errors_;
size_t num_failed_;
// Counting the amount of errors printed on this row
size_t print_count_;
// Counting the number of test-cases with and without failures
size_t tests_failed_;
size_t tests_passed_;
size_t tests_skipped_;
size_t tests_failed_;
// Arguments relevant for a specific routine
std::vector<std::string> options_;

View file

@ -20,10 +20,10 @@ namespace clblast {
// Constructor, initializes the base class tester and input data
template <typename T>
TestXY<T>::TestXY(const size_t platform_id, const size_t device_id,
TestXY<T>::TestXY(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>{platform_id, device_id, name, options},
Tester<T>{argc, argv, silent, name, options},
clblast_lambda_(clblast_lambda),
clblas_lambda_(clblas_lambda) {
@ -44,6 +44,7 @@ TestXY<T>::TestXY(const size_t platform_id, const size_t device_id,
// Tests the routine for a wide variety of parameters
template <typename T>
void TestXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
if (!PrecisionSupported()) { return; }
TestStart("regular behaviour", name);
// Iterates over the vector dimension
@ -100,7 +101,7 @@ void TestXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
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)) {
if (!TestSimilarity(r_result[index], s_result[index])) {
errors++;
}
}
@ -122,6 +123,7 @@ void TestXY<T>::TestRegular(Arguments<T> &args, const std::string &name) {
// does not test for results (if any).
template <typename T>
void TestXY<T>::TestInvalidBufferSizes(Arguments<T> &args, const std::string &name) {
if (!PrecisionSupported()) { return; }
TestStart("invalid buffer sizes", name);
// Sets example test parameters

View file

@ -31,7 +31,6 @@ class TestXY: public Tester<T> {
// 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;
@ -40,11 +39,13 @@ class TestXY: public Tester<T> {
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> kVectorDims = { 7, 93, 4096 };
const std::vector<size_t> kOffsets = { 0, 10 };
const std::vector<size_t> kIncrements = { 1, 2 };
const std::vector<size_t> kOffsets = GetOffsets();
const std::vector<size_t> kIncrements = { 1, 2, 7 };
const std::vector<T> kAlphaValues = GetExampleScalars();
// Test settings for the invalid test
@ -57,7 +58,7 @@ class TestXY: public Tester<T> {
CommandQueue&)>;
// Constructor, initializes the base class tester and input data
TestXY(const size_t platform_id, const size_t device_id,
TestXY(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);