1 //
2 // Copyright (c) 2017-2019 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 "testHarness.h"
17 #include "compat.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <cassert>
22 #include <stdexcept>
23 #include <vector>
24 #include "threadTesting.h"
25 #include "errorHelpers.h"
26 #include "kernelHelpers.h"
27 #include "fpcontrol.h"
28 #include "typeWrappers.h"
29 #include "imageHelpers.h"
30 #include "parseParameters.h"
31
32 #if !defined(_WIN32)
33 #include <sys/utsname.h>
34 #include <unistd.h>
35 #endif
36
37 #if !defined(_WIN32) && !defined(__ANDROID__)
38 #include <sys/sysctl.h>
39 #endif
40
41 #include <time.h>
42
43 #if !defined (__APPLE__)
44 #include <CL/cl.h>
45 #endif
46
47 int gTestsPassed = 0;
48 int gTestsFailed = 0;
49 int gFailCount;
50 int gTestCount;
51 cl_uint gRandomSeed = 0;
52 cl_uint gReSeed = 0;
53
54 int gFlushDenormsToZero = 0;
55 int gInfNanSupport = 1;
56 int gIsEmbedded = 0;
57 int gIsOpenCL_C_1_0_Device = 0;
58 int gIsOpenCL_1_0_Device = 0;
59 int gHasLong = 1;
60
61 #define DEFAULT_NUM_ELEMENTS 0x4000
62
runTestHarness(int argc,const char * argv[],int testNum,test_definition testList[],int imageSupportRequired,int forceNoContextCreation,cl_command_queue_properties queueProps)63 int runTestHarness( int argc, const char *argv[], int testNum, test_definition testList[],
64 int imageSupportRequired, int forceNoContextCreation, cl_command_queue_properties queueProps )
65 {
66 return runTestHarnessWithCheck( argc, argv, testNum, testList, forceNoContextCreation, queueProps,
67 ( imageSupportRequired ) ? verifyImageSupport : NULL );
68 }
69
skip_init_info(int count)70 int skip_init_info(int count) {
71 log_info("Test skipped while initialization\n");
72 log_info("SKIPPED %d of %d tests.\n", count, count);
73 return EXIT_SUCCESS;
74 }
75
fail_init_info(int count)76 int fail_init_info(int count) {
77 log_info("Test failed while initialization\n");
78 log_info("FAILED %d of %d tests.\n", count, count);
79 return EXIT_FAILURE;
80 }
version_expected_info(const char * test_name,const char * expected_version,const char * device_version)81 void version_expected_info(const char * test_name, const char * expected_version, const char * device_version) {
82 log_info("%s skipped (requires at least version %s, but the device reports version %s)\n",
83 test_name, expected_version, device_version);
84 }
runTestHarnessWithCheck(int argc,const char * argv[],int testNum,test_definition testList[],int forceNoContextCreation,cl_command_queue_properties queueProps,DeviceCheckFn deviceCheckFn)85 int runTestHarnessWithCheck( int argc, const char *argv[], int testNum, test_definition testList[],
86 int forceNoContextCreation, cl_command_queue_properties queueProps,
87 DeviceCheckFn deviceCheckFn )
88 {
89 test_start();
90
91 cl_device_type device_type = CL_DEVICE_TYPE_DEFAULT;
92 cl_uint num_platforms = 0;
93 cl_platform_id *platforms;
94 cl_device_id device;
95 int num_elements = DEFAULT_NUM_ELEMENTS;
96 cl_uint num_devices = 0;
97 cl_device_id *devices = NULL;
98 cl_uint choosen_device_index = 0;
99 cl_uint choosen_platform_index = 0;
100
101 int err, ret;
102 char *endPtr;
103 int based_on_env_var = 0;
104
105
106 /* Check for environment variable to set device type */
107 char *env_mode = getenv( "CL_DEVICE_TYPE" );
108 if( env_mode != NULL )
109 {
110 based_on_env_var = 1;
111 if( strcmp( env_mode, "gpu" ) == 0 || strcmp( env_mode, "CL_DEVICE_TYPE_GPU" ) == 0 )
112 device_type = CL_DEVICE_TYPE_GPU;
113 else if( strcmp( env_mode, "cpu" ) == 0 || strcmp( env_mode, "CL_DEVICE_TYPE_CPU" ) == 0 )
114 device_type = CL_DEVICE_TYPE_CPU;
115 else if( strcmp( env_mode, "accelerator" ) == 0 || strcmp( env_mode, "CL_DEVICE_TYPE_ACCELERATOR" ) == 0 )
116 device_type = CL_DEVICE_TYPE_ACCELERATOR;
117 else if( strcmp( env_mode, "default" ) == 0 || strcmp( env_mode, "CL_DEVICE_TYPE_DEFAULT" ) == 0 )
118 device_type = CL_DEVICE_TYPE_DEFAULT;
119 else
120 {
121 log_error( "Unknown CL_DEVICE_TYPE env variable setting: %s.\nAborting...\n", env_mode );
122 abort();
123 }
124 }
125
126 #if defined( __APPLE__ )
127 {
128 // report on any unusual library search path indirection
129 char *libSearchPath = getenv( "DYLD_LIBRARY_PATH");
130 if( libSearchPath )
131 log_info( "*** DYLD_LIBRARY_PATH = \"%s\"\n", libSearchPath );
132
133 // report on any unusual framework search path indirection
134 char *frameworkSearchPath = getenv( "DYLD_FRAMEWORK_PATH");
135 if( libSearchPath )
136 log_info( "*** DYLD_FRAMEWORK_PATH = \"%s\"\n", frameworkSearchPath );
137 }
138 #endif
139
140 env_mode = getenv( "CL_DEVICE_INDEX" );
141 if( env_mode != NULL )
142 {
143 choosen_device_index = atoi(env_mode);
144 }
145
146 env_mode = getenv( "CL_PLATFORM_INDEX" );
147 if( env_mode != NULL )
148 {
149 choosen_platform_index = atoi(env_mode);
150 }
151
152 /* Process the command line arguments */
153
154 argc = parseCustomParam(argc, argv);
155 if (argc == -1)
156 {
157 return EXIT_FAILURE;
158 }
159
160 /* Special case: just list the tests */
161 if( ( argc > 1 ) && (!strcmp( argv[ 1 ], "-list" ) || !strcmp( argv[ 1 ], "-h" ) || !strcmp( argv[ 1 ], "--help" )))
162 {
163 char *fileName = getenv("CL_CONFORMANCE_RESULTS_FILENAME");
164
165 log_info( "Usage: %s [<test name>*] [pid<num>] [id<num>] [<device type>]\n", argv[0] );
166 log_info( "\t<test name>\tOne or more of: (wildcard character '*') (default *)\n");
167 log_info( "\tpid<num>\tIndicates platform at index <num> should be used (default 0).\n" );
168 log_info( "\tid<num>\t\tIndicates device at index <num> should be used (default 0).\n" );
169 log_info( "\t<device_type>\tcpu|gpu|accelerator|<CL_DEVICE_TYPE_*> (default CL_DEVICE_TYPE_DEFAULT)\n" );
170 log_info( "\n" );
171 log_info( "\tNOTE: You may pass environment variable CL_CONFORMANCE_RESULTS_FILENAME (currently '%s')\n",
172 fileName != NULL ? fileName : "<undefined>" );
173 log_info( "\t to save results to JSON file.\n" );
174
175 log_info( "\n" );
176 log_info( "Test names:\n" );
177 for( int i = 0; i < testNum; i++ )
178 {
179 log_info( "\t%s\n", testList[i].name );
180 }
181 return EXIT_SUCCESS;
182 }
183
184 /* How are we supposed to seed the random # generators? */
185 if( argc > 1 && strcmp( argv[ argc - 1 ], "randomize" ) == 0 )
186 {
187 gRandomSeed = (cl_uint) time( NULL );
188 log_info( "Random seed: %u.\n", gRandomSeed );
189 gReSeed = 1;
190 argc--;
191 }
192 else
193 {
194 log_info(" Initializing random seed to 0.\n");
195 }
196
197 /* Do we have an integer to specify the number of elements to pass to tests? */
198 if( argc > 1 )
199 {
200 ret = (int)strtol( argv[ argc - 1 ], &endPtr, 10 );
201 if( endPtr != argv[ argc - 1 ] && *endPtr == 0 )
202 {
203 /* By spec, this means the entire string was a valid integer, so we treat it as a num_elements spec */
204 /* (hence why we stored the result in ret first) */
205 num_elements = ret;
206 log_info( "Testing with num_elements of %d\n", num_elements );
207 argc--;
208 }
209 }
210
211 /* Do we have a CPU/GPU specification? */
212 if( argc > 1 )
213 {
214 if( strcmp( argv[ argc - 1 ], "gpu" ) == 0 || strcmp( argv[ argc - 1 ], "CL_DEVICE_TYPE_GPU" ) == 0 )
215 {
216 device_type = CL_DEVICE_TYPE_GPU;
217 argc--;
218 }
219 else if( strcmp( argv[ argc - 1 ], "cpu" ) == 0 || strcmp( argv[ argc - 1 ], "CL_DEVICE_TYPE_CPU" ) == 0 )
220 {
221 device_type = CL_DEVICE_TYPE_CPU;
222 argc--;
223 }
224 else if( strcmp( argv[ argc - 1 ], "accelerator" ) == 0 || strcmp( argv[ argc - 1 ], "CL_DEVICE_TYPE_ACCELERATOR" ) == 0 )
225 {
226 device_type = CL_DEVICE_TYPE_ACCELERATOR;
227 argc--;
228 }
229 else if( strcmp( argv[ argc - 1 ], "CL_DEVICE_TYPE_DEFAULT" ) == 0 )
230 {
231 device_type = CL_DEVICE_TYPE_DEFAULT;
232 argc--;
233 }
234 }
235
236 /* Did we choose a specific device index? */
237 if( argc > 1 )
238 {
239 if( strlen( argv[ argc - 1 ] ) >= 3 && argv[ argc - 1 ][0] == 'i' && argv[ argc - 1 ][1] == 'd' )
240 {
241 choosen_device_index = atoi( &(argv[ argc - 1 ][2]) );
242 argc--;
243 }
244 }
245
246 /* Did we choose a specific platform index? */
247 if( argc > 1 )
248 {
249 if( strlen( argv[ argc - 1 ] ) >= 3 && argv[ argc - 1 ][0] == 'p' && argv[ argc - 1 ][1] == 'i' && argv[ argc - 1 ][2] == 'd')
250 {
251 choosen_platform_index = atoi( &(argv[ argc - 1 ][3]) );
252 argc--;
253 }
254 }
255
256
257
258 switch (device_type)
259 {
260 case CL_DEVICE_TYPE_GPU: log_info("Requesting GPU device "); break;
261 case CL_DEVICE_TYPE_CPU: log_info("Requesting CPU device "); break;
262 case CL_DEVICE_TYPE_ACCELERATOR: log_info("Requesting Accelerator device "); break;
263 case CL_DEVICE_TYPE_DEFAULT: log_info("Requesting Default device "); break;
264 default: log_error("Requesting unknown device "); return EXIT_FAILURE;
265 }
266 log_info(based_on_env_var ? "based on environment variable " : "based on command line ");
267 log_info("for platform index %d and device index %d\n", choosen_platform_index, choosen_device_index);
268
269 #if defined( __APPLE__ )
270 #if defined( __i386__ ) || defined( __x86_64__ )
271 #define kHasSSE3 0x00000008
272 #define kHasSupplementalSSE3 0x00000100
273 #define kHasSSE4_1 0x00000400
274 #define kHasSSE4_2 0x00000800
275 /* check our environment for a hint to disable SSE variants */
276 {
277 const char *env = getenv( "CL_MAX_SSE" );
278 if( env )
279 {
280 extern int _cpu_capabilities;
281 int mask = 0;
282 if( 0 == strcasecmp( env, "SSE4.1" ) )
283 mask = kHasSSE4_2;
284 else if( 0 == strcasecmp( env, "SSSE3" ) )
285 mask = kHasSSE4_2 | kHasSSE4_1;
286 else if( 0 == strcasecmp( env, "SSE3" ) )
287 mask = kHasSSE4_2 | kHasSSE4_1 | kHasSupplementalSSE3;
288 else if( 0 == strcasecmp( env, "SSE2" ) )
289 mask = kHasSSE4_2 | kHasSSE4_1 | kHasSupplementalSSE3 | kHasSSE3;
290 else
291 {
292 log_error( "Error: Unknown CL_MAX_SSE setting: %s\n", env );
293 return EXIT_FAILURE;
294 }
295
296 log_info( "*** Environment: CL_MAX_SSE = %s ***\n", env );
297 _cpu_capabilities &= ~mask;
298 }
299 }
300 #endif
301 #endif
302
303 /* Get the platform */
304 err = clGetPlatformIDs(0, NULL, &num_platforms);
305 if (err) {
306 print_error(err, "clGetPlatformIDs failed");
307 return EXIT_FAILURE;
308 }
309
310 platforms = (cl_platform_id *) malloc( num_platforms * sizeof( cl_platform_id ) );
311 if (!platforms || choosen_platform_index >= num_platforms) {
312 log_error( "platform index out of range -- choosen_platform_index (%d) >= num_platforms (%d)\n", choosen_platform_index, num_platforms );
313 return EXIT_FAILURE;
314 }
315 BufferOwningPtr<cl_platform_id> platformsBuf(platforms);
316
317 err = clGetPlatformIDs(num_platforms, platforms, NULL);
318 if (err) {
319 print_error(err, "clGetPlatformIDs failed");
320 return EXIT_FAILURE;
321 }
322
323 /* Get the number of requested devices */
324 err = clGetDeviceIDs(platforms[choosen_platform_index], device_type, 0, NULL, &num_devices );
325 if (err) {
326 print_error(err, "clGetDeviceIDs failed");
327 return EXIT_FAILURE;
328 }
329
330 devices = (cl_device_id *) malloc( num_devices * sizeof( cl_device_id ) );
331 if (!devices || choosen_device_index >= num_devices) {
332 log_error( "device index out of range -- choosen_device_index (%d) >= num_devices (%d)\n", choosen_device_index, num_devices );
333 return EXIT_FAILURE;
334 }
335 BufferOwningPtr<cl_device_id> devicesBuf(devices);
336
337
338 /* Get the requested device */
339 err = clGetDeviceIDs(platforms[choosen_platform_index], device_type, num_devices, devices, NULL );
340 if (err) {
341 print_error(err, "clGetDeviceIDs failed");
342 return EXIT_FAILURE;
343 }
344
345 device = devices[choosen_device_index];
346
347 err = clGetDeviceInfo( device, CL_DEVICE_TYPE, sizeof(gDeviceType), &gDeviceType, NULL );
348 if( err )
349 {
350 print_error( err, "Unable to get device type" );
351 return TEST_FAIL;
352 }
353
354 if( printDeviceHeader( device ) != CL_SUCCESS )
355 {
356 return EXIT_FAILURE;
357 }
358
359 cl_device_fp_config fpconfig = 0;
360 err = clGetDeviceInfo( device, CL_DEVICE_SINGLE_FP_CONFIG, sizeof( fpconfig ), &fpconfig, NULL );
361 if (err) {
362 print_error(err, "clGetDeviceInfo for CL_DEVICE_SINGLE_FP_CONFIG failed");
363 return EXIT_FAILURE;
364 }
365
366 gFlushDenormsToZero = ( 0 == (fpconfig & CL_FP_DENORM));
367 log_info( "Supports single precision denormals: %s\n", gFlushDenormsToZero ? "NO" : "YES" );
368 log_info( "sizeof( void*) = %d (host)\n", (int) sizeof( void* ) );
369
370 //detect whether profile of the device is embedded
371 char profile[1024] = "";
372 err = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile), profile, NULL);
373 if (err)
374 {
375 print_error(err, "clGetDeviceInfo for CL_DEVICE_PROFILE failed\n" );
376 return EXIT_FAILURE;
377 }
378 gIsEmbedded = NULL != strstr(profile, "EMBEDDED_PROFILE");
379
380 //detect the floating point capabilities
381 cl_device_fp_config floatCapabilities = 0;
382 err = clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_CONFIG, sizeof(floatCapabilities), &floatCapabilities, NULL);
383 if (err)
384 {
385 print_error(err, "clGetDeviceInfo for CL_DEVICE_SINGLE_FP_CONFIG failed\n");
386 return EXIT_FAILURE;
387 }
388
389 // Check for problems that only embedded will have
390 if( gIsEmbedded )
391 {
392 //If the device is embedded, we need to detect if the device supports Infinity and NaN
393 if ((floatCapabilities & CL_FP_INF_NAN) == 0)
394 gInfNanSupport = 0;
395
396 // check the extensions list to see if ulong and long are supported
397 if( !is_extension_available(device, "cles_khr_int64" ))
398 gHasLong = 0;
399 }
400
401 if( getenv( "OPENCL_1_0_DEVICE" ) )
402 {
403 char c_version[1024];
404 gIsOpenCL_1_0_Device = 1;
405 memset( c_version, 0, sizeof( c_version ) );
406
407 if( (err = clGetDeviceInfo( device, CL_DEVICE_OPENCL_C_VERSION, sizeof(c_version), c_version, NULL )) )
408 {
409 log_error( "FAILURE: unable to get CL_DEVICE_OPENCL_C_VERSION on 1.0 device. (%d)\n", err );
410 return EXIT_FAILURE;
411 }
412
413 if( 0 == strncmp( c_version, "OpenCL C 1.0 ", strlen( "OpenCL C 1.0 " ) ) )
414 {
415 gIsOpenCL_C_1_0_Device = 1;
416 log_info( "Device is a OpenCL C 1.0 device\n" );
417 }
418 else
419 log_info( "Device is a OpenCL 1.0 device, but supports OpenCL C 1.1\n" );
420 }
421
422 cl_uint device_address_bits = 0;
423 if( (err = clGetDeviceInfo( device, CL_DEVICE_ADDRESS_BITS, sizeof( device_address_bits ), &device_address_bits, NULL ) ))
424 {
425 print_error( err, "Unable to obtain device address bits" );
426 return EXIT_FAILURE;
427 }
428 if( device_address_bits )
429 log_info( "sizeof( void*) = %d (device)\n", device_address_bits/8 );
430 else
431 {
432 log_error("Invalid device address bit size returned by device.\n");
433 return EXIT_FAILURE;
434 }
435
436
437 /* If we have a device checking function, run it */
438 if( ( deviceCheckFn != NULL ) )
439 {
440 test_status status = deviceCheckFn( device );
441 switch (status)
442 {
443 case TEST_PASS:
444 break;
445 case TEST_FAIL:
446 return fail_init_info(testNum);
447 case TEST_SKIP:
448 return skip_init_info(testNum);
449 }
450 }
451
452 if (num_elements <= 0)
453 num_elements = DEFAULT_NUM_ELEMENTS;
454
455 // On most platforms which support denorm, default is FTZ off. However,
456 // on some hardware where the reference is computed, default might be flush denorms to zero e.g. arm.
457 // This creates issues in result verification. Since spec allows the implementation to either flush or
458 // not flush denorms to zero, an implementation may choose not be flush i.e. return denorm result whereas
459 // reference result may be zero (flushed denorm). Hence we need to disable denorm flushing on host side
460 // where reference is being computed to make sure we get non-flushed reference result. If implementation
461 // returns flushed result, we correctly take care of that in verification code.
462 #if defined(__APPLE__) && defined(__arm__)
463 FPU_mode_type oldMode;
464 DisableFTZ( &oldMode );
465 #endif
466
467 int error = parseAndCallCommandLineTests( argc, argv, device, testNum, testList, forceNoContextCreation, queueProps, num_elements );
468
469 #if defined(__APPLE__) && defined(__arm__)
470 // Restore the old FP mode before leaving.
471 RestoreFPState( &oldMode );
472 #endif
473
474 return (error == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
475 }
476
find_matching_tests(test_definition testList[],unsigned char selectedTestList[],int testNum,const char * argument,bool isWildcard)477 static int find_matching_tests( test_definition testList[], unsigned char selectedTestList[], int testNum,
478 const char *argument, bool isWildcard )
479 {
480 int found_tests = 0;
481 size_t wildcard_length = strlen( argument ) - 1; /* -1 for the asterisk */
482
483 for( int i = 0; i < testNum; i++ )
484 {
485 if( ( !isWildcard && strcmp( testList[i].name, argument ) == 0 ) ||
486 ( isWildcard && strncmp( testList[i].name, argument, wildcard_length ) == 0 ) )
487 {
488 if( selectedTestList[i] )
489 {
490 log_error( "ERROR: Test '%s' has already been selected.\n", testList[i].name );
491 return EXIT_FAILURE;
492 }
493 else if( testList[i].func == NULL )
494 {
495 log_error( "ERROR: Test '%s' is missing implementation.\n", testList[i].name );
496 return EXIT_FAILURE;
497 }
498 else
499 {
500 selectedTestList[i] = 1;
501 found_tests = 1;
502 if( !isWildcard )
503 {
504 break;
505 }
506 }
507 }
508 }
509
510 if( !found_tests )
511 {
512 log_error( "ERROR: The argument '%s' did not match any test names.\n", argument );
513 return EXIT_FAILURE;
514 }
515
516 return EXIT_SUCCESS;
517 }
518
saveResultsToJson(const char * fileName,const char * suiteName,test_definition testList[],unsigned char selectedTestList[],test_status resultTestList[],int testNum)519 static int saveResultsToJson( const char *fileName, const char *suiteName, test_definition testList[],
520 unsigned char selectedTestList[], test_status resultTestList[], int testNum )
521 {
522 FILE *file = fopen( fileName, "w" );
523 if( NULL == file )
524 {
525 log_error( "ERROR: Failed to open '%s' for writing results.\n", fileName );
526 return EXIT_FAILURE;
527 }
528
529 const char *save_map[] = { "success", "failure" };
530 const char *result_map[] = { "pass", "fail", "skip" };
531 const char *linebreak[] = { "", ",\n" };
532 int add_linebreak = 0;
533
534 fprintf( file, "{\n" );
535 fprintf( file, "\t\"cmd\": \"%s\",\n", suiteName );
536 fprintf( file, "\t\"results\": {\n" );
537
538 for( int i = 0; i < testNum; ++i )
539 {
540 if( selectedTestList[i] )
541 {
542 fprintf( file, "%s\t\t\"%s\": \"%s\"", linebreak[add_linebreak], testList[i].name, result_map[(int)resultTestList[i]] );
543 add_linebreak = 1;
544 }
545 }
546 fprintf( file, "\n");
547
548 fprintf( file, "\t}\n" );
549 fprintf( file, "}\n" );
550
551 int ret = fclose( file ) ? 1 : 0;
552
553 log_info( "Saving results to %s: %s!\n", fileName, save_map[ret] );
554
555 return ret;
556 }
557
print_results(int failed,int count,const char * name)558 static void print_results( int failed, int count, const char* name )
559 {
560 if( count < failed )
561 {
562 count = failed;
563 }
564
565 if( failed == 0 )
566 {
567 if( count > 1 )
568 {
569 log_info( "PASSED %d of %d %ss.\n", count, count, name );
570 }
571 else
572 {
573 log_info( "PASSED %s.\n", name );
574 }
575 }
576 else if( failed > 0 )
577 {
578 if( count > 1 )
579 {
580 log_error( "FAILED %d of %d %ss.\n", failed, count, name );
581 }
582 else
583 {
584 log_error( "FAILED %s.\n", name );
585 }
586 }
587 }
588
parseAndCallCommandLineTests(int argc,const char * argv[],cl_device_id device,int testNum,test_definition testList[],int forceNoContextCreation,cl_command_queue_properties queueProps,int num_elements)589 int parseAndCallCommandLineTests( int argc, const char *argv[], cl_device_id device, int testNum,
590 test_definition testList[], int forceNoContextCreation,
591 cl_command_queue_properties queueProps, int num_elements )
592 {
593 int ret = EXIT_SUCCESS;
594
595 unsigned char *selectedTestList = ( unsigned char* ) calloc( testNum, 1 );
596 test_status *resultTestList = NULL;
597
598 if( argc == 1 )
599 {
600 /* No actual arguments, all tests will be run. */
601 memset( selectedTestList, 1, testNum );
602 }
603 else
604 {
605 for( int i = 1; i < argc; i++ )
606 {
607 if( strchr( argv[i], '*' ) != NULL )
608 {
609 ret = find_matching_tests( testList, selectedTestList, testNum, argv[i], true );
610 }
611 else
612 {
613 if( strcmp( argv[i], "all" ) == 0 )
614 {
615 memset( selectedTestList, 1, testNum );
616 break;
617 }
618 else
619 {
620 ret = find_matching_tests( testList, selectedTestList, testNum, argv[i], false );
621 }
622 }
623
624 if( ret == EXIT_FAILURE )
625 {
626 break;
627 }
628 }
629 }
630
631 if( ret == EXIT_SUCCESS )
632 {
633 resultTestList = ( test_status* ) calloc( testNum, sizeof(*resultTestList) );
634
635 callTestFunctions( testList, selectedTestList, resultTestList, testNum, device,
636 forceNoContextCreation, num_elements, queueProps );
637
638 print_results( gFailCount, gTestCount, "sub-test" );
639 print_results( gTestsFailed, gTestsFailed + gTestsPassed, "test" );
640
641 char *filename = getenv( "CL_CONFORMANCE_RESULTS_FILENAME" );
642 if( filename != NULL )
643 {
644 ret = saveResultsToJson( filename, argv[0], testList, selectedTestList, resultTestList, testNum );
645 }
646 }
647
648 free( selectedTestList );
649 free( resultTestList );
650
651 return ret;
652 }
653
callTestFunctions(test_definition testList[],unsigned char selectedTestList[],test_status resultTestList[],int testNum,cl_device_id deviceToUse,int forceNoContextCreation,int numElementsToUse,cl_command_queue_properties queueProps)654 void callTestFunctions( test_definition testList[], unsigned char selectedTestList[], test_status resultTestList[],
655 int testNum, cl_device_id deviceToUse, int forceNoContextCreation, int numElementsToUse,
656 cl_command_queue_properties queueProps )
657 {
658 for( int i = 0; i < testNum; ++i )
659 {
660 if( selectedTestList[i] )
661 {
662 resultTestList[i] = callSingleTestFunction( testList[i], deviceToUse, forceNoContextCreation,
663 numElementsToUse, queueProps );
664 }
665 }
666 }
667
notify_callback(const char * errinfo,const void * private_info,size_t cb,void * user_data)668 void CL_CALLBACK notify_callback(const char *errinfo, const void *private_info, size_t cb, void *user_data)
669 {
670 log_info( "%s\n", errinfo );
671 }
672
673 // Actual function execution
callSingleTestFunction(test_definition test,cl_device_id deviceToUse,int forceNoContextCreation,int numElementsToUse,const cl_queue_properties queueProps)674 test_status callSingleTestFunction( test_definition test, cl_device_id deviceToUse, int forceNoContextCreation,
675 int numElementsToUse, const cl_queue_properties queueProps )
676 {
677 test_status status;
678 cl_int error;
679 cl_context context = NULL;
680 cl_command_queue queue = NULL;
681
682 log_info( "%s...\n", test.name );
683 fflush( stdout );
684
685 const Version device_version = get_device_cl_version(deviceToUse);
686 if (test.min_version > device_version)
687 {
688 version_expected_info(test.name, test.min_version.to_string().c_str(), device_version.to_string().c_str());
689 return TEST_SKIP;
690 }
691
692 /* Create a context to work with, unless we're told not to */
693 if( !forceNoContextCreation )
694 {
695 context = clCreateContext(NULL, 1, &deviceToUse, notify_callback, NULL, &error );
696 if (!context)
697 {
698 print_error( error, "Unable to create testing context" );
699 return TEST_FAIL;
700 }
701
702 if (device_version < Version(2, 0)) {
703 queue = clCreateCommandQueue(context, deviceToUse, queueProps, &error);
704 } else {
705 const cl_command_queue_properties cmd_queueProps = (queueProps)?CL_QUEUE_PROPERTIES:0;
706 cl_command_queue_properties queueCreateProps[] = {cmd_queueProps, queueProps, 0};
707 queue = clCreateCommandQueueWithProperties( context, deviceToUse, &queueCreateProps[0], &error );
708 }
709
710 if( queue == NULL )
711 {
712 print_error( error, "Unable to create testing command queue" );
713 return TEST_FAIL;
714 }
715 }
716
717 /* Run the test and print the result */
718 error = check_functions_for_offline_compiler(test.name, deviceToUse);
719 test_missing_support_offline_cmpiler(error, test.name);
720
721 if( test.func == NULL )
722 {
723 // Skip unimplemented test, can happen when all of the tests are selected
724 log_info("%s test currently not implemented\n", test.name);
725 status = TEST_SKIP;
726 }
727 else
728 {
729 int ret = test.func(deviceToUse, context, queue, numElementsToUse); //test_threaded_function( ptr_basefn_list[i], group, context, num_elements);
730 if( ret == TEST_NOT_IMPLEMENTED )
731 {
732 /* Tests can also let us know they're not implemented yet */
733 log_info("%s test currently not implemented\n", test.name);
734 status = TEST_SKIP;
735 }
736 else if (ret == TEST_SKIPPED_ITSELF)
737 {
738 /* Tests can also let us know they're not supported by the implementation */
739 log_info("%s test not supported\n", test.name);
740 status = TEST_SKIP;
741 }
742 else
743 {
744 /* Print result */
745 if( ret == 0 ) {
746 log_info( "%s passed\n", test.name );
747 gTestsPassed++;
748 status = TEST_PASS;
749 }
750 else
751 {
752 log_error( "%s FAILED\n", test.name );
753 gTestsFailed++;
754 status = TEST_FAIL;
755 }
756 }
757 }
758
759 /* Release the context */
760 if( !forceNoContextCreation )
761 {
762 int error = clFinish(queue);
763 if (error) {
764 log_error("clFinish failed: %d", error);
765 status = TEST_FAIL;
766 }
767 clReleaseCommandQueue( queue );
768 clReleaseContext( context );
769 }
770
771 return status;
772 }
773
774 #if ! defined( __APPLE__ )
memset_pattern4(void * dest,const void * src_pattern,size_t bytes)775 void memset_pattern4(void *dest, const void *src_pattern, size_t bytes )
776 {
777 uint32_t pat = ((uint32_t*) src_pattern)[0];
778 size_t count = bytes / 4;
779 size_t i;
780 uint32_t *d = (uint32_t*)dest;
781
782 for( i = 0; i < count; i++ )
783 d[i] = pat;
784
785 d += i;
786
787 bytes &= 3;
788 if( bytes )
789 memcpy( d, src_pattern, bytes );
790 }
791 #endif
792
GetDeviceType(cl_device_id d)793 cl_device_type GetDeviceType( cl_device_id d )
794 {
795 cl_device_type result = -1;
796 cl_int err = clGetDeviceInfo( d, CL_DEVICE_TYPE, sizeof( result ), &result, NULL );
797 if( CL_SUCCESS != err )
798 log_error( "ERROR: Unable to get device type for device %p\n", d );
799 return result;
800 }
801
802
GetOpposingDevice(cl_device_id device)803 cl_device_id GetOpposingDevice( cl_device_id device )
804 {
805 cl_int error;
806 cl_device_id *otherDevices;
807 cl_uint actualCount;
808 cl_platform_id plat;
809
810 // Get the platform of the device to use for getting a list of devices
811 error = clGetDeviceInfo( device, CL_DEVICE_PLATFORM, sizeof( plat ), &plat, NULL );
812 if( error != CL_SUCCESS )
813 {
814 print_error( error, "Unable to get device's platform" );
815 return NULL;
816 }
817
818 // Get a list of all devices
819 error = clGetDeviceIDs( plat, CL_DEVICE_TYPE_ALL, 0, NULL, &actualCount );
820 if( error != CL_SUCCESS )
821 {
822 print_error( error, "Unable to get list of devices size" );
823 return NULL;
824 }
825 otherDevices = (cl_device_id *)malloc(actualCount*sizeof(cl_device_id));
826 if (NULL == otherDevices) {
827 print_error( error, "Unable to allocate list of other devices." );
828 return NULL;
829 }
830 BufferOwningPtr<cl_device_id> otherDevicesBuf(otherDevices);
831
832 error = clGetDeviceIDs( plat, CL_DEVICE_TYPE_ALL, actualCount, otherDevices, NULL );
833 if( error != CL_SUCCESS )
834 {
835 print_error( error, "Unable to get list of devices" );
836 return NULL;
837 }
838
839 if( actualCount == 1 )
840 {
841 return device; // NULL means error, returning self means we couldn't find another one
842 }
843
844 // Loop and just find one that isn't the one we were given
845 cl_uint i;
846 for( i = 0; i < actualCount; i++ )
847 {
848 if( otherDevices[ i ] != device )
849 {
850 cl_device_type newType;
851 error = clGetDeviceInfo( otherDevices[ i ], CL_DEVICE_TYPE, sizeof( newType ), &newType, NULL );
852 if( error != CL_SUCCESS )
853 {
854 print_error( error, "Unable to get device type for other device" );
855 return NULL;
856 }
857 cl_device_id result = otherDevices[ i ];
858 return result;
859 }
860 }
861
862 // Should never get here
863 return NULL;
864 }
865
get_device_cl_version(cl_device_id device)866 Version get_device_cl_version(cl_device_id device)
867 {
868 size_t str_size;
869 cl_int err = clGetDeviceInfo(device, CL_DEVICE_VERSION, 0, NULL, &str_size);
870 ASSERT_SUCCESS(err, "clGetDeviceInfo");
871
872 std::vector<char> str(str_size);
873 err = clGetDeviceInfo(device, CL_DEVICE_VERSION, str_size, str.data(), NULL);
874 ASSERT_SUCCESS(err, "clGetDeviceInfo");
875
876 if (strstr(str.data(), "OpenCL 1.0") != NULL)
877 return Version(1, 0);
878 else if (strstr(str.data(), "OpenCL 1.1") != NULL)
879 return Version(1, 1);
880 else if (strstr(str.data(), "OpenCL 1.2") != NULL)
881 return Version(1, 2);
882 else if (strstr(str.data(), "OpenCL 2.0") != NULL)
883 return Version(2, 0);
884 else if (strstr(str.data(), "OpenCL 2.1") != NULL)
885 return Version(2, 1);
886 else if (strstr(str.data(), "OpenCL 2.2") != NULL)
887 return Version(2, 2);
888 else if (strstr(str.data(), "OpenCL 3.0") != NULL)
889 return Version(3, 0);
890
891 throw std::runtime_error(std::string("Unknown OpenCL version: ") + str.data());
892 }
893
PrintArch(void)894 void PrintArch( void )
895 {
896 vlog( "sizeof( void*) = %ld\n", sizeof( void *) );
897 #if defined( __ppc__ )
898 vlog( "ARCH:\tppc\n" );
899 #elif defined( __ppc64__ )
900 vlog( "ARCH:\tppc64\n" );
901 #elif defined( __PPC__ )
902 vlog( "ARCH:\tppc\n" );
903 #elif defined( __i386__ )
904 vlog( "ARCH:\ti386\n" );
905 #elif defined( __x86_64__ )
906 vlog( "ARCH:\tx86_64\n" );
907 #elif defined( __arm__ )
908 vlog( "ARCH:\tarm\n" );
909 #elif defined(__aarch64__)
910 vlog( "ARCH:\taarch64\n" );
911 #elif defined (_WIN32)
912 vlog( "ARCH:\tWindows\n" );
913 #else
914 #error unknown arch
915 #endif
916
917 #if defined( __APPLE__ )
918
919 int type = 0;
920 size_t typeSize = sizeof( type );
921 sysctlbyname( "hw.cputype", &type, &typeSize, NULL, 0 );
922 vlog( "cpu type:\t%d\n", type );
923 typeSize = sizeof( type );
924 sysctlbyname( "hw.cpusubtype", &type, &typeSize, NULL, 0 );
925 vlog( "cpu subtype:\t%d\n", type );
926
927 #elif defined( __linux__ )
928 struct utsname buffer;
929
930 if (uname(&buffer) != 0) {
931 vlog("uname error");
932 }
933 else {
934 vlog("system name = %s\n", buffer.sysname);
935 vlog("node name = %s\n", buffer.nodename);
936 vlog("release = %s\n", buffer.release);
937 vlog("version = %s\n", buffer.version);
938 vlog("machine = %s\n", buffer.machine);
939 }
940 #endif
941 }
942
943