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 "harness/compat.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include "procs.h"
24
25
26
get_type_size(cl_context context,cl_command_queue queue,const char * type,cl_ulong * size,cl_device_id device)27 cl_int get_type_size( cl_context context, cl_command_queue queue, const char *type, cl_ulong *size, cl_device_id device )
28 {
29 const char *sizeof_kernel_code[4] =
30 {
31 "", /* optional pragma string */
32 "__kernel __attribute__((reqd_work_group_size(1,1,1))) void test_sizeof(__global uint *dst) \n"
33 "{\n"
34 " dst[0] = (uint) sizeof( ", type, " );\n"
35 "}\n"
36 };
37
38 cl_program p;
39 cl_kernel k;
40 cl_mem m;
41 cl_uint temp;
42
43
44 if (!strncmp(type, "double", 6))
45 {
46 sizeof_kernel_code[0] = "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
47 }
48 else if (!strncmp(type, "half", 4))
49 {
50 sizeof_kernel_code[0] = "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n";
51 }
52 cl_int err = create_single_kernel_helper_with_build_options(
53 context, &p, &k, 4, sizeof_kernel_code, "test_sizeof", nullptr);
54 if( err )
55 return err;
56
57 m = clCreateBuffer( context, CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR, sizeof( cl_ulong ), size, &err );
58 if( NULL == m )
59 {
60 clReleaseProgram( p );
61 clReleaseKernel( k );
62 log_error("\nclCreateBuffer FAILED\n");
63 return err;
64 }
65
66 err = clSetKernelArg( k, 0, sizeof( cl_mem ), &m );
67 if( err )
68 {
69 clReleaseProgram( p );
70 clReleaseKernel( k );
71 clReleaseMemObject( m );
72 log_error("\nclSetKernelArg FAILED\n");
73 return err;
74 }
75
76 err = clEnqueueTask( queue, k, 0, NULL, NULL );
77 clReleaseProgram( p );
78 clReleaseKernel( k );
79 if( err )
80 {
81 clReleaseMemObject( m );
82 log_error( "\nclEnqueueTask FAILED\n" );
83 return err;
84 }
85
86 err = clEnqueueReadBuffer( queue, m, CL_TRUE, 0, sizeof( cl_uint ), &temp, 0, NULL, NULL );
87 clReleaseMemObject( m );
88 if( err )
89 log_error( "\nclEnqueueReadBuffer FAILED\n" );
90
91 *size = (cl_ulong) temp;
92
93 return err;
94 }
95
96 typedef struct size_table
97 {
98 const char *name;
99 cl_ulong size;
100 cl_ulong cl_size;
101 }size_table;
102
103 const size_table scalar_table[] =
104 {
105 // Fixed size entries from table 6.1
106 { "char", 1, sizeof( cl_char ) },
107 { "uchar", 1, sizeof( cl_uchar) },
108 { "unsigned char", 1, sizeof( cl_uchar) },
109 { "short", 2, sizeof( cl_short) },
110 { "ushort", 2, sizeof( cl_ushort) },
111 { "unsigned short", 2, sizeof( cl_ushort) },
112 { "int", 4, sizeof( cl_int ) },
113 { "uint", 4, sizeof( cl_uint) },
114 { "unsigned int", 4, sizeof( cl_uint) },
115 { "float", 4, sizeof( cl_float) },
116 { "long", 8, sizeof( cl_long ) },
117 { "ulong", 8, sizeof( cl_ulong) },
118 { "unsigned long", 8, sizeof( cl_ulong) }
119 };
120
121 const size_table vector_table[] =
122 {
123 // Fixed size entries from table 6.1
124 { "char", 1, sizeof( cl_char ) },
125 { "uchar", 1, sizeof( cl_uchar) },
126 { "short", 2, sizeof( cl_short) },
127 { "ushort", 2, sizeof( cl_ushort) },
128 { "int", 4, sizeof( cl_int ) },
129 { "uint", 4, sizeof( cl_uint) },
130 { "float", 4, sizeof( cl_float) },
131 { "long", 8, sizeof( cl_long ) },
132 { "ulong", 8, sizeof( cl_ulong) }
133 };
134
135 const char *ptr_table[] =
136 {
137 "global void*",
138 "size_t",
139 "sizeof(int)", // check return type of sizeof
140 "ptrdiff_t"
141 };
142
143 const char *other_types[] =
144 {
145 "event_t",
146 "image2d_t",
147 "image3d_t",
148 "sampler_t"
149 };
150
IsPowerOfTwo(cl_ulong x)151 static int IsPowerOfTwo( cl_ulong x ){ return 0 == (x & (x-1)); }
152
test_sizeof(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)153 int test_sizeof(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
154 {
155 size_t i, j;
156 cl_ulong test;
157 cl_uint ptr_size = CL_UINT_MAX;
158 cl_int err = CL_SUCCESS;
159
160 // Check address space size
161 err = clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(ptr_size), &ptr_size, NULL);
162 if( err || ptr_size > 64)
163 {
164 log_error( "FAILED: Unable to get CL_DEVICE_ADDRESS_BITS for device %p\n", device );
165 return -1;
166 }
167 log_info( "\tCL_DEVICE_ADDRESS_BITS = %u\n", ptr_size );
168 ptr_size /= 8;
169
170 // Test standard scalar sizes
171 for( i = 0; i < sizeof( scalar_table ) / sizeof( scalar_table[0] ); i++ )
172 {
173 if( ! gHasLong &&
174 (0 == strcmp(scalar_table[i].name, "long") ||
175 0 == strcmp(scalar_table[i].name, "ulong") ||
176 0 == strcmp(scalar_table[i].name, "unsigned long")))
177 {
178 log_info("\nLongs are not supported by this device. Skipping test.\t");
179 continue;
180 }
181
182 test = CL_ULONG_MAX;
183 err = get_type_size( context, queue, scalar_table[i].name, &test, device);
184 if( err )
185 return err;
186 if( test != scalar_table[i].size )
187 {
188 log_error( "\nFAILED: Type %s has size %lld, but expected size %lld!\n", scalar_table[i].name, test, scalar_table[i].size );
189 return -1;
190 }
191 if( test != scalar_table[i].cl_size )
192 {
193 log_error( "\nFAILED: Type %s has size %lld, but cl_ size is %lld!\n", scalar_table[i].name, test, scalar_table[i].cl_size );
194 return -2;
195 }
196 log_info( "%16s", scalar_table[i].name );
197 }
198 log_info( "\n" );
199
200 // Test standard vector sizes
201 for( j = 2; j <= 16; j *= 2 )
202 {
203 // For each vector size, iterate through types
204 for( i = 0; i < sizeof( vector_table ) / sizeof( vector_table[0] ); i++ )
205 {
206 if( !gHasLong &&
207 (0 == strcmp(vector_table[i].name, "long") ||
208 0 == strcmp(vector_table[i].name, "ulong")))
209 {
210 log_info("\nLongs are not supported by this device. Skipping test.\t");
211 continue;
212 }
213
214 char name[32];
215 sprintf( name, "%s%ld", vector_table[i].name, j );
216
217 test = CL_ULONG_MAX;
218 err = get_type_size( context, queue, name, &test, device );
219 if( err )
220 return err;
221 if( test != j * vector_table[i].size )
222 {
223 log_error( "\nFAILED: Type %s has size %lld, but expected size %lld!\n", name, test, j * vector_table[i].size );
224 return -1;
225 }
226 if( test != j * vector_table[i].cl_size )
227 {
228 log_error( "\nFAILED: Type %s has size %lld, but cl_ size is %lld!\n", name, test, j * vector_table[i].cl_size );
229 return -2;
230 }
231 log_info( "%16s", name );
232 }
233 log_info( "\n" );
234 }
235
236 //Check that pointer sizes are correct
237 for( i = 0; i < sizeof( ptr_table ) / sizeof( ptr_table[0] ); i++ )
238 {
239 test = CL_ULONG_MAX;
240 err = get_type_size( context, queue, ptr_table[i], &test, device );
241 if( err )
242 return err;
243 if( test != ptr_size )
244 {
245 log_error( "\nFAILED: Type %s has size %lld, but expected size %u!\n", ptr_table[i], test, ptr_size );
246 return -1;
247 }
248 log_info( "%16s", ptr_table[i] );
249 }
250
251 // Check that intptr_t is large enough
252 test = CL_ULONG_MAX;
253 err = get_type_size( context, queue, "intptr_t", &test, device );
254 if( err )
255 return err;
256 if( test < ptr_size )
257 {
258 log_error( "\nFAILED: intptr_t has size %lld, but must be at least %u!\n", test, ptr_size );
259 return -1;
260 }
261 if( ! IsPowerOfTwo( test ) )
262 {
263 log_error( "\nFAILED: sizeof(intptr_t) is %lld, but must be a power of two!\n", test );
264 return -2;
265 }
266 log_info( "%16s", "intptr_t" );
267
268 // Check that uintptr_t is large enough
269 test = CL_ULONG_MAX;
270 err = get_type_size( context, queue, "uintptr_t", &test, device );
271 if( err )
272 return err;
273 if( test < ptr_size )
274 {
275 log_error( "\nFAILED: uintptr_t has size %lld, but must be at least %u!\n", test, ptr_size );
276 return -1;
277 }
278 if( ! IsPowerOfTwo( test ) )
279 {
280 log_error( "\nFAILED: sizeof(uintptr_t) is %lld, but must be a power of two!\n", test );
281 return -2;
282 }
283 log_info( "%16s\n", "uintptr_t" );
284
285 //Check that other types are powers of two
286 for( i = 0; i < sizeof( other_types ) / sizeof( other_types[0] ); i++ )
287 {
288 if( 0 == strcmp(other_types[i], "image2d_t") &&
289 checkForImageSupport( device ) == CL_IMAGE_FORMAT_NOT_SUPPORTED)
290 {
291 log_info("\nimages are not supported by this device. Skipping test.\t");
292 continue;
293 }
294
295 if( gIsEmbedded &&
296 0 == strcmp(other_types[i], "image3d_t") &&
297 checkFor3DImageSupport( device ) == CL_IMAGE_FORMAT_NOT_SUPPORTED)
298 {
299 log_info("\n3D images are not supported by this device. Skipping test.\t");
300 continue;
301 }
302
303 if( 0 == strcmp(other_types[i], "sampler_t") &&
304 checkForImageSupport( device ) == CL_IMAGE_FORMAT_NOT_SUPPORTED)
305 {
306 log_info("\nimages are not supported by this device. Skipping test.\t");
307 continue;
308 }
309
310 test = CL_ULONG_MAX;
311 err = get_type_size( context, queue, other_types[i], &test, device );
312 if( err )
313 return err;
314 if( ! IsPowerOfTwo( test ) )
315 {
316 log_error( "\nFAILED: Type %s has size %lld, which is not a power of two (section 6.1.5)!\n", other_types[i], test );
317 return -1;
318 }
319 log_info( "%16s", other_types[i] );
320 }
321 log_info( "\n" );
322
323
324 //Check double
325 if( is_extension_available( device, "cl_khr_fp64" ) )
326 {
327 log_info( "\tcl_khr_fp64:" );
328 test = CL_ULONG_MAX;
329 err = get_type_size( context, queue, "double", &test, device );
330 if( err )
331 return err;
332 if( test != 8 )
333 {
334 log_error( "\nFAILED: double has size %lld, but must be 8!\n", test );
335 return -1;
336 }
337 log_info( "%16s", "double" );
338
339 // Test standard vector sizes
340 for( j = 2; j <= 16; j *= 2 )
341 {
342 char name[32];
343 sprintf( name, "double%ld", j );
344
345 test = CL_ULONG_MAX;
346 err = get_type_size( context, queue, name, &test, device );
347 if( err )
348 return err;
349 if( test != 8*j )
350 {
351 log_error( "\nFAILED: %s has size %lld, but must be %ld!\n", name, test, 8 * j);
352 return -1;
353 }
354 log_info( "%16s", name );
355 }
356 log_info( "\n" );
357 }
358
359 //Check half
360 if( is_extension_available( device, "cl_khr_fp16" ) )
361 {
362 log_info( "\tcl_khr_fp16:" );
363 test = CL_ULONG_MAX;
364 err = get_type_size( context, queue, "half", &test, device );
365 if( err )
366 return err;
367 if( test != 2 )
368 {
369 log_error( "\nFAILED: half has size %lld, but must be 2!\n", test );
370 return -1;
371 }
372 log_info( "%16s", "half" );
373
374 // Test standard vector sizes
375 for( j = 2; j <= 16; j *= 2 )
376 {
377 char name[32];
378 sprintf( name, "half%ld", j );
379
380 test = CL_ULONG_MAX;
381 err = get_type_size( context, queue, name, &test, device );
382 if( err )
383 return err;
384 if( test != 2*j )
385 {
386 log_error( "\nFAILED: %s has size %lld, but must be %ld!\n", name, test, 2 * j);
387 return -1;
388 }
389 log_info( "%16s", name );
390 }
391 log_info( "\n" );
392 }
393
394 return err;
395 }
396
397
398