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