1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #ifndef _errorHelpers_h
17 #define _errorHelpers_h
18 
19 #include <sstream>
20 
21 #ifdef __APPLE__
22 #include <OpenCL/opencl.h>
23 #else
24 #include <CL/opencl.h>
25 #endif
26 #include <stdlib.h>
27 #define LOWER_IS_BETTER 0
28 #define HIGHER_IS_BETTER 1
29 
30 #include <stdio.h>
31 #define test_start()
32 #define log_info printf
33 #define log_error printf
34 #define log_missing_feature printf
35 #define log_perf(_number, _higherBetter, _numType, _format, ...)               \
36     printf("Performance Number " _format " (in %s, %s): %g\n", ##__VA_ARGS__,  \
37            _numType, _higherBetter ? "higher is better" : "lower is better",   \
38            _number)
39 #define vlog_perf(_number, _higherBetter, _numType, _format, ...)              \
40     printf("Performance Number " _format " (in %s, %s): %g\n", ##__VA_ARGS__,  \
41            _numType, _higherBetter ? "higher is better" : "lower is better",   \
42            _number)
43 #ifdef _WIN32
44 #ifdef __MINGW32__
45 // Use __mingw_printf since it supports "%a" format specifier
46 #define vlog __mingw_printf
47 #define vlog_error __mingw_printf
48 #else
49 // Use home-baked function that treats "%a" as "%f"
50 static int vlog_win32(const char *format, ...);
51 #define vlog vlog_win32
52 #define vlog_error vlog_win32
53 #endif
54 #else
55 #define vlog_error printf
56 #define vlog printf
57 #endif
58 
59 #define ct_assert(b) ct_assert_i(b, __LINE__)
60 #define ct_assert_i(b, line) ct_assert_ii(b, line)
61 #define ct_assert_ii(b, line)                                                  \
62     int _compile_time_assertion_on_line_##line[b ? 1 : -1];
63 
64 #define test_fail(msg, ...)                                                    \
65     {                                                                          \
66         log_error(msg, ##__VA_ARGS__);                                         \
67         return TEST_FAIL;                                                      \
68     }
69 #define test_error(errCode, msg) test_error_ret(errCode, msg, errCode)
70 #define test_error_ret(errCode, msg, retValue)                                 \
71     {                                                                          \
72         auto errCodeResult = errCode;                                          \
73         if (errCodeResult != CL_SUCCESS)                                       \
74         {                                                                      \
75             print_error(errCodeResult, msg);                                   \
76             return retValue;                                                   \
77         }                                                                      \
78     }
79 #define print_error(errCode, msg)                                              \
80     log_error("ERROR: %s! (%s from %s:%d)\n", msg, IGetErrorString(errCode),   \
81               __FILE__, __LINE__);
82 
83 #define test_missing_feature(errCode, msg)                                     \
84     test_missing_feature_ret(errCode, msg, errCode)
85 // this macro should always return CL_SUCCESS, but print the missing feature
86 // message
87 #define test_missing_feature_ret(errCode, msg, retValue)                       \
88     {                                                                          \
89         if (errCode != CL_SUCCESS)                                             \
90         {                                                                      \
91             print_missing_feature(errCode, msg);                               \
92             return CL_SUCCESS;                                                 \
93         }                                                                      \
94     }
95 #define print_missing_feature(errCode, msg)                                    \
96     log_missing_feature("ERROR: Subtest %s tests a feature not supported by "  \
97                         "the device version! (from %s:%d)\n",                  \
98                         msg, __FILE__, __LINE__);
99 
100 #define test_missing_support_offline_cmpiler(errCode, msg)                     \
101     test_missing_support_offline_cmpiler_ret(errCode, msg, errCode)
102 // this macro should always return CL_SUCCESS, but print the skip message on
103 // test not supported with offline compiler
104 #define test_missing_support_offline_cmpiler_ret(errCode, msg, retValue)       \
105     {                                                                          \
106         if (errCode != CL_SUCCESS)                                             \
107         {                                                                      \
108             log_info("INFO: Subtest %s tests is not supported in offline "     \
109                      "compiler execution path! (from %s:%d)\n",                \
110                      msg, __FILE__, __LINE__);                                 \
111             return TEST_SKIP;                                                  \
112         }                                                                      \
113     }
114 
115 // expected error code vs. what we got
116 #define test_failure_error(errCode, expectedErrCode, msg)                      \
117     test_failure_error_ret(errCode, expectedErrCode, msg,                      \
118                            errCode != expectedErrCode)
119 #define test_failure_error_ret(errCode, expectedErrCode, msg, retValue)        \
120     {                                                                          \
121         if (errCode != expectedErrCode)                                        \
122         {                                                                      \
123             print_failure_error(errCode, expectedErrCode, msg);                \
124             return retValue;                                                   \
125         }                                                                      \
126     }
127 #define print_failure_error(errCode, expectedErrCode, msg)                     \
128     log_error("ERROR: %s! (Got %s, expected %s from %s:%d)\n", msg,            \
129               IGetErrorString(errCode), IGetErrorString(expectedErrCode),      \
130               __FILE__, __LINE__);
131 #define test_failure_warning(errCode, expectedErrCode, msg)                    \
132     test_failure_warning_ret(errCode, expectedErrCode, msg,                    \
133                              errCode != expectedErrCode)
134 #define test_failure_warning_ret(errCode, expectedErrCode, msg, retValue)      \
135     {                                                                          \
136         if (errCode != expectedErrCode)                                        \
137         {                                                                      \
138             print_failure_warning(errCode, expectedErrCode, msg);              \
139             warnings++;                                                        \
140         }                                                                      \
141     }
142 #define print_failure_warning(errCode, expectedErrCode, msg)                   \
143     log_error("WARNING: %s! (Got %s, expected %s from %s:%d)\n", msg,          \
144               IGetErrorString(errCode), IGetErrorString(expectedErrCode),      \
145               __FILE__, __LINE__);
146 
147 // generate an error when an assertion is false (not error code related)
148 #define test_assert_error(condition, msg)                                      \
149     test_assert_error_ret(condition, msg, TEST_FAIL)
150 #define test_assert_error_ret(condition, msg, retValue)                        \
151     {                                                                          \
152         if (!(condition))                                                      \
153         {                                                                      \
154             print_assertion_error(condition, msg);                             \
155             return retValue;                                                   \
156         }                                                                      \
157     }
158 #define print_assertion_error(condition, msg)                                  \
159     log_error("ERROR: %s! (!(%s) from %s:%d)\n", msg, #condition, __FILE__,    \
160               __LINE__);
161 
162 #define ASSERT_SUCCESS(expr, msg)                                              \
163     do                                                                         \
164     {                                                                          \
165         cl_int _temp_retval = (expr);                                          \
166         if (_temp_retval != CL_SUCCESS)                                        \
167         {                                                                      \
168             std::stringstream ss;                                              \
169             ss << "ERROR: " << msg << "=" << IGetErrorString(_temp_retval)     \
170                << " at " << __FILE__ << ":" << __LINE__ << "\n";               \
171             throw std::runtime_error(ss.str());                                \
172         }                                                                      \
173     } while (0)
174 
175 extern const char *IGetErrorString(int clErrorCode);
176 
177 extern float Ulp_Error_Half(cl_half test, float reference);
178 extern float Ulp_Error(float test, double reference);
179 extern float Ulp_Error_Double(double test, long double reference);
180 
181 extern const char *GetChannelTypeName(cl_channel_type type);
182 extern int IsChannelTypeSupported(cl_channel_type type);
183 extern const char *GetChannelOrderName(cl_channel_order order);
184 extern int IsChannelOrderSupported(cl_channel_order order);
185 extern const char *GetAddressModeName(cl_addressing_mode mode);
186 extern const char *GetQueuePropertyName(cl_command_queue_properties properties);
187 
188 extern const char *GetDeviceTypeName(cl_device_type type);
189 int check_functions_for_offline_compiler(const char *subtestname,
190                                          cl_device_id device);
191 cl_int OutputBuildLogs(cl_program program, cl_uint num_devices,
192                        cl_device_id *device_list);
193 
194 // NON-REENTRANT UNLESS YOU PROVIDE A BUFFER PTR (pass null to use static
195 // storage, but it's not reentrant then!)
196 extern const char *GetDataVectorString(void *dataBuffer, size_t typeSize,
197                                        size_t vecSize, char *buffer);
198 
199 #if defined(_WIN32) && !defined(__MINGW32__)
200 #include <stdarg.h>
201 #include <stdio.h>
202 #include <string.h>
vlog_win32(const char * format,...)203 static int vlog_win32(const char *format, ...)
204 {
205     const char *new_format = format;
206 
207     if (strstr(format, "%a"))
208     {
209         char *temp;
210         if ((temp = strdup(format)) == NULL)
211         {
212             printf("vlog_win32: Failed to allocate memory for strdup\n");
213             return -1;
214         }
215         new_format = temp;
216         while (*temp)
217         {
218             // replace %a with %f
219             if ((*temp == '%') && (*(temp + 1) == 'a'))
220             {
221                 *(temp + 1) = 'f';
222             }
223             temp++;
224         }
225     }
226 
227     va_list args;
228     va_start(args, format);
229     vprintf(new_format, args);
230     va_end(args);
231 
232     if (new_format != format)
233     {
234         free((void *)new_format);
235     }
236 
237     return 0;
238 }
239 #endif
240 
241 
242 #endif // _errorHelpers_h
243