// // Copyright (c) 2017 The Khronos Group Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef _errorHelpers_h #define _errorHelpers_h #include #ifdef __APPLE__ #include #else #include #endif #include #define LOWER_IS_BETTER 0 #define HIGHER_IS_BETTER 1 #include #define test_start() #define log_info printf #define log_error printf #define log_missing_feature printf #define log_perf(_number, _higherBetter, _numType, _format, ...) \ printf("Performance Number " _format " (in %s, %s): %g\n", ##__VA_ARGS__, \ _numType, _higherBetter ? "higher is better" : "lower is better", \ _number) #define vlog_perf(_number, _higherBetter, _numType, _format, ...) \ printf("Performance Number " _format " (in %s, %s): %g\n", ##__VA_ARGS__, \ _numType, _higherBetter ? "higher is better" : "lower is better", \ _number) #ifdef _WIN32 #ifdef __MINGW32__ // Use __mingw_printf since it supports "%a" format specifier #define vlog __mingw_printf #define vlog_error __mingw_printf #else // Use home-baked function that treats "%a" as "%f" static int vlog_win32(const char *format, ...); #define vlog vlog_win32 #define vlog_error vlog_win32 #endif #else #define vlog_error printf #define vlog printf #endif #define ct_assert(b) ct_assert_i(b, __LINE__) #define ct_assert_i(b, line) ct_assert_ii(b, line) #define ct_assert_ii(b, line) \ int _compile_time_assertion_on_line_##line[b ? 1 : -1]; #define test_fail(msg, ...) \ { \ log_error(msg, ##__VA_ARGS__); \ return TEST_FAIL; \ } #define test_error(errCode, msg) test_error_ret(errCode, msg, errCode) #define test_error_ret(errCode, msg, retValue) \ { \ auto errCodeResult = errCode; \ if (errCodeResult != CL_SUCCESS) \ { \ print_error(errCodeResult, msg); \ return retValue; \ } \ } #define print_error(errCode, msg) \ log_error("ERROR: %s! (%s from %s:%d)\n", msg, IGetErrorString(errCode), \ __FILE__, __LINE__); #define test_missing_feature(errCode, msg) \ test_missing_feature_ret(errCode, msg, errCode) // this macro should always return CL_SUCCESS, but print the missing feature // message #define test_missing_feature_ret(errCode, msg, retValue) \ { \ if (errCode != CL_SUCCESS) \ { \ print_missing_feature(errCode, msg); \ return CL_SUCCESS; \ } \ } #define print_missing_feature(errCode, msg) \ log_missing_feature("ERROR: Subtest %s tests a feature not supported by " \ "the device version! (from %s:%d)\n", \ msg, __FILE__, __LINE__); #define test_missing_support_offline_cmpiler(errCode, msg) \ test_missing_support_offline_cmpiler_ret(errCode, msg, errCode) // this macro should always return CL_SUCCESS, but print the skip message on // test not supported with offline compiler #define test_missing_support_offline_cmpiler_ret(errCode, msg, retValue) \ { \ if (errCode != CL_SUCCESS) \ { \ log_info("INFO: Subtest %s tests is not supported in offline " \ "compiler execution path! (from %s:%d)\n", \ msg, __FILE__, __LINE__); \ return TEST_SKIP; \ } \ } // expected error code vs. what we got #define test_failure_error(errCode, expectedErrCode, msg) \ test_failure_error_ret(errCode, expectedErrCode, msg, \ errCode != expectedErrCode) #define test_failure_error_ret(errCode, expectedErrCode, msg, retValue) \ { \ if (errCode != expectedErrCode) \ { \ print_failure_error(errCode, expectedErrCode, msg); \ return retValue; \ } \ } #define print_failure_error(errCode, expectedErrCode, msg) \ log_error("ERROR: %s! (Got %s, expected %s from %s:%d)\n", msg, \ IGetErrorString(errCode), IGetErrorString(expectedErrCode), \ __FILE__, __LINE__); #define test_failure_warning(errCode, expectedErrCode, msg) \ test_failure_warning_ret(errCode, expectedErrCode, msg, \ errCode != expectedErrCode) #define test_failure_warning_ret(errCode, expectedErrCode, msg, retValue) \ { \ if (errCode != expectedErrCode) \ { \ print_failure_warning(errCode, expectedErrCode, msg); \ warnings++; \ } \ } #define print_failure_warning(errCode, expectedErrCode, msg) \ log_error("WARNING: %s! (Got %s, expected %s from %s:%d)\n", msg, \ IGetErrorString(errCode), IGetErrorString(expectedErrCode), \ __FILE__, __LINE__); // generate an error when an assertion is false (not error code related) #define test_assert_error(condition, msg) \ test_assert_error_ret(condition, msg, TEST_FAIL) #define test_assert_error_ret(condition, msg, retValue) \ { \ if (!(condition)) \ { \ print_assertion_error(condition, msg); \ return retValue; \ } \ } #define print_assertion_error(condition, msg) \ log_error("ERROR: %s! (!(%s) from %s:%d)\n", msg, #condition, __FILE__, \ __LINE__); #define ASSERT_SUCCESS(expr, msg) \ do \ { \ cl_int _temp_retval = (expr); \ if (_temp_retval != CL_SUCCESS) \ { \ std::stringstream ss; \ ss << "ERROR: " << msg << "=" << IGetErrorString(_temp_retval) \ << " at " << __FILE__ << ":" << __LINE__ << "\n"; \ throw std::runtime_error(ss.str()); \ } \ } while (0) extern const char *IGetErrorString(int clErrorCode); extern float Ulp_Error_Half(cl_half test, float reference); extern float Ulp_Error(float test, double reference); extern float Ulp_Error_Double(double test, long double reference); extern const char *GetChannelTypeName(cl_channel_type type); extern int IsChannelTypeSupported(cl_channel_type type); extern const char *GetChannelOrderName(cl_channel_order order); extern int IsChannelOrderSupported(cl_channel_order order); extern const char *GetAddressModeName(cl_addressing_mode mode); extern const char *GetQueuePropertyName(cl_command_queue_properties properties); extern const char *GetDeviceTypeName(cl_device_type type); int check_functions_for_offline_compiler(const char *subtestname, cl_device_id device); cl_int OutputBuildLogs(cl_program program, cl_uint num_devices, cl_device_id *device_list); // NON-REENTRANT UNLESS YOU PROVIDE A BUFFER PTR (pass null to use static // storage, but it's not reentrant then!) extern const char *GetDataVectorString(void *dataBuffer, size_t typeSize, size_t vecSize, char *buffer); #if defined(_WIN32) && !defined(__MINGW32__) #include #include #include static int vlog_win32(const char *format, ...) { const char *new_format = format; if (strstr(format, "%a")) { char *temp; if ((temp = strdup(format)) == NULL) { printf("vlog_win32: Failed to allocate memory for strdup\n"); return -1; } new_format = temp; while (*temp) { // replace %a with %f if ((*temp == '%') && (*(temp + 1) == 'a')) { *(temp + 1) = 'f'; } temp++; } } va_list args; va_start(args, format); vprintf(new_format, args); va_end(args); if (new_format != format) { free((void *)new_format); } return 0; } #endif #endif // _errorHelpers_h