1 //
2 // Copyright (c) 2020 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 <iostream>
17 #include <vector>
18 #include <string>
19 #include <algorithm>
20 #include "procs.h"
21 #include "harness/errorHelpers.h"
22 #include "harness/typeWrappers.h"
23 #include "harness/parseParameters.h"
24
25 using KernelAttributes = std::vector<std::string>;
26
generate_kernel_source(const KernelAttributes & attributes)27 static std::string generate_kernel_source(const KernelAttributes& attributes)
28 {
29 std::string kernel;
30 for (auto attribute : attributes)
31 {
32 kernel += "__attribute__((" + attribute + "))\n";
33 }
34 kernel += "__kernel void test_kernel(){}";
35 return kernel;
36 }
37
38
39 using AttributePermutations = std::vector<KernelAttributes>;
40
41 // The following combinations have been chosen as they place each of the
42 // attribute types in the different orders that they can occur. While distinct
43 // permutations would provide a complete overview of the API the sheer number of
44 // combinations increases the runtime of this test by an unreasonable amount
45 AttributePermutations vect_tests;
46 AttributePermutations work_tests;
47 AttributePermutations reqd_tests;
48
49 AttributePermutations vect_reqd_tests;
50 AttributePermutations work_vect_tests;
51 AttributePermutations reqd_work_tests;
52
53 AttributePermutations vect_work_reqd_tests;
54 AttributePermutations work_reqd_vect_tests;
55 AttributePermutations reqd_vect_work_tests;
56
57
58 // Generate a vector with vec_type_hint(<data_type>) so that it can be used to
59 // generate different kernels
generate_vec_type_hint_data(cl_device_id deviceID)60 static KernelAttributes generate_vec_type_hint_data(cl_device_id deviceID)
61 {
62 KernelAttributes vec_type_hint_data;
63 // TODO Test for signed vectors (char/short/int/etc)
64 std::vector<std::string> vector_types = { "uchar", "ushort", "uint",
65 "float" };
66 if (gHasLong)
67 {
68 vector_types.push_back("ulong");
69 }
70 if (device_supports_half(deviceID))
71 {
72 vector_types.push_back("half");
73 }
74 if (device_supports_double(deviceID))
75 {
76 vector_types.push_back("double");
77 }
78
79 const auto vector_sizes = { "2", "3", "4", "8", "16" };
80 for (auto type : vector_types)
81 {
82 for (auto size : vector_sizes)
83 {
84 vec_type_hint_data.push_back("vec_type_hint(" + type + size + ")");
85 }
86 }
87 return vec_type_hint_data;
88 }
89
90
91 struct WorkGroupDimensions
92 {
93 int x;
94 int y;
95 int z;
96 };
97
98 // Generate vectors to store reqd_work_group_size(<dimensions>) and
99 // work_group_size_hint(<dimensions>) so that they can be used to generate
100 // different kernels
generate_reqd_work_group_size_data(const std::vector<WorkGroupDimensions> & work_group_dimensions)101 static KernelAttributes generate_reqd_work_group_size_data(
102 const std::vector<WorkGroupDimensions>& work_group_dimensions)
103 {
104 KernelAttributes reqd_work_group_size_data;
105 for (auto dimension : work_group_dimensions)
106 {
107 reqd_work_group_size_data.push_back(
108 "reqd_work_group_size(" + std::to_string(dimension.x) + ","
109 + std::to_string(dimension.y) + "," + std::to_string(dimension.z)
110 + ")");
111 }
112 return reqd_work_group_size_data;
113 }
114
generate_work_group_size_data(const std::vector<WorkGroupDimensions> & work_group_dimensions)115 static KernelAttributes generate_work_group_size_data(
116 const std::vector<WorkGroupDimensions>& work_group_dimensions)
117 {
118 KernelAttributes work_group_size_hint_data;
119 for (auto dimension : work_group_dimensions)
120 {
121 work_group_size_hint_data.push_back(
122 "work_group_size_hint(" + std::to_string(dimension.x) + ","
123 + std::to_string(dimension.y) + "," + std::to_string(dimension.z)
124 + ")");
125 }
126 return work_group_size_hint_data;
127 }
128
129 // Populate the Global Vectors which store individual Kernel Attributes
populate_single_attribute_tests(const KernelAttributes & vec_type_hint_data,const KernelAttributes & work_group_size_hint_data,const KernelAttributes & reqd_work_group_size_data)130 static void populate_single_attribute_tests(
131 // Vectors to store the different data that fill the attributes
132 const KernelAttributes& vec_type_hint_data,
133 const KernelAttributes& work_group_size_hint_data,
134 const KernelAttributes& reqd_work_group_size_data)
135 {
136 for (auto vector_test : vec_type_hint_data)
137 {
138 // Initialise vec_type_hint attribute tests
139 vect_tests.push_back({ vector_test });
140 }
141 for (auto work_group_test : work_group_size_hint_data)
142 {
143
144 // Initialise work_group_size_hint attribute test
145 work_tests.push_back({ work_group_test });
146 }
147 for (auto reqd_work_group_test : reqd_work_group_size_data)
148 {
149
150 // Initialise reqd_work_group_size attribute tests
151 reqd_tests.push_back({ reqd_work_group_test });
152 }
153 }
154
155 // Populate the Global Vectors which store the different permutations of 2
156 // Kernel Attributes
populate_double_attribute_tests(const KernelAttributes & vec_type_hint_data,const KernelAttributes & work_group_size_hint_data,const KernelAttributes & reqd_work_group_size_data)157 static void populate_double_attribute_tests(
158 const KernelAttributes& vec_type_hint_data,
159 const KernelAttributes& work_group_size_hint_data,
160 const KernelAttributes& reqd_work_group_size_data)
161 {
162 for (auto vector_test : vec_type_hint_data)
163 {
164 for (auto work_group_test : work_group_size_hint_data)
165 {
166 // Initialise the tests for the permutation of work_group_size_hint
167 // combined with vec_type_hint
168 work_vect_tests.push_back({ work_group_test, vector_test });
169 }
170 for (auto reqd_work_group_test : reqd_work_group_size_data)
171 {
172 // Initialise the tests for the permutation of vec_type_hint and
173 // reqd_work_group_size
174 vect_reqd_tests.push_back({ vector_test, reqd_work_group_test });
175 }
176 }
177 for (auto work_group_test : work_group_size_hint_data)
178 {
179
180 for (auto reqd_work_group_test : reqd_work_group_size_data)
181 {
182 // Initialse the tests for the permutation of reqd_work_group_size
183 // and work_group_size_hint
184 reqd_work_tests.push_back(
185 { reqd_work_group_test, work_group_test });
186 }
187 }
188 }
189
190 // Populate the Global Vectors which store the different permutations of 3
191 // Kernel Attributes
populate_triple_attribute_tests(const KernelAttributes & vec_type_hint_data,const KernelAttributes & work_group_size_hint_data,const KernelAttributes & reqd_work_group_size_data)192 static void populate_triple_attribute_tests(
193 const KernelAttributes& vec_type_hint_data,
194 const KernelAttributes& work_group_size_hint_data,
195 const KernelAttributes& reqd_work_group_size_data)
196 {
197 for (auto vector_test : vec_type_hint_data)
198 {
199 for (auto work_group_test : work_group_size_hint_data)
200 {
201 for (auto reqd_work_group_test : reqd_work_group_size_data)
202 {
203 // Initialise the chosen permutations of 3 attributes
204 vect_work_reqd_tests.push_back(
205 { vector_test, work_group_test, reqd_work_group_test });
206 work_reqd_vect_tests.push_back(
207 { work_group_test, reqd_work_group_test, vector_test });
208 reqd_vect_work_tests.push_back(
209 { reqd_work_group_test, vector_test, work_group_test });
210 }
211 }
212 }
213 }
214
215 static const std::vector<AttributePermutations*>
generate_attribute_tests(const KernelAttributes & vec_type_hint_data,const KernelAttributes & work_group_size_hint_data,const KernelAttributes & reqd_work_group_size_data)216 generate_attribute_tests(const KernelAttributes& vec_type_hint_data,
217 const KernelAttributes& work_group_size_hint_data,
218 const KernelAttributes& reqd_work_group_size_data)
219 {
220 populate_single_attribute_tests(vec_type_hint_data,
221 work_group_size_hint_data,
222 reqd_work_group_size_data);
223 populate_double_attribute_tests(vec_type_hint_data,
224 work_group_size_hint_data,
225 reqd_work_group_size_data);
226 populate_triple_attribute_tests(vec_type_hint_data,
227 work_group_size_hint_data,
228 reqd_work_group_size_data);
229
230 // Store all of the filled vectors in a single structure
231 const std::vector<AttributePermutations*> all_tests = {
232 &vect_tests, &work_tests, &reqd_tests,
233
234 &work_vect_tests, &vect_reqd_tests, &reqd_work_tests,
235
236 &vect_work_reqd_tests, &work_reqd_vect_tests, &reqd_vect_work_tests
237 };
238 return all_tests;
239 }
240
241 static const std::vector<AttributePermutations*>
initialise_attribute_data(cl_device_id deviceID)242 initialise_attribute_data(cl_device_id deviceID)
243 {
244 // This vector stores different work group dimensions that can be used by
245 // the reqd_work_group_size and work_group_size_hint attributes. It
246 // currently only has a single value to minimise time complexity of the
247 // overall test but can be easily changed.
248 static const std::vector<WorkGroupDimensions> work_group_dimensions = {
249 { 1, 1, 1 }
250 };
251 KernelAttributes vec_type_hint_data = generate_vec_type_hint_data(deviceID);
252 KernelAttributes work_group_size_hint_data =
253 generate_work_group_size_data(work_group_dimensions);
254 KernelAttributes reqd_work_group_size_data =
255 generate_reqd_work_group_size_data(work_group_dimensions);
256
257 // Generate all the permutations of attributes to create different test
258 // suites
259 return generate_attribute_tests(vec_type_hint_data,
260 work_group_size_hint_data,
261 reqd_work_group_size_data);
262 }
263
run_test(cl_context context,cl_device_id deviceID,const AttributePermutations & permutations)264 static bool run_test(cl_context context, cl_device_id deviceID,
265 const AttributePermutations& permutations)
266 {
267 bool success = true;
268 for (auto attribute_permutation : permutations)
269 {
270
271 std::string kernel_source_string =
272 generate_kernel_source(attribute_permutation);
273 const char* kernel_src = kernel_source_string.c_str();
274 clProgramWrapper program;
275 clKernelWrapper kernel;
276 cl_int err = create_single_kernel_helper(context, &program, &kernel, 1,
277 &kernel_src, "test_kernel");
278 test_error_ret(err, "create_single_kernel_helper", false);
279
280 // Get the size of the kernel attribute string returned
281 size_t size = 0;
282 err = clGetKernelInfo(kernel, CL_KERNEL_ATTRIBUTES, 0, nullptr, &size);
283 test_error_ret(err, "clGetKernelInfo", false);
284 std::vector<char> attributes(size);
285 err = clGetKernelInfo(kernel, CL_KERNEL_ATTRIBUTES, attributes.size(),
286 attributes.data(), nullptr);
287 test_error_ret(err, "clGetKernelInfo", false);
288 std::string attribute_string(attributes.data());
289 attribute_string.erase(
290 std::remove(attribute_string.begin(), attribute_string.end(), ' '),
291 attribute_string.end());
292 if (gCompilationMode != kOnline)
293 {
294 if (!attribute_string.empty())
295 {
296 success = false;
297 log_error("Error: Expected an empty string\n");
298 log_error("Attribute string reported as: %s\n",
299 attribute_string.c_str());
300 }
301 }
302 else
303 {
304 bool permutation_success = true;
305 for (auto attribute : attribute_permutation)
306 {
307 if (attribute_string.find(attribute) == std::string::npos)
308 {
309 success = false;
310 permutation_success = false;
311 log_error("ERROR: did not find expected attribute: '%s'\n",
312 attribute.c_str());
313 }
314 }
315 if (!permutation_success)
316 {
317 log_error("Attribute string reported as: %s\n",
318 attribute_string.c_str());
319 }
320 }
321 }
322 return success;
323 }
324
test_kernel_attributes(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)325 int test_kernel_attributes(cl_device_id deviceID, cl_context context,
326 cl_command_queue queue, int num_elements)
327 {
328 bool success = true;
329
330 // Vector to store all of the tests
331 const std::vector<AttributePermutations*> all_tests =
332 initialise_attribute_data(deviceID);
333
334 for (auto permutations : all_tests)
335 {
336 success = success && run_test(context, deviceID, *permutations);
337 }
338 return success ? TEST_PASS : TEST_FAIL;
339 }
340