xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/conversions/test_conversions.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1 //
2 // Copyright (c) 2017 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 "harness/ThreadPool.h"
17 #include "harness/testHarness.h"
18 #include "harness/parseParameters.h"
19 #include "harness/mt19937.h"
20 
21 #if defined(__APPLE__)
22 #include <sys/sysctl.h>
23 #endif
24 
25 #if defined(__linux__)
26 #include <unistd.h>
27 #include <sys/syscall.h>
28 #include <linux/sysctl.h>
29 #endif
30 #if defined(__linux__)
31 #include <sys/param.h>
32 #include <libgen.h>
33 #endif
34 
35 #if defined(__MINGW32__)
36 #include <sys/param.h>
37 #endif
38 
39 #include <sstream>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <string.h>
43 #if !defined(_WIN32)
44 #include <libgen.h>
45 #include <sys/mman.h>
46 #endif
47 #include <time.h>
48 
49 #include <algorithm>
50 #include <type_traits>
51 #include <vector>
52 
53 #include "Sleep.h"
54 
55 #include "basic_test_conversions.h"
56 #include <climits>
57 #include <cstring>
58 
59 #if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
60 #include "fplib.h"
61 #endif
62 
63 #if (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
64 /* Rounding modes and saturation for use with qcom 64 bit to float conversion
65  * library */
66 bool qcom_sat;
67 roundingMode qcom_rm;
68 #endif
69 
70 
71 static int ParseArgs(int argc, const char **argv);
72 static void PrintUsage(void);
73 test_status InitCL(cl_device_id device);
74 
75 
76 const char *gTypeNames[kTypeCount] = { "uchar", "char", "ushort", "short",
77                                        "uint",  "int",  "float",  "double",
78                                        "ulong", "long" };
79 
80 const char *gRoundingModeNames[kRoundingModeCount] = { "", "_rte", "_rtp",
81                                                        "_rtn", "_rtz" };
82 
83 const char *gSaturationNames[2] = { "", "_sat" };
84 
85 size_t gTypeSizes[kTypeCount] = {
86     sizeof(cl_uchar), sizeof(cl_char), sizeof(cl_ushort), sizeof(cl_short),
87     sizeof(cl_uint),  sizeof(cl_int),  sizeof(cl_float),  sizeof(cl_double),
88     sizeof(cl_ulong), sizeof(cl_long),
89 };
90 
91 char appName[64] = "ctest";
92 int gMultithread = 1;
93 
94 
test_conversions(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)95 int test_conversions(cl_device_id device, cl_context context,
96                      cl_command_queue queue, int num_elements)
97 {
98     if (argCount)
99     {
100         return MakeAndRunTest<CustomConversionsTest>(device, context, queue,
101                                                      num_elements);
102     }
103     else
104     {
105         return MakeAndRunTest<ConversionsTest>(device, context, queue,
106                                                num_elements);
107     }
108 }
109 
110 
111 test_definition test_list[] = {
112     ADD_TEST(conversions),
113 };
114 
115 const int test_num = ARRAY_SIZE(test_list);
116 
117 
main(int argc,const char ** argv)118 int main(int argc, const char **argv)
119 {
120     int error;
121 
122     argc = parseCustomParam(argc, argv);
123     if (argc == -1)
124     {
125         return 1;
126     }
127 
128     if ((error = ParseArgs(argc, argv))) return error;
129 
130     // Turn off sleep so our tests run to completion
131     PreventSleep();
132     atexit(ResumeSleep);
133 
134     if (!gMultithread) SetThreadCount(1);
135 
136 #if defined(_MSC_VER) && defined(_M_IX86)
137     // VS2005 (and probably others, since long double got deprecated) sets
138     // the x87 to 53-bit precision. This causes problems with the tests
139     // that convert long and ulong to float and double, since they deal
140     // with values that need more precision than that. So, set the x87
141     // to 64-bit precision.
142     unsigned int ignored;
143     _controlfp_s(&ignored, _PC_64, _MCW_PC);
144 #endif
145 
146     vlog("===========================================================\n");
147     vlog("Random seed: %u\n", gRandomSeed);
148     gMTdata = init_genrand(gRandomSeed);
149 
150     const char *arg[] = { argv[0] };
151     int ret =
152         runTestHarnessWithCheck(1, arg, test_num, test_list, true, 0, InitCL);
153 
154     free_mtdata(gMTdata);
155     if (gQueue)
156     {
157         error = clFinish(gQueue);
158         if (error) vlog_error("clFinish failed: %d\n", error);
159     }
160 
161     clReleaseMemObject(gInBuffer);
162 
163     for (int i = 0; i < kCallStyleCount; i++)
164     {
165         clReleaseMemObject(gOutBuffers[i]);
166     }
167     clReleaseCommandQueue(gQueue);
168     clReleaseContext(gContext);
169 
170     return ret;
171 }
172 
173 
ParseArgs(int argc,const char ** argv)174 static int ParseArgs(int argc, const char **argv)
175 {
176     int i;
177     argList = (const char **)calloc(argc, sizeof(char *));
178     argCount = 0;
179 
180     if (NULL == argList && argc > 1) return -1;
181 
182 #if (defined(__APPLE__) || defined(__linux__) || defined(__MINGW32__))
183     { // Extract the app name
184         char baseName[MAXPATHLEN];
185         strncpy(baseName, argv[0], MAXPATHLEN);
186         char *base = basename(baseName);
187         if (NULL != base)
188         {
189             strncpy(appName, base, sizeof(appName));
190             appName[sizeof(appName) - 1] = '\0';
191         }
192     }
193 #elif defined(_WIN32)
194     {
195         char fname[_MAX_FNAME + _MAX_EXT + 1];
196         char ext[_MAX_EXT];
197 
198         errno_t err = _splitpath_s(argv[0], NULL, 0, NULL, 0, fname, _MAX_FNAME,
199                                    ext, _MAX_EXT);
200         if (err == 0)
201         { // no error
202             strcat(fname, ext); // just cat them, size of frame can keep both
203             strncpy(appName, fname, sizeof(appName));
204             appName[sizeof(appName) - 1] = '\0';
205         }
206     }
207 #endif
208 
209     vlog("\n%s", appName);
210     for (i = 1; i < argc; i++)
211     {
212         const char *arg = argv[i];
213         if (NULL == arg) break;
214 
215         vlog("\t%s", arg);
216         if (arg[0] == '-')
217         {
218             arg++;
219             while (*arg != '\0')
220             {
221                 switch (*arg)
222                 {
223                     case 'd': gTestDouble ^= 1; break;
224                     case 'l': gSkipTesting ^= 1; break;
225                     case 'm': gMultithread ^= 1; break;
226                     case 'w': gWimpyMode ^= 1; break;
227                     case '[':
228                         parseWimpyReductionFactor(arg, gWimpyReductionFactor);
229                         break;
230                     case 'z': gForceFTZ ^= 1; break;
231                     case 't': gTimeResults ^= 1; break;
232                     case 'a': gReportAverageTimes ^= 1; break;
233                     case '1':
234                         if (arg[1] == '6')
235                         {
236                             gMinVectorSize = 6;
237                             gMaxVectorSize = 7;
238                             arg++;
239                         }
240                         else
241                         {
242                             gMinVectorSize = 0;
243                             gMaxVectorSize = 2;
244                         }
245                         break;
246 
247                     case '2':
248                         gMinVectorSize = 2;
249                         gMaxVectorSize = 3;
250                         break;
251 
252                     case '3':
253                         gMinVectorSize = 3;
254                         gMaxVectorSize = 4;
255                         break;
256 
257                     case '4':
258                         gMinVectorSize = 4;
259                         gMaxVectorSize = 5;
260                         break;
261 
262                     case '8':
263                         gMinVectorSize = 5;
264                         gMaxVectorSize = 6;
265                         break;
266 
267                     default:
268                         vlog(" <-- unknown flag: %c (0x%2.2x)\n)", *arg, *arg);
269                         PrintUsage();
270                         return -1;
271                 }
272                 arg++;
273             }
274         }
275         else
276         {
277             char *t = NULL;
278             long number = strtol(arg, &t, 0);
279             if (t != arg)
280             {
281                 if (gStartTestNumber != -1)
282                     gEndTestNumber = gStartTestNumber + (int)number;
283                 else
284                     gStartTestNumber = (int)number;
285             }
286             else
287             {
288                 argList[argCount] = arg;
289                 argCount++;
290             }
291         }
292     }
293 
294     // Check for the wimpy mode environment variable
295     if (getenv("CL_WIMPY_MODE"))
296     {
297         vlog("\n");
298         vlog("*** Detected CL_WIMPY_MODE env                          ***\n");
299         gWimpyMode = 1;
300     }
301 
302     vlog("\n");
303 
304     PrintArch();
305 
306     if (gWimpyMode)
307     {
308         vlog("\n");
309         vlog("*** WARNING: Testing in Wimpy mode!                     ***\n");
310         vlog("*** Wimpy mode is not sufficient to verify correctness. ***\n");
311         vlog("*** It gives warm fuzzy feelings and then nevers calls. ***\n\n");
312         vlog("*** Wimpy Reduction Factor: %-27u ***\n\n",
313              gWimpyReductionFactor);
314     }
315 
316     return 0;
317 }
318 
319 
PrintUsage(void)320 static void PrintUsage(void)
321 {
322     int i;
323     vlog("%s [-wz#]: <optional: test names>\n", appName);
324     vlog("\ttest names:\n");
325     vlog("\t\tdestFormat<_sat><_round>_sourceFormat\n");
326     vlog("\t\t\tPossible format types are:\n\t\t\t\t");
327     for (i = 0; i < kTypeCount; i++) vlog("%s, ", gTypeNames[i]);
328     vlog("\n\n\t\t\tPossible saturation values are: (empty) and _sat\n");
329     vlog("\t\t\tPossible rounding values are:\n\t\t\t\t(empty), ");
330     for (i = 1; i < kRoundingModeCount; i++)
331         vlog("%s, ", gRoundingModeNames[i]);
332     vlog("\n\t\t\tExamples:\n");
333     vlog("\t\t\t\tulong_short   converts short to ulong\n");
334     vlog("\t\t\t\tchar_sat_rte_float   converts float to char with saturated "
335          "clipping in round to nearest rounding mode\n\n");
336     vlog("\toptions:\n");
337     vlog("\t\t-d\tToggle testing of double precision.  On by default if "
338          "cl_khr_fp64 is enabled, ignored otherwise.\n");
339     vlog("\t\t-l\tToggle link check mode. When on, testing is skipped, and we "
340          "just check to see that the kernels build. (Off by default.)\n");
341     vlog("\t\t-m\tToggle Multithreading. (On by default.)\n");
342     vlog("\t\t-w\tToggle wimpy mode. When wimpy mode is on, we run a very "
343          "small subset of the tests for each fn. NOT A VALID TEST! (Off by "
344          "default.)\n");
345     vlog(" \t\t-[2^n]\tSet wimpy reduction factor, recommended range of n is "
346          "1-12, default factor(%u)\n",
347          gWimpyReductionFactor);
348     vlog("\t\t-z\tToggle flush to zero mode  (Default: per device)\n");
349     vlog("\t\t-#\tTest just vector size given by #, where # is an element of "
350          "the set {1,2,3,4,8,16}\n");
351     vlog("\n");
352     vlog(
353         "You may also pass the number of the test on which to start.\nA second "
354         "number can be then passed to indicate how many tests to run\n\n");
355 }
356 
357 
358 
InitCL(cl_device_id device)359 test_status InitCL(cl_device_id device)
360 {
361     int error, i;
362     size_t configSize = sizeof(gComputeDevices);
363 
364     if ((error = clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS,
365                                  configSize, &gComputeDevices, NULL)))
366         gComputeDevices = 1;
367 
368     configSize = sizeof(gDeviceFrequency);
369     if ((error = clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY,
370                                  configSize, &gDeviceFrequency, NULL)))
371         gDeviceFrequency = 0;
372 
373     cl_device_fp_config floatCapabilities = 0;
374     if ((error = clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_CONFIG,
375                                  sizeof(floatCapabilities), &floatCapabilities,
376                                  NULL)))
377         floatCapabilities = 0;
378     if (0 == (CL_FP_DENORM & floatCapabilities)) gForceFTZ ^= 1;
379 
380     if (0 == (floatCapabilities & CL_FP_ROUND_TO_NEAREST))
381     {
382         char profileStr[128] = "";
383         // Verify that we are an embedded profile device
384         if ((error = clGetDeviceInfo(device, CL_DEVICE_PROFILE,
385                                      sizeof(profileStr), profileStr, NULL)))
386         {
387             vlog_error("FAILURE: Could not get device profile: error %d\n",
388                        error);
389             return TEST_FAIL;
390         }
391 
392         if (strcmp(profileStr, "EMBEDDED_PROFILE"))
393         {
394             vlog_error("FAILURE: non-embedded profile device does not support "
395                        "CL_FP_ROUND_TO_NEAREST\n");
396             return TEST_FAIL;
397         }
398 
399         if (0 == (floatCapabilities & CL_FP_ROUND_TO_ZERO))
400         {
401             vlog_error("FAILURE: embedded profile device supports neither "
402                        "CL_FP_ROUND_TO_NEAREST or CL_FP_ROUND_TO_ZERO\n");
403             return TEST_FAIL;
404         }
405 
406         gIsRTZ = 1;
407     }
408 
409     else if (is_extension_available(device, "cl_khr_fp64"))
410     {
411         gHasDouble = 1;
412     }
413     gTestDouble &= gHasDouble;
414 
415     // detect whether profile of the device is embedded
416     char profile[1024] = "";
417     if ((error = clGetDeviceInfo(device, CL_DEVICE_PROFILE, sizeof(profile),
418                                  profile, NULL)))
419     {
420         vlog_error("clGetDeviceInfo failed. (%d)\n", error);
421         return TEST_FAIL;
422     }
423     else if (strstr(profile, "EMBEDDED_PROFILE"))
424     {
425         gIsEmbedded = 1;
426         if (!is_extension_available(device, "cles_khr_int64")) gHasLong = 0;
427     }
428 
429     gContext = clCreateContext(NULL, 1, &device, notify_callback, NULL, &error);
430     if (NULL == gContext || error)
431     {
432         vlog_error("clCreateContext failed. (%d)\n", error);
433         return TEST_FAIL;
434     }
435 
436     gQueue = clCreateCommandQueue(gContext, device, 0, &error);
437     if (NULL == gQueue || error)
438     {
439         vlog_error("clCreateCommandQueue failed. (%d)\n", error);
440         return TEST_FAIL;
441     }
442 
443     // Allocate buffers
444     // FIXME: use clProtectedArray for guarded allocations?
445     gIn = malloc(BUFFER_SIZE + 2 * kPageSize);
446     gAllowZ = malloc(BUFFER_SIZE + 2 * kPageSize);
447     gRef = malloc(BUFFER_SIZE + 2 * kPageSize);
448     for (i = 0; i < kCallStyleCount; i++)
449     {
450         gOut[i] = malloc(BUFFER_SIZE + 2 * kPageSize);
451         if (NULL == gOut[i]) return TEST_FAIL;
452     }
453 
454     // setup input buffers
455     gInBuffer =
456         clCreateBuffer(gContext, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR,
457                        BUFFER_SIZE, NULL, &error);
458     if (gInBuffer == NULL || error)
459     {
460         vlog_error("clCreateBuffer failed for input (%d)\n", error);
461         return TEST_FAIL;
462     }
463 
464     // setup output buffers
465     for (i = 0; i < kCallStyleCount; i++)
466     {
467         gOutBuffers[i] =
468             clCreateBuffer(gContext, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
469                            BUFFER_SIZE, NULL, &error);
470         if (gOutBuffers[i] == NULL || error)
471         {
472             vlog_error("clCreateArray failed for output (%d)\n", error);
473             return TEST_FAIL;
474         }
475     }
476 
477     char c[1024];
478     static const char *no_yes[] = { "NO", "YES" };
479     vlog("\nCompute Device info:\n");
480     clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(c), c, NULL);
481     vlog("\tDevice Name: %s\n", c);
482     clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(c), c, NULL);
483     vlog("\tVendor: %s\n", c);
484     clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(c), c, NULL);
485     vlog("\tDevice Version: %s\n", c);
486     clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, sizeof(c), &c, NULL);
487     vlog("\tCL C Version: %s\n", c);
488     clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(c), c, NULL);
489     vlog("\tDriver Version: %s\n", c);
490     vlog("\tProcessing with %ld devices\n", gComputeDevices);
491     vlog("\tDevice Frequency: %d MHz\n", gDeviceFrequency);
492     vlog("\tSubnormal values supported for floats? %s\n",
493          no_yes[0 != (CL_FP_DENORM & floatCapabilities)]);
494     vlog("\tTesting with FTZ mode ON for floats? %s\n", no_yes[0 != gForceFTZ]);
495     vlog("\tTesting with default RTZ mode for floats? %s\n",
496          no_yes[0 != gIsRTZ]);
497     vlog("\tHas Double? %s\n", no_yes[0 != gHasDouble]);
498     if (gHasDouble) vlog("\tTest Double? %s\n", no_yes[0 != gTestDouble]);
499     vlog("\tHas Long? %s\n", no_yes[0 != gHasLong]);
500     vlog("\tTesting vector sizes: ");
501     for (i = gMinVectorSize; i < gMaxVectorSize; i++)
502         vlog("\t%d", vectorSizes[i]);
503     vlog("\n");
504     return TEST_PASS;
505 }
506 
507 
508