mirror of
https://github.com/CNugteren/CLBlast.git
synced 2024-07-15 10:55:42 +02:00
Merge pull request #5 from CNugteren/improved_testing
Improved testing infrastructure
This commit is contained in:
commit
e19893ff15
15
CHANGELOG
15
CHANGELOG
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)); }
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_++;
|
||||
}
|
||||
|
||||
// =================================================================================================
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue