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