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