Compute Library
 20.02.1
CLHelpers.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2020 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
28 #include "arm_compute/core/Error.h"
29 #include "arm_compute/core/Log.h"
30 #include "arm_compute/core/Types.h"
31 
32 #include <utility>
33 #include <vector>
34 
35 namespace arm_compute
36 {
37 std::string get_cl_type_from_data_type(const DataType &dt)
38 {
39  switch(dt)
40  {
41  case DataType::U8:
42  case DataType::QASYMM8:
43  return "uchar";
44  case DataType::S8:
46  case DataType::QSYMM8:
48  return "char";
49  case DataType::U16:
50  case DataType::QASYMM16:
51  return "ushort";
52  case DataType::S16:
53  case DataType::QSYMM16:
54  return "short";
55  case DataType::U32:
56  return "uint";
57  case DataType::S32:
58  return "int";
59  case DataType::U64:
60  return "ulong";
61  case DataType::S64:
62  return "long";
63  case DataType::F16:
64  return "half";
65  case DataType::F32:
66  return "float";
67  default:
68  ARM_COMPUTE_ERROR("Unsupported input data type.");
69  return "";
70  }
71 }
72 
74 {
75  switch(dt)
76  {
77  case DataType::U8:
78  case DataType::QASYMM8:
79  return "ushort";
80  case DataType::S8:
82  case DataType::QSYMM8:
84  return "short";
85  case DataType::U16:
86  case DataType::QASYMM16:
87  return "uint";
88  case DataType::S16:
89  case DataType::QSYMM16:
90  return "int";
91  case DataType::U32:
92  return "ulong";
93  case DataType::S32:
94  return "long";
95  case DataType::F16:
96  return "float";
97  default:
98  ARM_COMPUTE_ERROR("Cannot get promoted OpenCL type for the input data type.");
99  return "";
100  }
101 }
102 
103 std::string get_cl_unsigned_type_from_element_size(size_t element_size)
104 {
105  switch(element_size)
106  {
107  case 1:
108  return "uchar";
109  case 2:
110  return "ushort";
111  case 4:
112  return "uint";
113  case 8:
114  return "ulong";
115  default:
116  ARM_COMPUTE_ERROR("Data type not supported");
117  return "";
118  }
119 }
120 
121 std::string get_cl_signed_type_from_element_size(size_t element_size)
122 {
123  switch(element_size)
124  {
125  case 1:
126  return "char";
127  case 2:
128  return "short";
129  case 4:
130  return "int";
131  case 8:
132  return "long";
133  default:
134  ARM_COMPUTE_ERROR("Data type not supported");
135  return "";
136  }
137 }
138 
140 {
141  switch(dt)
142  {
143  case DataType::U8:
144  case DataType::QASYMM8:
145  return "uchar";
146  case DataType::S8:
148  case DataType::QSYMM8:
150  return "char";
151  case DataType::U16:
152  case DataType::QASYMM16:
153  return "ushort";
154  case DataType::F16:
155  case DataType::S16:
156  case DataType::QSYMM16:
157  return "short";
158  case DataType::U32:
159  return "uint";
160  case DataType::F32:
161  case DataType::S32:
162  return "int";
163  case DataType::U64:
164  return "ulong";
165  case DataType::S64:
166  return "long";
167  default:
168  ARM_COMPUTE_ERROR("Unsupported input data type.");
169  return "";
170  }
171 }
172 
174 {
175  switch(dt)
176  {
177  case DataType::U8:
178  case DataType::QASYMM8:
179  return "uint";
180  case DataType::S8:
182  case DataType::QSYMM8:
184  return "int";
185  default:
186  ARM_COMPUTE_ERROR("Unsupported data type.");
187  return "";
188  }
189 }
190 
192 {
193  switch(dt)
194  {
195  case DataType::U8:
196  case DataType::S8:
197  case DataType::QSYMM8:
198  case DataType::QASYMM8:
201  return "8";
202  case DataType::U16:
203  case DataType::S16:
204  case DataType::QSYMM16:
205  case DataType::QASYMM16:
206  case DataType::F16:
207  return "16";
208  case DataType::U32:
209  case DataType::S32:
210  case DataType::F32:
211  return "32";
212  case DataType::U64:
213  case DataType::S64:
214  return "64";
215  default:
216  ARM_COMPUTE_ERROR("Unsupported input data type.");
217  return "0";
218  }
219 }
220 
222 {
223  return get_cl_type_from_data_type(dt);
224 }
225 
226 GPUTarget get_target_from_device(const cl::Device &device)
227 {
228  // Query device name size
229  std::string device_name = device.getInfo<CL_DEVICE_NAME>();
230 
231  return get_target_from_name(device_name);
232 }
233 
234 bool arm_non_uniform_workgroup_supported(const cl::Device &device)
235 {
236  return device_supports_extension(device, "cl_arm_non_uniform_work_group_size");
237 }
238 
239 bool fp16_supported(const cl::Device &device)
240 {
241  return device_supports_extension(device, "cl_khr_fp16");
242 }
243 
244 bool dot8_supported(const cl::Device &device)
245 {
246  std::string device_name = device.getInfo<CL_DEVICE_NAME>();
247  const GPUTarget gpu_target = get_target_from_name(device_name);
248 
249  // SW_WORKAROUND: Workaround for DDK revision r14p0.to enable cl_arm_integer_dot_product_int8
250  std::set<GPUTarget> sw_workaround_issue = { GPUTarget::G76 };
251  return (device_supports_extension(device, "cl_arm_integer_dot_product_int8") || sw_workaround_issue.count(gpu_target) != 0);
252 }
253 
254 bool dot8_acc_supported(const cl::Device &device)
255 {
256  return device_supports_extension(device, "cl_arm_integer_dot_product_accumulate_int8");
257 }
258 
259 CLVersion get_cl_version(const cl::Device &device)
260 {
261  std::string version_str = device.getInfo<CL_DEVICE_VERSION>();
262  if(version_str.find("OpenCL 2") != std::string::npos)
263  {
264  return CLVersion::CL20;
265  }
266  else if(version_str.find("OpenCL 1.2") != std::string::npos)
267  {
268  return CLVersion::CL12;
269  }
270  else if(version_str.find("OpenCL 1.1") != std::string::npos)
271  {
272  return CLVersion::CL11;
273  }
274  else if(version_str.find("OpenCL 1.0") != std::string::npos)
275  {
276  return CLVersion::CL10;
277  }
278 
279  return CLVersion::UNKNOWN;
280 }
281 
282 bool device_supports_extension(const cl::Device &device, const char *extension_name)
283 {
284  std::string extensions = device.getInfo<CL_DEVICE_EXTENSIONS>();
285  auto pos = extensions.find(extension_name);
286  return (pos != std::string::npos);
287 }
288 
289 bool cl_winograd_convolution_layer_supported(const Size2D &output_tile, const Size2D &kernel_size, DataLayout data_layout)
290 {
292 
293  using WinogradConfiguration = std::pair<std::pair<int, int>, std::pair<int, int>>;
294 
295  std::vector<WinogradConfiguration> winograd_configs_nchw =
296  {
297  WinogradConfiguration(std::pair<int, int>(1, 2), std::pair<int, int>(1, 3)),
298  WinogradConfiguration(std::pair<int, int>(1, 4), std::pair<int, int>(1, 3)),
299  WinogradConfiguration(std::pair<int, int>(2, 1), std::pair<int, int>(3, 1)),
300  WinogradConfiguration(std::pair<int, int>(4, 1), std::pair<int, int>(3, 1)),
301  WinogradConfiguration(std::pair<int, int>(2, 2), std::pair<int, int>(3, 3)),
302  WinogradConfiguration(std::pair<int, int>(4, 4), std::pair<int, int>(3, 3)),
303  WinogradConfiguration(std::pair<int, int>(4, 4), std::pair<int, int>(5, 5)),
304  WinogradConfiguration(std::pair<int, int>(4, 1), std::pair<int, int>(5, 1)),
305  WinogradConfiguration(std::pair<int, int>(1, 4), std::pair<int, int>(1, 5))
306  };
307 
308  std::vector<WinogradConfiguration> winograd_configs_nhwc =
309  {
310  WinogradConfiguration(std::pair<int, int>(2, 2), std::pair<int, int>(3, 3)),
311  WinogradConfiguration(std::pair<int, int>(1, 4), std::pair<int, int>(1, 3)),
312  WinogradConfiguration(std::pair<int, int>(4, 1), std::pair<int, int>(3, 1)),
313  WinogradConfiguration(std::pair<int, int>(4, 4), std::pair<int, int>(3, 3)),
314  WinogradConfiguration(std::pair<int, int>(4, 4), std::pair<int, int>(5, 5)),
315  WinogradConfiguration(std::pair<int, int>(4, 1), std::pair<int, int>(5, 1)),
316  WinogradConfiguration(std::pair<int, int>(1, 4), std::pair<int, int>(1, 5)),
317  WinogradConfiguration(std::pair<int, int>(1, 2), std::pair<int, int>(1, 7)),
318  WinogradConfiguration(std::pair<int, int>(2, 1), std::pair<int, int>(7, 1)),
319  WinogradConfiguration(std::pair<int, int>(2, 2), std::pair<int, int>(7, 7)),
320  };
321 
322  auto p = std::make_pair(std::pair<int, int>(output_tile.width, output_tile.height),
323  std::pair<int, int>(kernel_size.width, kernel_size.height));
324 
325  // Return true if supported
327  {
328  return (std::find(winograd_configs_nchw.begin(), winograd_configs_nchw.end(), p) != winograd_configs_nchw.end());
329  }
330  else
331  {
332  return (std::find(winograd_configs_nhwc.begin(), winograd_configs_nhwc.end(), p) != winograd_configs_nhwc.end());
333  }
334 }
335 
336 size_t preferred_vector_width(const cl::Device &device, const DataType dt)
337 {
338  switch(dt)
339  {
340  case DataType::U8:
341  case DataType::S8:
342  case DataType::QASYMM8:
344  case DataType::QSYMM8:
346  return device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR>();
347  case DataType::U16:
348  case DataType::S16:
349  case DataType::QSYMM16:
350  case DataType::QASYMM16:
351  return device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT>();
352  case DataType::U32:
353  case DataType::S32:
354  return device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT>();
355  case DataType::F16:
356  case DataType::F32:
357  return device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>();
358  case DataType::U64:
359  case DataType::S64:
360  return device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG>();
361  default:
362  return 1;
363  }
364 }
365 
366 bool preferred_dummy_work_items_support(const cl::Device &device)
367 {
368  ARM_COMPUTE_UNUSED(device);
369  // TODO (COMPMID-2044)
370  return true;
371 }
372 
373 cl::Kernel create_opencl_kernel(CLCoreRuntimeContext *ctx, const std::string &kernel_name, const CLBuildOptions &build_opts)
374 {
375  if(ctx && ctx->kernel_library())
376  {
377  // New api going through the core context
378  return static_cast<cl::Kernel>(ctx->kernel_library()->create_kernel(kernel_name, build_opts.options()));
379  }
380  else
381  {
382  // Legacy code through the singleton
383  return static_cast<cl::Kernel>(CLKernelLibrary::get().create_kernel(kernel_name, build_opts.options()));
384  }
385 }
386 
387 cl::NDRange create_lws_hint_parallel_implementations(unsigned int input_dimension, unsigned int vector_size)
388 {
389  const unsigned int width_leftover = input_dimension % vector_size;
390  const unsigned int border_width = (width_leftover != 0) ? vector_size - width_leftover : 0;
391  const unsigned int num_of_threads = ((input_dimension + border_width) / 16);
392  return cl::NDRange(std::min(8U, num_of_threads));
393 }
394 } // namespace arm_compute
bool dot8_acc_supported(const cl::Device &device)
Helper function to check whether the cl_arm_integer_dot_product_accumulate_int8 extension is supporte...
Definition: CLHelpers.cpp:254
const DataLayout data_layout
Definition: Im2Col.cpp:146
bool dot8_supported(const cl::Device &device)
Helper function to check whether the cl_arm_integer_dot_product_int8 extension is supported.
Definition: CLHelpers.cpp:244
quantized, symmetric fixed-point 16-bit number
bool fp16_supported(const cl::Device &device)
Helper function to check whether the cl_khr_fp16 extension is supported.
Definition: CLHelpers.cpp:239
const StringSet & options() const
Gets the current options list set.
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
bool preferred_dummy_work_items_support(const cl::Device &device)
Helper function to check if "dummy work-items" are preferred to have a power of two NDRange In case d...
Definition: CLHelpers.cpp:366
std::string get_cl_select_type_from_data_type(const DataType &dt)
Translates a tensor data type to the appropriate OpenCL select type.
Definition: CLHelpers.cpp:139
1 channel, 1 U8 per channel
std::string get_cl_dot8_acc_type_from_data_type(const DataType &dt)
Translates a tensor data type to the appropriate OpenCL dot8 accumulator type.
Definition: CLHelpers.cpp:173
CLVersion
Available OpenCL Version.
Definition: CLTypes.h:38
std::string get_cl_signed_type_from_element_size(size_t element_size)
Translates the element size to an signed integer data type.
Definition: CLHelpers.cpp:121
1 channel, 1 F32 per channel
size_t preferred_vector_width(const cl::Device &device, DataType dt)
Helper function to get the preferred native vector width size for built-in scalar types that can be p...
Definition: CLHelpers.cpp:336
GPUTarget get_target_from_name(const std::string &device_name)
Helper function to get the GPU target from a device name.
Definition: GPUTarget.cpp:141
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
static CLKernelLibrary & get()
Access the KernelLibrary singleton.
quantized, asymmetric fixed-point 16-bit number
1 channel, 1 U16 per channel
Copyright (c) 2017-2020 ARM Limited.
size_t height
Height of the image region or rectangle.
Definition: Size2D.h:93
1 channel, 1 F16 per channel
1 channel, 1 S32 per channel
signed 64-bit number
std::string get_data_size_from_data_type(const DataType &dt)
Get the size of a data type in number of bits.
Definition: CLHelpers.cpp:191
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
1 channel, 1 U32 per channel
Core runtime context for OpenCL.
quantized, asymmetric fixed-point 8-bit number unsigned
std::string kernel_name
std::string get_cl_type_from_data_type(const DataType &dt)
Translates a tensor data type to the appropriate OpenCL type.
Definition: CLHelpers.cpp:37
GPUTarget get_target_from_device(const cl::Device &device)
Helper function to get the GPU target from CL device.
Definition: CLHelpers.cpp:226
cl::NDRange create_lws_hint_parallel_implementations(unsigned int input_dimension, unsigned int vector_size)
Creates a suitable LWS hint object for parallel implementations.
Definition: CLHelpers.cpp:387
std::unique_ptr< Kernel > create_kernel()
Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object.
Definition: Helpers.h:86
std::string get_underlying_cl_type_from_data_type(const DataType &dt)
Translates fixed point tensor data type to the underlying OpenCL type.
Definition: CLHelpers.cpp:221
1 channel, 1 S16 per channel
quantized, symmetric fixed-point 8-bit number
Num samples, channels, height, width.
quantized, symmetric per channel fixed-point 8-bit number
CLVersion get_cl_version(const cl::Device &device)
Helper function to get the highest OpenCL version supported.
Definition: CLHelpers.cpp:259
std::string get_cl_promoted_type_from_data_type(const DataType &dt)
Translates a tensor data type to the appropriate OpenCL promoted type.
Definition: CLHelpers.cpp:73
bool device_supports_extension(const cl::Device &device, const char *extension_name)
Helper function to check whether a given extension is supported.
Definition: CLHelpers.cpp:282
size_t width
Width of the image region or rectangle.
Definition: Size2D.h:92
GPUTarget
Available GPU Targets.
Definition: GPUTarget.h:34
CLKernelLibrary * kernel_library() const
Kernel Library accessor.
Class for specifying the size of an image or rectangle.
Definition: Size2D.h:34
cl::Kernel create_opencl_kernel(CLCoreRuntimeContext *ctx, const std::string &kernel_name, const CLBuildOptions &build_opts)
Creates an opencl kernel.
Definition: CLHelpers.cpp:373
std::string get_cl_unsigned_type_from_element_size(size_t element_size)
Translates the element size to an unsigned integer data type.
Definition: CLHelpers.cpp:103
Kernel create_kernel(const std::string &kernel_name, const StringSet &build_options_set={}) const
Creates a kernel from the kernel library.
bool arm_non_uniform_workgroup_supported(const cl::Device &device)
Helper function to check whether the arm_non_uniform_work_group_size extension is supported.
Definition: CLHelpers.cpp:234
quantized, asymmetric fixed-point 8-bit number signed
bool cl_winograd_convolution_layer_supported(const Size2D &output_tile, const Size2D &kernel_size, DataLayout data_layout)
This function checks if the Winograd configuration (defined through the output tile,...
Definition: CLHelpers.cpp:289
unsigned 64-bit number
DataType
Available data types.
Definition: Types.h:75
DataLayout
[DataLayout enum definition]
Definition: Types.h:117
signed 8-bit number