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