xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/basic/test_hiloeo.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1 //
2 // Copyright (c) 2023 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 <iomanip>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <vector>
23 
24 #include "procs.h"
25 
hi_offset(int index,int vectorSize)26 int hi_offset( int index, int vectorSize) { return index + vectorSize / 2; }
lo_offset(int index,int vectorSize)27 int lo_offset( int index, int vectorSize) { return index; }
even_offset(int index,int vectorSize)28 int even_offset( int index, int vectorSize ) { return index * 2; }
odd_offset(int index,int vectorSize)29 int odd_offset( int index, int vectorSize ) { return index * 2 + 1; }
30 
31 typedef int (*OffsetFunc)( int index, int vectorSize );
32 static const OffsetFunc offsetFuncs[4] = { hi_offset, lo_offset, even_offset, odd_offset };
33 static const char *operatorToUse_names[] = { "hi", "lo", "even", "odd" };
34 static const char *test_str_names[] = { "char", "uchar", "short", "ushort",
35                                         "int",  "uint",  "long",  "ulong",
36                                         "half", "float", "double" };
37 
38 static const unsigned int vector_sizes[] =     { 1, 2, 3, 4, 8, 16};
39 static const unsigned int vector_aligns[] =    { 1, 2, 4, 4, 8, 16};
40 static const unsigned int out_vector_idx[] =   { 0, 0, 1, 1, 3, 4};
41 // if input is size vector_sizes[i], output is size
42 // vector_sizes[out_vector_idx[i]]
43 // input type name is strcat(gentype, vector_size_names[i]);
44 // and output type name is
45 // strcat(gentype, vector_size_names[out_vector_idx[i]]);
46 static const char *vector_size_names[] = { "", "2", "3", "4", "8", "16"};
47 
48 static const size_t kSizes[] = { 1, 1, 2, 2, 4, 4, 8, 8, 2, 4, 8 };
49 static int CheckResults( void *in, void *out, size_t elementCount, int type, int vectorSize, int operatorToUse );
50 
test_hiloeo(cl_device_id device,cl_context context,cl_command_queue queue,int n_elems)51 int test_hiloeo(cl_device_id device, cl_context context, cl_command_queue queue, int n_elems)
52 {
53     int err;
54     int hasDouble = is_extension_available( device, "cl_khr_fp64" );
55     int hasHalf = is_extension_available(device, "cl_khr_fp16");
56     cl_uint vectorSize, operatorToUse;
57     cl_uint type;
58     MTdataHolder d(gRandomSeed);
59 
60     int expressionMode;
61     int numExpressionModes = 2;
62 
63     size_t length = sizeof(cl_int) * 4 * n_elems;
64 
65     std::vector<cl_int> input_ptr(4 * n_elems);
66     std::vector<cl_int> output_ptr(4 * n_elems);
67 
68     for (cl_uint i = 0; i < 4 * (cl_uint)n_elems; i++)
69         input_ptr[i] = genrand_int32(d);
70 
71     for( type = 0; type < sizeof( test_str_names ) / sizeof( test_str_names[0] ); type++ )
72     {
73         // Note: restrict the element count here so we don't end up overrunning the output buffer if we're compensating for 32-bit writes
74         size_t elementCount = length / kSizes[type];
75         clMemWrapper streams[2];
76 
77         // skip double if unavailable
78         if( !hasDouble && ( 0 == strcmp( test_str_names[type], "double" )))
79             continue;
80 
81         if (!hasHalf && (0 == strcmp(test_str_names[type], "half"))) continue;
82 
83         if( !gHasLong &&
84             (( 0 == strcmp( test_str_names[type], "long" )) ||
85             ( 0 == strcmp( test_str_names[type], "ulong" ))))
86             continue;
87 
88         log_info( "%s", test_str_names[type] );
89         fflush( stdout );
90 
91         // Set up data streams for the type
92         streams[0] = clCreateBuffer(context, CL_MEM_READ_WRITE, length, NULL, NULL);
93         if (!streams[0])
94         {
95             log_error("clCreateBuffer failed\n");
96             return -1;
97         }
98         streams[1] = clCreateBuffer(context, CL_MEM_READ_WRITE, length, NULL, NULL);
99         if (!streams[1])
100         {
101             log_error("clCreateBuffer failed\n");
102             return -1;
103         }
104 
105         err = clEnqueueWriteBuffer(queue, streams[0], CL_TRUE, 0, length,
106                                    input_ptr.data(), 0, NULL, NULL);
107         test_error(err, "clEnqueueWriteBuffer failed\n");
108 
109         for( operatorToUse = 0; operatorToUse < sizeof( operatorToUse_names ) / sizeof( operatorToUse_names[0] ); operatorToUse++ )
110         {
111             log_info( " %s", operatorToUse_names[ operatorToUse ] );
112             fflush( stdout );
113             for( vectorSize = 1; vectorSize < sizeof( vector_size_names ) / sizeof( vector_size_names[0] ); vectorSize++ ) {
114                 for(expressionMode = 0; expressionMode < numExpressionModes; ++expressionMode) {
115 
116                     clProgramWrapper program;
117                     clKernelWrapper kernel;
118                     cl_uint outVectorSize = out_vector_idx[vectorSize];
119                     char expression[1024];
120 
121                     const char *source[] = {
122                         "", // optional pragma string
123                         "__kernel void test_", operatorToUse_names[ operatorToUse ], "_", test_str_names[type], vector_size_names[vectorSize],
124                         "(__global ", test_str_names[type], vector_size_names[vectorSize],
125                         " *srcA, __global ", test_str_names[type], vector_size_names[outVectorSize],
126                         " *dst)\n"
127                         "{\n"
128                         "    int  tid = get_global_id(0);\n"
129                         "\n"
130                         "    ", test_str_names[type],
131                         vector_size_names[out_vector_idx[vectorSize]],
132                         " tmp = ", expression, ".", operatorToUse_names[ operatorToUse ], ";\n"
133                         "    dst[tid] = tmp;\n"
134                         "}\n"
135                     };
136 
137                     if (expressionMode == 1 && vector_sizes[vectorSize] != 1)
138                     {
139                         std::ostringstream sstr;
140                         const char *index_chars[] = { "0", "1", "2", "3",
141                                                       "4", "5", "6", "7",
142                                                       "8", "9", "A", "B",
143                                                       "C", "D", "E", "f" };
144                         sstr << "((" << test_str_names[type]
145                              << std::to_string(vector_sizes[vectorSize])
146                              << ")(";
147                         for (unsigned i = 0; i < vector_sizes[vectorSize]; i++)
148                             sstr << " srcA[tid].s" << index_chars[i] << ",";
149                         sstr.seekp(-1, sstr.cur);
150                         sstr << "))";
151                         std::snprintf(expression, sizeof(expression), "%s",
152                                       sstr.str().c_str());
153                     }
154                     else
155                     {
156                         std::snprintf(expression, sizeof(expression),
157                                       "srcA[tid]");
158                     }
159 
160                     if (0 == strcmp( test_str_names[type], "double" ))
161                         source[0] = "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
162 
163                     if (0 == strcmp(test_str_names[type], "half"))
164                         source[0] =
165                             "#pragma OPENCL EXTENSION cl_khr_fp16 : enable\n";
166 
167                     char kernelName[128];
168                     snprintf( kernelName, sizeof( kernelName ), "test_%s_%s%s", operatorToUse_names[ operatorToUse ], test_str_names[type], vector_size_names[vectorSize] );
169                     err = create_single_kernel_helper(context, &program, &kernel, sizeof( source ) / sizeof( source[0] ), source, kernelName );
170                     test_error(err, "create_single_kernel_helper failed\n");
171 
172                     err  = clSetKernelArg(kernel, 0, sizeof streams[0], &streams[0]);
173                     err |= clSetKernelArg(kernel, 1, sizeof streams[1], &streams[1]);
174                     test_error(err, "clSetKernelArg failed\n");
175 
176                     //Wipe the output buffer clean
177                     uint32_t pattern = 0xdeadbeef;
178                     memset_pattern4(output_ptr.data(), &pattern, length);
179                     err = clEnqueueWriteBuffer(queue, streams[1], CL_TRUE, 0,
180                                                length, output_ptr.data(), 0,
181                                                NULL, NULL);
182                     test_error(err, "clEnqueueWriteBuffer failed\n");
183 
184                     size_t size = elementCount / (vector_aligns[vectorSize]);
185                     err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &size, NULL, 0, NULL, NULL);
186                     test_error(err, "clEnqueueNDRangeKernel failed\n");
187 
188                     err = clEnqueueReadBuffer(queue, streams[1], CL_TRUE, 0,
189                                               length, output_ptr.data(), 0,
190                                               NULL, NULL);
191                     test_error(err, "clEnqueueReadBuffer failed\n");
192 
193                     char *inP = (char *)input_ptr.data();
194                     char *outP = (char *)output_ptr.data();
195                     outP += kSizes[type] * ( ( vector_sizes[outVectorSize] ) -
196                                             ( vector_sizes[ out_vector_idx[vectorSize] ] ) );
197                     // was                outP += kSizes[type] * ( ( 1 << outVectorSize ) - ( 1 << ( vectorSize - 1 ) ) );
198                     for( size_t e = 0; e < size; e++ )
199                     {
200                         if( CheckResults( inP, outP, 1, type, vectorSize, operatorToUse ) ) {
201 
202                             log_info("e is %d\n", (int)e);
203                             fflush(stdout);
204                             // break;
205                             return -1;
206                         }
207                         inP += kSizes[type] * ( vector_aligns[vectorSize] );
208                         outP += kSizes[type] * ( vector_aligns[outVectorSize] );
209                     }
210                     log_info( "." );
211                     fflush( stdout );
212                 }
213             }
214         }
215         log_info( "done\n" );
216     }
217 
218     log_info("HiLoEO test passed\n");
219     return err;
220 }
221 
222 template <typename T>
verify(void * in,void * out,size_t elementCount,int type,int vectorSize,int operatorToUse,size_t cmpVectorSize)223 cl_int verify(void *in, void *out, size_t elementCount, int type,
224               int vectorSize, int operatorToUse, size_t cmpVectorSize)
225 {
226     size_t halfVectorSize = vector_sizes[out_vector_idx[vectorSize]];
227     size_t elementSize = kSizes[type];
228     OffsetFunc f = offsetFuncs[operatorToUse];
229     cl_ulong array[8];
230     void *p = array;
231 
232     std::ostringstream ss;
233 
234     T *i = (T *)in, *o = (T *)out;
235 
236     for (cl_uint k = 0; k < elementCount; k++)
237     {
238         T *o2 = (T *)p;
239         for (size_t j = 0; j < halfVectorSize; j++)
240             o2[j] = i[f((int)j, (int)halfVectorSize * 2)];
241 
242         if (memcmp(o, o2, elementSize * cmpVectorSize))
243         {
244             ss << "\n"
245                << k << ") Failure for" << test_str_names[type]
246                << vector_size_names[vectorSize] << '.'
247                << operatorToUse_names[operatorToUse] << " { "
248                << "0x" << std::setfill('0') << std::setw(elementSize * 2)
249                << std::hex << i[0];
250 
251             for (size_t j = 1; j < halfVectorSize * 2; j++) ss << ", " << i[j];
252             ss << " } --> { " << o[0];
253             for (size_t j = 1; j < halfVectorSize; j++) ss << ", " << o[j];
254             ss << " }\n";
255             return -1;
256         }
257         i += 2 * halfVectorSize;
258         o += halfVectorSize;
259     }
260     return 0;
261 }
262 
CheckResults(void * in,void * out,size_t elementCount,int type,int vectorSize,int operatorToUse)263 static int CheckResults(void *in, void *out, size_t elementCount, int type,
264                         int vectorSize, int operatorToUse)
265 {
266     size_t cmpVectorSize = vector_sizes[out_vector_idx[vectorSize]];
267     size_t elementSize = kSizes[type];
268 
269     if (vector_size_names[vectorSize][0] == '3')
270     {
271         if (operatorToUse_names[operatorToUse][0] == 'h'
272             || operatorToUse_names[operatorToUse][0] == 'o') // hi or odd
273         {
274             cmpVectorSize = 1; // special case for vec3 ignored values
275         }
276     }
277 
278     switch (elementSize)
279     {
280         case 1:
281             return verify<char>(in, out, elementCount, type, vectorSize,
282                                 operatorToUse, cmpVectorSize);
283         case 2:
284             return verify<short>(in, out, elementCount, type, vectorSize,
285                                  operatorToUse, cmpVectorSize);
286         case 4:
287             return verify<int>(in, out, elementCount, type, vectorSize,
288                                operatorToUse, cmpVectorSize);
289         case 8:
290             return verify<cl_ulong>(in, out, elementCount, type, vectorSize,
291                                     operatorToUse, cmpVectorSize);
292         default: log_info("Internal error. Unknown data type\n"); return -2;
293     }
294 }
295