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