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 #include "testBase.h"
17 #include "harness/conversions.h"
18 #include "harness/typeWrappers.h"
19
20 #define TEST_SIZE 512
21
22 const char *equivTestKernelPattern_double =
23 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
24 "__kernel void sample_test(__global double%s *sourceA, __global double%s *sourceB, __global long%s *destValues, __global long%s *destValuesB)\n"
25 "{\n"
26 " int tid = get_global_id(0);\n"
27 " destValues[tid] = %s( sourceA[tid], sourceB[tid] );\n"
28 " destValuesB[tid] = sourceA[tid] %s sourceB[tid];\n"
29 "\n"
30 "}\n";
31
32 const char *equivTestKernelPatternLessGreater_double =
33 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
34 "__kernel void sample_test(__global double%s *sourceA, __global double%s *sourceB, __global long%s *destValues, __global long%s *destValuesB)\n"
35 "{\n"
36 " int tid = get_global_id(0);\n"
37 " destValues[tid] = %s( sourceA[tid], sourceB[tid] );\n"
38 " destValuesB[tid] = (sourceA[tid] < sourceB[tid]) | (sourceA[tid] > sourceB[tid]);\n"
39 "\n"
40 "}\n";
41
42
43 const char *equivTestKernelPattern_double3 =
44 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
45 "__kernel void sample_test(__global double%s *sourceA, __global double%s *sourceB, __global long%s *destValues, __global long%s *destValuesB)\n"
46 "{\n"
47 " int tid = get_global_id(0);\n"
48 " double3 sampA = vload3(tid, (__global double *)sourceA);\n"
49 " double3 sampB = vload3(tid, (__global double *)sourceB);\n"
50 " vstore3(%s( sampA, sampB ), tid, (__global long *)destValues);\n"
51 " vstore3(( sampA %s sampB ), tid, (__global long *)destValuesB);\n"
52 "\n"
53 "}\n";
54
55 const char *equivTestKernelPatternLessGreater_double3 =
56 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
57 "__kernel void sample_test(__global double%s *sourceA, __global double%s *sourceB, __global long%s *destValues, __global long%s *destValuesB)\n"
58 "{\n"
59 " int tid = get_global_id(0);\n"
60 " double3 sampA = vload3(tid, (__global double *)sourceA);\n"
61 " double3 sampB = vload3(tid, (__global double *)sourceB);\n"
62 " vstore3(%s( sampA, sampB ), tid, (__global long *)destValues);\n"
63 " vstore3(( sampA < sampB ) | (sampA > sampB), tid, (__global long *)destValuesB);\n"
64 "\n"
65 "}\n";
66
67
68 typedef bool (*equivVerifyFn)( double inDataA, double inDataB );
69
verify_equiv_values_double(unsigned int vecSize,double * inDataA,double * inDataB,cl_long * outData,equivVerifyFn verifyFn)70 void verify_equiv_values_double( unsigned int vecSize, double *inDataA, double *inDataB, cl_long *outData, equivVerifyFn verifyFn )
71 {
72 unsigned int i;
73 cl_long trueResult;
74 bool result;
75
76 trueResult = ( vecSize == 1 ) ? 1 : -1;
77 for( i = 0; i < vecSize; i++ )
78 {
79 result = verifyFn( inDataA[ i ], inDataB[ i ] );
80 outData[ i ] = result ? trueResult : 0;
81 }
82 }
83
generate_equiv_test_data_double(double * outData,unsigned int vecSize,bool alpha,MTdata d)84 void generate_equiv_test_data_double( double *outData, unsigned int vecSize, bool alpha, MTdata d )
85 {
86 unsigned int i;
87
88 generate_random_data( kDouble, vecSize * TEST_SIZE, d, outData );
89
90 // Fill the first few vectors with NAN in each vector element (or the second set if we're alpha, so we can test either case)
91 if( alpha )
92 outData += vecSize * vecSize;
93 for( i = 0; i < vecSize; i++ )
94 {
95 outData[ 0 ] = NAN;
96 outData += vecSize + 1;
97 }
98 // Make sure the third set is filled regardless, to test the case where both have NANs
99 if( !alpha )
100 outData += vecSize * vecSize;
101 for( i = 0; i < vecSize; i++ )
102 {
103 outData[ 0 ] = NAN;
104 outData += vecSize + 1;
105 }
106 }
107
test_equiv_kernel_double(cl_context context,cl_command_queue queue,const char * fnName,const char * opName,unsigned int vecSize,equivVerifyFn verifyFn,MTdata d)108 int test_equiv_kernel_double(cl_context context, cl_command_queue queue, const char *fnName, const char *opName,
109 unsigned int vecSize, equivVerifyFn verifyFn, MTdata d )
110 {
111 clProgramWrapper program;
112 clKernelWrapper kernel;
113 clMemWrapper streams[4];
114 double inDataA[TEST_SIZE * 16], inDataB[ TEST_SIZE * 16 ];
115 cl_long outData[TEST_SIZE * 16], expected[16];
116 int error, i, j;
117 size_t threads[1], localThreads[1];
118 char kernelSource[10240];
119 char *programPtr;
120 char sizeName[4];
121
122
123 /* Create the source */
124 if( vecSize == 1 )
125 sizeName[ 0 ] = 0;
126 else
127 sprintf( sizeName, "%d", vecSize );
128
129 if(DENSE_PACK_VECS && vecSize == 3) {
130 if (strcmp(fnName, "islessgreater")) {
131 sprintf( kernelSource, equivTestKernelPattern_double3, sizeName, sizeName, sizeName, sizeName, fnName, opName );
132 } else {
133 sprintf( kernelSource, equivTestKernelPatternLessGreater_double3, sizeName, sizeName, sizeName, sizeName, fnName );
134 }
135 } else {
136 if (strcmp(fnName, "islessgreater")) {
137 sprintf( kernelSource, equivTestKernelPattern_double, sizeName, sizeName, sizeName, sizeName, fnName, opName );
138 } else {
139 sprintf( kernelSource, equivTestKernelPatternLessGreater_double, sizeName, sizeName, sizeName, sizeName, fnName );
140 }
141 }
142
143 /* Create kernels */
144 programPtr = kernelSource;
145 if( create_single_kernel_helper( context, &program, &kernel, 1, (const char **)&programPtr, "sample_test" ) )
146 {
147 return -1;
148 }
149
150 /* Generate some streams */
151 generate_equiv_test_data_double( inDataA, vecSize, true, d );
152 generate_equiv_test_data_double( inDataB, vecSize, false, d );
153
154 streams[0] = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR,
155 sizeof(cl_double) * vecSize * TEST_SIZE,
156 &inDataA, &error);
157 if( streams[0] == NULL )
158 {
159 print_error( error, "Creating input array A failed!\n");
160 return -1;
161 }
162 streams[1] = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR,
163 sizeof(cl_double) * vecSize * TEST_SIZE,
164 &inDataB, &error);
165 if( streams[1] == NULL )
166 {
167 print_error( error, "Creating input array A failed!\n");
168 return -1;
169 }
170 streams[2] = clCreateBuffer( context, CL_MEM_READ_WRITE, sizeof( cl_long ) * vecSize * TEST_SIZE, NULL, &error);
171 if( streams[2] == NULL )
172 {
173 print_error( error, "Creating output array failed!\n");
174 return -1;
175 }
176 streams[3] = clCreateBuffer( context, CL_MEM_READ_WRITE, sizeof( cl_long ) * vecSize * TEST_SIZE, NULL, &error);
177 if( streams[3] == NULL )
178 {
179 print_error( error, "Creating output array failed!\n");
180 return -1;
181 }
182
183
184 /* Assign streams and execute */
185 error = clSetKernelArg( kernel, 0, sizeof( streams[0] ), &streams[0] );
186 test_error( error, "Unable to set indexed kernel arguments" );
187 error = clSetKernelArg( kernel, 1, sizeof( streams[1] ), &streams[1] );
188 test_error( error, "Unable to set indexed kernel arguments" );
189 error = clSetKernelArg( kernel, 2, sizeof( streams[2] ), &streams[2] );
190 test_error( error, "Unable to set indexed kernel arguments" );
191 error = clSetKernelArg( kernel, 3, sizeof( streams[3] ), &streams[3] );
192 test_error( error, "Unable to set indexed kernel arguments" );
193
194
195 /* Run the kernel */
196 threads[0] = TEST_SIZE;
197
198 error = get_max_common_work_group_size( context, kernel, threads[0], &localThreads[0] );
199 test_error( error, "Unable to get work group size to use" );
200
201 error = clEnqueueNDRangeKernel( queue, kernel, 1, NULL, threads, localThreads, 0, NULL, NULL );
202 test_error( error, "Unable to execute test kernel" );
203
204 /* Now get the results */
205 error = clEnqueueReadBuffer( queue, streams[2], true, 0, sizeof( cl_long ) * TEST_SIZE * vecSize, outData, 0, NULL, NULL );
206 test_error( error, "Unable to read output array!" );
207
208 /* And verify! */
209 for( i = 0; i < TEST_SIZE; i++ )
210 {
211 verify_equiv_values_double( vecSize, &inDataA[ i * vecSize ], &inDataB[ i * vecSize ], expected, verifyFn);
212
213 for( j = 0; j < (int)vecSize; j++ )
214 {
215 if( expected[ j ] != outData[ i * vecSize + j ] )
216 {
217 log_error( "ERROR: Data sample %d:%d at size %d does not validate! Expected %lld, got %lld, source %f,%f\n",
218 i, j, vecSize, expected[ j ], outData[ i * vecSize + j ], inDataA[i*vecSize + j], inDataB[i*vecSize + j] );
219 return -1;
220 }
221 }
222 }
223
224 /* Now get the results */
225 error = clEnqueueReadBuffer( queue, streams[3], true, 0, sizeof( cl_long ) * TEST_SIZE * vecSize, outData, 0, NULL, NULL );
226 test_error( error, "Unable to read output array!" );
227
228 /* And verify! */
229 for( i = 0; i < TEST_SIZE; i++ )
230 {
231 verify_equiv_values_double( vecSize, &inDataA[ i * vecSize ], &inDataB[ i * vecSize ], expected, verifyFn);
232
233 for( j = 0; j < (int)vecSize; j++ )
234 {
235 if( expected[ j ] != outData[ i * vecSize + j ] )
236 {
237 log_error( "ERROR: Data sample %d:%d at size %d does not validate! Expected %lld, got %lld, source %f,%f\n",
238 i, j, vecSize, expected[ j ], outData[ i * vecSize + j ], inDataA[i*vecSize + j], inDataB[i*vecSize + j] );
239 return -1;
240 }
241 }
242 }
243
244 return 0;
245 }
246
test_equiv_kernel_set_double(cl_device_id device,cl_context context,cl_command_queue queue,const char * fnName,const char * opName,equivVerifyFn verifyFn,MTdata d)247 int test_equiv_kernel_set_double(cl_device_id device, cl_context context, cl_command_queue queue, const char *fnName, const char *opName, equivVerifyFn verifyFn, MTdata d )
248 {
249 unsigned int vecSizes[] = { 1, 2, 3, 4, 8, 16, 0 };
250 unsigned int index;
251 int retVal = 0;
252
253 if (!is_extension_available(device, "cl_khr_fp64")) {
254 log_info("Extension cl_khr_fp64 not supported; skipping double tests.\n");
255 return 0;
256 }
257 log_info("Testing doubles.\n");
258
259 for( index = 0; vecSizes[ index ] != 0; index++ )
260 {
261 // Test!
262 if( test_equiv_kernel_double(context, queue, fnName, opName, vecSizes[ index ], verifyFn, d ) != 0 )
263 {
264 log_error( " Vector double%d FAILED\n", vecSizes[ index ] );
265 retVal = -1;
266 }
267 }
268
269 return retVal;
270 }
271
isequal_verify_fn_double(double valueA,double valueB)272 bool isequal_verify_fn_double( double valueA, double valueB )
273 {
274 if( isnan( valueA ) || isnan( valueB ) )
275 return false;
276 return valueA == valueB;
277 }
278
test_relational_isequal_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)279 int test_relational_isequal_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
280 {
281 RandomSeed seed(gRandomSeed);
282 return test_equiv_kernel_set_double( device, context, queue, "isequal", "==", isequal_verify_fn_double, seed );
283 }
284
isnotequal_verify_fn_double(double valueA,double valueB)285 bool isnotequal_verify_fn_double( double valueA, double valueB )
286 {
287 if( isnan( valueA ) || isnan( valueB ) )
288 return true;
289 return valueA != valueB;
290 }
291
test_relational_isnotequal_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)292 int test_relational_isnotequal_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
293 {
294 RandomSeed seed(gRandomSeed);
295 return test_equiv_kernel_set_double( device, context, queue, "isnotequal", "!=", isnotequal_verify_fn_double, seed );
296 }
297
isgreater_verify_fn_double(double valueA,double valueB)298 bool isgreater_verify_fn_double( double valueA, double valueB )
299 {
300 if( isnan( valueA ) || isnan( valueB ) )
301 return false;
302 return valueA > valueB;
303 }
304
test_relational_isgreater_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)305 int test_relational_isgreater_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
306 {
307 RandomSeed seed(gRandomSeed);
308 return test_equiv_kernel_set_double( device, context, queue, "isgreater", ">", isgreater_verify_fn_double, seed );
309 }
310
isgreaterequal_verify_fn_double(double valueA,double valueB)311 bool isgreaterequal_verify_fn_double( double valueA, double valueB )
312 {
313 if( isnan( valueA ) || isnan( valueB ) )
314 return false;
315 return valueA >= valueB;
316 }
317
test_relational_isgreaterequal_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)318 int test_relational_isgreaterequal_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
319 {
320 RandomSeed seed(gRandomSeed);
321 return test_equiv_kernel_set_double( device, context, queue, "isgreaterequal", ">=", isgreaterequal_verify_fn_double, seed );
322 }
323
isless_verify_fn_double(double valueA,double valueB)324 bool isless_verify_fn_double( double valueA, double valueB )
325 {
326 if( isnan( valueA ) || isnan( valueB ) )
327 return false;
328 return valueA < valueB;
329 }
330
test_relational_isless_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)331 int test_relational_isless_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
332 {
333 RandomSeed seed(gRandomSeed);
334 return test_equiv_kernel_set_double( device, context, queue, "isless", "<", isless_verify_fn_double, seed );
335 }
336
islessequal_verify_fn_double(double valueA,double valueB)337 bool islessequal_verify_fn_double( double valueA, double valueB )
338 {
339 if( isnan( valueA ) || isnan( valueB ) )
340 return false;
341 return valueA <= valueB;
342 }
343
test_relational_islessequal_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)344 int test_relational_islessequal_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
345 {
346 RandomSeed seed(gRandomSeed);
347 return test_equiv_kernel_set_double( device, context, queue, "islessequal", "<=", islessequal_verify_fn_double, seed );
348 }
349
islessgreater_verify_fn_double(double valueA,double valueB)350 bool islessgreater_verify_fn_double( double valueA, double valueB )
351 {
352 if( isnan( valueA ) || isnan( valueB ) )
353 return false;
354 return ( valueA < valueB ) || ( valueA > valueB );
355 }
356
test_relational_islessgreater_double(cl_device_id device,cl_context context,cl_command_queue queue,int numElements)357 int test_relational_islessgreater_double(cl_device_id device, cl_context context, cl_command_queue queue, int numElements )
358 {
359 RandomSeed seed(gRandomSeed);
360 return test_equiv_kernel_set_double( device, context, queue, "islessgreater", "<>", islessgreater_verify_fn_double, seed );
361 }
362
363
364