• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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