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