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 test_fail(msg, ...) \
60 { \
61 log_error(msg, ##__VA_ARGS__); \
62 return TEST_FAIL; \
63 }
64 #define test_error(errCode, msg) test_error_ret(errCode, msg, errCode)
65 #define test_error_fail(errCode, msg) test_error_ret(errCode, msg, TEST_FAIL)
66 #define test_error_ret(errCode, msg, retValue) \
67 { \
68 auto errCodeResult = errCode; \
69 if (errCodeResult != CL_SUCCESS) \
70 { \
71 print_error(errCodeResult, msg); \
72 return retValue; \
73 } \
74 }
75 #define print_error(errCode, msg) \
76 log_error("ERROR: %s! (%s from %s:%d)\n", msg, IGetErrorString(errCode), \
77 __FILE__, __LINE__);
78
79 #define test_missing_feature(errCode, msg) \
80 test_missing_feature_ret(errCode, msg, errCode)
81 // this macro should always return CL_SUCCESS, but print the missing feature
82 // message
83 #define test_missing_feature_ret(errCode, msg, retValue) \
84 { \
85 if (errCode != CL_SUCCESS) \
86 { \
87 print_missing_feature(errCode, msg); \
88 return CL_SUCCESS; \
89 } \
90 }
91 #define print_missing_feature(errCode, msg) \
92 log_missing_feature("ERROR: Subtest %s tests a feature not supported by " \
93 "the device version! (from %s:%d)\n", \
94 msg, __FILE__, __LINE__);
95
96 // expected error code vs. what we got
97 #define test_failure_error(errCode, expectedErrCode, msg) \
98 test_failure_error_ret(errCode, expectedErrCode, msg, \
99 errCode != expectedErrCode)
100 #define test_failure_error_ret(errCode, expectedErrCode, msg, retValue) \
101 { \
102 if (errCode != expectedErrCode) \
103 { \
104 print_failure_error(errCode, expectedErrCode, msg); \
105 return retValue; \
106 } \
107 }
108 #define print_failure_error(errCode, expectedErrCode, msg) \
109 log_error("ERROR: %s! (Got %s, expected %s from %s:%d)\n", msg, \
110 IGetErrorString(errCode), IGetErrorString(expectedErrCode), \
111 __FILE__, __LINE__);
112 #define test_failure_warning(errCode, expectedErrCode, msg) \
113 test_failure_warning_ret(errCode, expectedErrCode, msg, \
114 errCode != expectedErrCode)
115 #define test_failure_warning_ret(errCode, expectedErrCode, msg, retValue) \
116 { \
117 if (errCode != expectedErrCode) \
118 { \
119 print_failure_warning(errCode, expectedErrCode, msg); \
120 warnings++; \
121 } \
122 }
123 #define print_failure_warning(errCode, expectedErrCode, msg) \
124 log_error("WARNING: %s! (Got %s, expected %s from %s:%d)\n", msg, \
125 IGetErrorString(errCode), IGetErrorString(expectedErrCode), \
126 __FILE__, __LINE__);
127
128 // generate an error when an assertion is false (not error code related)
129 #define test_assert_error(condition, msg) \
130 test_assert_error_ret(condition, msg, TEST_FAIL)
131 #define test_assert_error_ret(condition, msg, retValue) \
132 { \
133 if (!(condition)) \
134 { \
135 print_assertion_error(condition, msg); \
136 return retValue; \
137 } \
138 }
139 #define print_assertion_error(condition, msg) \
140 log_error("ERROR: %s! (!(%s) from %s:%d)\n", msg, #condition, __FILE__, \
141 __LINE__);
142
143 #define ASSERT_SUCCESS(expr, msg) \
144 do \
145 { \
146 cl_int _temp_retval = (expr); \
147 if (_temp_retval != CL_SUCCESS) \
148 { \
149 std::stringstream ss; \
150 ss << "ERROR: " << msg << "=" << IGetErrorString(_temp_retval) \
151 << " at " << __FILE__ << ":" << __LINE__ << "\n"; \
152 throw std::runtime_error(ss.str()); \
153 } \
154 } while (0)
155
156 #define test_assert_event_status(comparison_operator, event) \
157 do \
158 { \
159 cl_int status; \
160 cl_int err = clGetEventInfo(event, CL_EVENT_COMMAND_EXECUTION_STATUS, \
161 sizeof(status), &status, nullptr); \
162 test_error(err, "Could not get " #event " info"); \
163 test_assert_error(status comparison_operator CL_COMPLETE, \
164 "Unexpected status for " #event); \
165 } while (false)
166
167 #define test_assert_event_inprogress(event) test_assert_event_status(>, event)
168 #define test_assert_event_terminated(event) test_assert_event_status(<, event)
169 #define test_assert_event_complete(event) test_assert_event_status(==, event)
170
171 extern const char *IGetErrorString(int clErrorCode);
172
173 extern float Ulp_Error_Half(cl_half test, float reference);
174 extern float Ulp_Error(float test, double reference);
175 extern float Ulp_Error_Double(double test, long double reference);
176
177 extern const char *GetChannelTypeName(cl_channel_type type);
178 extern int IsChannelTypeSupported(cl_channel_type type);
179 extern const char *GetChannelOrderName(cl_channel_order order);
180 extern int IsChannelOrderSupported(cl_channel_order order);
181 extern const char *GetAddressModeName(cl_addressing_mode mode);
182 extern const char *GetQueuePropertyName(cl_command_queue_properties properties);
183
184 extern const char *GetDeviceTypeName(cl_device_type type);
185 bool check_functions_for_offline_compiler(const char *subtestname);
186 cl_int OutputBuildLogs(cl_program program, cl_uint num_devices,
187 cl_device_id *device_list);
188
189 // NON-REENTRANT UNLESS YOU PROVIDE A BUFFER PTR (pass null to use static
190 // storage, but it's not reentrant then!)
191 extern const char *GetDataVectorString(void *dataBuffer, size_t typeSize,
192 size_t vecSize, char *buffer);
193
194 #if defined(_WIN32) && !defined(__MINGW32__)
195 #include <stdarg.h>
196 #include <stdio.h>
197 #include <string.h>
vlog_win32(const char * format,...)198 static int vlog_win32(const char *format, ...)
199 {
200 const char *new_format = format;
201
202 if (strstr(format, "%a"))
203 {
204 char *temp;
205 if ((temp = strdup(format)) == NULL)
206 {
207 printf("vlog_win32: Failed to allocate memory for strdup\n");
208 return -1;
209 }
210 new_format = temp;
211 while (*temp)
212 {
213 // replace %a with %f
214 if ((*temp == '%') && (*(temp + 1) == 'a'))
215 {
216 *(temp + 1) = 'f';
217 }
218 temp++;
219 }
220 }
221
222 va_list args;
223 va_start(args, format);
224 vprintf(new_format, args);
225 va_end(args);
226
227 if (new_format != format)
228 {
229 free((void *)new_format);
230 }
231
232 return 0;
233 }
234 #endif
235
236
237 #endif // _errorHelpers_h
238