diff --git a/test_conformance/math_brute_force/FunctionList.c b/test_conformance/math_brute_force/FunctionList.c index 027672fb..2f54d9bc 100644 --- a/test_conformance/math_brute_force/FunctionList.c +++ b/test_conformance/math_brute_force/FunctionList.c @@ -24,6 +24,36 @@ #define STRINGIFY( _s) #_s +// Only use ulps information in spir test +#ifdef FUNCTION_LIST_ULPS_ONLY + +#define ENTRY( _name, _ulp, _embedded_ulp, _rmode, _type ) { STRINGIFY(_name), STRINGIFY(_name), {NULL}, {NULL}, {NULL}, _ulp, _ulp, _embedded_ulp, INFINITY, _rmode, RELAXED_OFF, _type } +#define ENTRY_EXT( _name, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, _type ) { STRINGIFY(_name), STRINGIFY(_name), {NULL}, {NULL}, {NULL}, _ulp, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, RELAXED_ON, _type } +#define HALF_ENTRY( _name, _ulp, _embedded_ulp, _rmode, _type ) { "half_" STRINGIFY(_name), "half_" STRINGIFY(_name), {NULL}, {NULL}, {NULL}, _ulp, _ulp, _embedded_ulp, INFINITY, _rmode, RELAXED_OFF, _type } +#define OPERATOR_ENTRY(_name, _operator, _ulp, _embedded_ulp, _rmode, _type) { STRINGIFY(_name), _operator, {NULL}, {NULL}, {NULL}, _ulp, _ulp, _embedded_ulp, INFINITY, _rmode, RELAXED_OFF, _type } +#define unaryF NULL +#define i_unaryF NULL +#define unaryF_u NULL +#define macro_unaryF NULL +#define binaryF NULL +#define binaryF_nextafter NULL +#define binaryOperatorF NULL +#define binaryF_i NULL +#define macro_binaryF NULL +#define ternaryF NULL +#define unaryF_two_results NULL +#define unaryF_two_results_i NULL +#define binaryF_two_results_i NULL +#define mad_function NULL + +#define reference_sqrt NULL +#define reference_sqrtl NULL +#define reference_divide NULL +#define reference_dividel NULL +#define reference_relaxed_divide NULL + +#else // FUNCTION_LIST_ULPS_ONLY + #define ENTRY( _name, _ulp, _embedded_ulp, _rmode, _type ) { STRINGIFY(_name), STRINGIFY(_name), {(void*)reference_##_name}, {(void*)reference_##_name##l}, {(void*)reference_##_name}, _ulp, _ulp, _embedded_ulp, INFINITY, _rmode, RELAXED_OFF, _type } #define ENTRY_EXT( _name, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, _type ) { STRINGIFY(_name), STRINGIFY(_name), {(void*)reference_##_name}, {(void*)reference_##_name##l}, {(void*)reference_##relaxed_##_name}, _ulp, _ulp, _embedded_ulp, _relaxed_ulp, _rmode, RELAXED_ON, _type } #define HALF_ENTRY( _name, _ulp, _embedded_ulp, _rmode, _type ) { "half_" STRINGIFY(_name), "half_" STRINGIFY(_name), {(void*)reference_##_name}, {NULL}, {NULL}, _ulp, _ulp, _embedded_ulp, INFINITY, _rmode, RELAXED_OFF, _type } @@ -65,6 +95,7 @@ extern const vtbl _mad_tbl; // float mad( float, float, float ) #define binaryF_two_results_i &_binary_two_results_i #define mad_function &_mad_tbl +#endif // FUNCTION_LIST_ULPS_ONLY const Func functionList[] = { ENTRY( acos, 4.0f, 4.0f, FTZ_OFF, unaryF), diff --git a/test_conformance/math_brute_force/FunctionList.h b/test_conformance/math_brute_force/FunctionList.h index b5ddb715..32facbd6 100644 --- a/test_conformance/math_brute_force/FunctionList.h +++ b/test_conformance/math_brute_force/FunctionList.h @@ -30,6 +30,10 @@ #include "../../test_common/harness/mt19937.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef union fptr { void *p; @@ -93,6 +97,9 @@ extern const Func functionList[]; extern const size_t functionListCount; +#ifdef __cplusplus +} +#endif #endif diff --git a/test_conformance/spir/CMakeLists.txt b/test_conformance/spir/CMakeLists.txt index b0a3e020..819fadf9 100644 --- a/test_conformance/spir/CMakeLists.txt +++ b/test_conformance/spir/CMakeLists.txt @@ -4,13 +4,17 @@ endfunction() include_directories(${CLConf_SRC_DIR}/test_common) +# Import function list from math_brute_force +add_definitions(-DFUNCTION_LIST_ULPS_ONLY) + clconf_add_executable( test_spir main.cpp datagen.cpp run_build_test.cpp run_services.cpp - kernelargs.cpp) + kernelargs.cpp + ../math_brute_force/FunctionList.c) target_link_libraries( test_spir${CLConf_SUFFIX} diff --git a/test_conformance/spir/kernelargs.h b/test_conformance/spir/kernelargs.h index 9f14053e..6ba6e8e7 100644 --- a/test_conformance/spir/kernelargs.h +++ b/test_conformance/spir/kernelargs.h @@ -110,7 +110,7 @@ public: return m_buffer; } - virtual bool compare( const KernelArg& rhs ) const + virtual bool compare( const KernelArg& rhs, float ulps ) const { if( m_argInfo != rhs.m_argInfo ) { @@ -133,21 +133,58 @@ public: return true; } + bool match = true; if( memcmp( m_buffer, rhs.m_buffer, m_size) ) { + std::string typeName = m_argInfo.getTypeName(); size_t compared = 0; - while (compared < m_size) + if (typeName.compare("float*") == 0) { - if ( *(((char*)m_buffer)+compared) != *(((char*)rhs.m_buffer)+compared) ) + while (compared < m_size) { - std::cerr << std::endl << " difference is at offset " << compared << std::endl; - return false; + float l = *(float*)(((char*)m_buffer)+compared); + float r = *(float*)(((char*)rhs.m_buffer)+compared); + if (fabsf(Ulp_Error(l, r)) > ulps) + { + match = false; + break; + } + compared += sizeof(float); } - compared++; + } + else if (typeName.compare("double*") == 0) + { + while (compared < m_size) + { + double l = *(double*)(((char*)m_buffer)+compared); + double r = *(double*)(((char*)rhs.m_buffer)+compared); + if (fabsf(Ulp_Error_Double(l, r)) > ulps) + { + match = false; + break; + } + compared += sizeof(double); + } + } + else + { + while (compared < m_size) + { + if ( *(((char*)m_buffer)+compared) != *(((char*)rhs.m_buffer)+compared) ) + { + match = false; + break; + } + compared++; + } + } + if (!match) + { + std::cerr << std::endl << " difference is at offset " << compared << std::endl; } } - return true; + return match; } virtual void readToHost(cl_command_queue queue) diff --git a/test_conformance/spir/run_build_test.cpp b/test_conformance/spir/run_build_test.cpp index 45d7261b..71fd8dbc 100644 --- a/test_conformance/spir/run_build_test.cpp +++ b/test_conformance/spir/run_build_test.cpp @@ -38,6 +38,7 @@ #include "datagen.h" #include "run_services.h" #include "run_build_test.h" +#include "../math_brute_force/FunctionList.h" #include // // Task @@ -262,7 +263,8 @@ size_t KernelEnumerator::size() const { Run the single test - run the test for both CL and SPIR versions of the kernel */ static bool run_test(cl_context context, cl_command_queue queue, cl_program clprog, - cl_program bcprog, const std::string& kernel_name, std::string& err, const cl_device_id device) + cl_program bcprog, const std::string& kernel_name, std::string& err, const cl_device_id device, + float ulps) { WorkSizeInfo ws; TestResult cl_result; @@ -274,7 +276,7 @@ static bool run_test(cl_context context, cl_command_queue queue, cl_program clpr // based on the kernel characteristics, we are generating and initializing the arguments for both phases (cl and bc executions) generate_kernel_data(context, kernel, ws, cl_result); bc_result.reset(cl_result.clone(context, ws, kernel, device)); - assert (compare_results(cl_result, *bc_result) && "not equal?"); + assert (compare_results(cl_result, *bc_result, ulps) && "not equal?"); run_kernel( kernel, queue, ws, cl_result ); } // now, run the single BC test @@ -292,7 +294,7 @@ static bool run_test(cl_context context, cl_command_queue queue, cl_program clpr } // compare the results - if( !compare_results(cl_result, *bc_result) ) + if( !compare_results(cl_result, *bc_result, ulps) ) { err = " (result diff in kernel '" + kernel_name + "')."; return false; @@ -300,6 +302,37 @@ static bool run_test(cl_context context, cl_command_queue queue, cl_program clpr return true; } +/** + Get the maximum relative error defined as ULP of floating-point math functions + */ +static float get_max_ulps(const char *test_name) +{ + float ulps = 0.f; + // Get ULP values from math_brute_force functionList + if (strstr(test_name, "math_kernel")) + { + for( size_t i = 0; i < functionListCount; i++ ) + { + char name[64]; + const Func *func = &functionList[ i ]; + sprintf(name, ".%s_float", func->name); + if (strstr(test_name, name)) + { + ulps = func->float_ulps; + } + else + { + sprintf(name, ".%s_double", func->name); + if (strstr(test_name, name)) + { + ulps = func->double_ulps; + } + } + } + } + return ulps; +} + TestRunner::TestRunner(EventHandler *success, EventHandler *failure, const OclExtensions& devExt): m_successHandler(success), m_failureHandler(failure), m_devExt(&devExt) {} @@ -321,6 +354,8 @@ bool TestRunner::runBuildTest(cl_device_id device, const char *folder, log_info("%s...\n", test_name); + float ulps = get_max_ulps(test_name); + // Figure out whether the test can run on the device. If not, we skip it. const KhrSupport& khrDb = *KhrSupport::get(csvName); cl_bool images = khrDb.isImagesRequired(folder, test_name); @@ -415,7 +450,7 @@ bool TestRunner::runBuildTest(cl_device_id device, const char *folder, std::string err; try { - bool success = run_test(context, queue, clprog, bcprog, kernel_name, err, device); + bool success = run_test(context, queue, clprog, bcprog, kernel_name, err, device, ulps); if (success) { log_info("kernel '%s' passed.\n", kernel_name.c_str()); diff --git a/test_conformance/spir/run_services.cpp b/test_conformance/spir/run_services.cpp index 282a805d..cefae082 100644 --- a/test_conformance/spir/run_services.cpp +++ b/test_conformance/spir/run_services.cpp @@ -746,7 +746,7 @@ void run_kernel( cl_kernel kernel, cl_command_queue queue, WorkSizeInfo &ws, Tes /** Compare two test results */ -bool compare_results( const TestResult& lhs, const TestResult& rhs ) +bool compare_results( const TestResult& lhs, const TestResult& rhs, float ulps ) { if( lhs.kernelArgs().getArgCount() != rhs.kernelArgs().getArgCount() ) { @@ -756,7 +756,7 @@ bool compare_results( const TestResult& lhs, const TestResult& rhs ) for( size_t i = 0 ; i < lhs.kernelArgs().getArgCount(); ++i ) { - if( ! lhs.kernelArgs().getArg(i)->compare( *rhs.kernelArgs().getArg(i)) ) + if( ! lhs.kernelArgs().getArg(i)->compare( *rhs.kernelArgs().getArg(i), ulps ) ) { log_error("the kernel parameter (%d) is different between SPIR and CL version of the kernel\n", i); return false; diff --git a/test_conformance/spir/run_services.h b/test_conformance/spir/run_services.h index 37cec763..6bac4c91 100644 --- a/test_conformance/spir/run_services.h +++ b/test_conformance/spir/run_services.h @@ -217,6 +217,6 @@ void generate_kernel_data(cl_context context, cl_kernel kernel, WorkSizeInfo &ws, TestResult& res); void run_kernel(cl_kernel kernel, cl_command_queue queue, WorkSizeInfo &ws, TestResult& result); -bool compare_results(const TestResult& lhs, const TestResult& rhs); +bool compare_results(const TestResult& lhs, const TestResult& rhs, float ulps); #endif