1 
2 // =================================================================================================
3 // This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
4 // project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
5 // width of 100 characters per line.
6 //
7 // Author(s):
8 //   Cedric Nugteren <www.cedricnugteren.nl>
9 //
10 // This file provides declarations for the common utility functions such as a command-line
11 // argument parser. On top of this, it serves as the 'common' header, including the C++ OpenCL
12 // wrapper.
13 //
14 // =================================================================================================
15 
16 #ifndef CLBLAST_UTILITIES_H_
17 #define CLBLAST_UTILITIES_H_
18 
19 #include <string>
20 #include <functional>
21 #include <complex>
22 #include <random>
23 
24 #include "clpp11.hpp"
25 #include "clblast.h"
26 #include "clblast_half.h"
27 #include "utilities/clblast_exceptions.hpp"
28 #include "utilities/msvc.hpp"
29 
30 namespace clblast {
31 // =================================================================================================
32 
33 // Shorthands for half-precision
34 using half = cl_half; // based on the OpenCL type, which is actually an 'unsigned short'
35 
36 // Shorthands for complex data-types
37 using float2 = std::complex<float>;
38 using double2 = std::complex<double>;
39 
40 // Khronos OpenCL extensions
41 const std::string kKhronosHalfPrecision = "cl_khr_fp16";
42 const std::string kKhronosDoublePrecision = "cl_khr_fp64";
43 const std::string kKhronosAttributesAMD = "cl_amd_device_attribute_query";
44 const std::string kKhronosAttributesNVIDIA = "cl_nv_device_attribute_query";
45 
46 // Catched an unknown error
47 constexpr auto kUnknownError = -999;
48 
49 // =================================================================================================
50 
51 // The routine-specific arguments in string form
52 constexpr auto kArgM = "m";
53 constexpr auto kArgN = "n";
54 constexpr auto kArgK = "k";
55 constexpr auto kArgKL = "kl";
56 constexpr auto kArgKU = "ku";
57 constexpr auto kArgLayout = "layout";
58 constexpr auto kArgATransp = "transA";
59 constexpr auto kArgBTransp = "transB";
60 constexpr auto kArgSide = "side";
61 constexpr auto kArgTriangle = "triangle";
62 constexpr auto kArgDiagonal = "diagonal";
63 constexpr auto kArgXInc = "incx";
64 constexpr auto kArgYInc = "incy";
65 constexpr auto kArgXOffset = "offx";
66 constexpr auto kArgYOffset = "offy";
67 constexpr auto kArgALeadDim = "lda";
68 constexpr auto kArgBLeadDim = "ldb";
69 constexpr auto kArgCLeadDim = "ldc";
70 constexpr auto kArgAOffset = "offa";
71 constexpr auto kArgBOffset = "offb";
72 constexpr auto kArgCOffset = "offc";
73 constexpr auto kArgAPOffset = "offap";
74 constexpr auto kArgDotOffset = "offdot";
75 constexpr auto kArgNrm2Offset = "offnrm2";
76 constexpr auto kArgAsumOffset = "offasum";
77 constexpr auto kArgImaxOffset = "offimax";
78 constexpr auto kArgAlpha = "alpha";
79 constexpr auto kArgBeta = "beta";
80 constexpr auto kArgBatchCount = "batch_num";
81 
82 // Constants for im2col
83 constexpr auto kArgChannels = "channels";
84 constexpr auto kArgHeight = "height";
85 constexpr auto kArgWidth = "width";
86 constexpr auto kArgKernelH = "kernelh";
87 constexpr auto kArgKernelW = "kernelw";
88 constexpr auto kArgPadH = "padh";
89 constexpr auto kArgPadW = "padw";
90 constexpr auto kArgStrideH = "strideh";
91 constexpr auto kArgStrideW = "stridew";
92 constexpr auto kArgDilationH = "dilationh";
93 constexpr auto kArgDilationW = "dilationw";
94 
95 // The tuner-specific arguments in string form
96 constexpr auto kArgFraction = "fraction";
97 constexpr auto kArgHeuristicSelection = "heuristic";
98 // PSO tuner-specific arguments in string form
99 constexpr auto kArgPsoSwarmSize = "pso_swarm_size";
100 constexpr auto kArgPsoInfGlobal = "pso_inf_global";
101 constexpr auto kArgPsoInfLocal = "pso_inf_local";
102 constexpr auto kArgPsoInfRandom = "pso_inf_random";
103 // Annealing tuner-specific arguments in string form
104 constexpr auto kArgAnnMaxTemp = "ann_max_temperature";
105 
106 // The common arguments in string form
107 constexpr auto kArgPlatform = "platform";
108 constexpr auto kArgDevice = "device";
109 constexpr auto kArgPrecision = "precision";
110 constexpr auto kArgHelp = "h";
111 constexpr auto kArgQuiet = "q";
112 constexpr auto kArgNoAbbreviations = "no_abbrv";
113 constexpr auto kArgNumRuns = "runs";
114 
115 // The buffer names
116 constexpr auto kBufVecX = "X";
117 constexpr auto kBufVecY = "Y";
118 constexpr auto kBufMatA = "A";
119 constexpr auto kBufMatB = "B";
120 constexpr auto kBufMatC = "C";
121 constexpr auto kBufMatAP = "AP";
122 constexpr auto kBufScalar = "Scalar";
123 
124 // =================================================================================================
125 
126 #ifdef VERBOSE
log_debug(const std::string & log_string)127 inline void log_debug(const std::string &log_string) {
128   printf("[DEBUG] %s\n", log_string.c_str());
129 }
130 #else
log_debug(const std::string &)131 inline void log_debug(const std::string&) { }
132 #endif
133 
134 
135 // =================================================================================================
136 
137 // Converts a regular or complex type to it's base type (e.g. float2 to float)
138 template <typename T> struct BaseType { using Type = T; };
139 template <> struct BaseType<float2> { using Type = float; };
140 template <> struct BaseType<double2> { using Type = double; };
141 
142 // =================================================================================================
143 
144 // Returns a scalar with a default value
145 template <typename T> T GetScalar();
146 
147 // Fixed value scalars
148 template <typename T> T ConstantZero();
149 template <typename T> T ConstantOne();
150 template <typename T> T ConstantNegOne();
151 template <typename T> T Constant(const double val);
152 template <typename T> T SmallConstant();
153 
154 // Returns the absolute value of a scalar (modulus in case of complex numbers)
155 template <typename T> typename BaseType<T>::Type AbsoluteValue(const T value);
156 
157 // =================================================================================================
158 
159 // Structure containing all possible arguments for test clients, including their default values
160 template <typename T>
161 struct Arguments {
162   // Routine-specific arguments
163   size_t m = 1;
164   size_t n = 1;
165   size_t k = 1;
166   size_t ku = 1;
167   size_t kl = 1;
168   Layout layout = Layout::kRowMajor;
169   Transpose a_transpose = Transpose::kNo;
170   Transpose b_transpose = Transpose::kNo;
171   Side side = Side::kLeft;
172   Triangle triangle = Triangle::kUpper;
173   Diagonal diagonal = Diagonal::kUnit;
174   size_t x_inc = 1;
175   size_t y_inc = 1;
176   size_t x_offset = 0;
177   size_t y_offset = 0;
178   size_t a_ld = 1;
179   size_t b_ld = 1;
180   size_t c_ld = 1;
181   size_t a_offset = 0;
182   size_t b_offset = 0;
183   size_t c_offset = 0;
184   size_t ap_offset = 0;
185   size_t dot_offset = 0;
186   size_t nrm2_offset = 0;
187   size_t asum_offset = 0;
188   size_t imax_offset = 0;
189   T alpha = ConstantOne<T>();
190   T beta = ConstantOne<T>();
191   // Arguments for im2col
192   size_t channels = 1;
193   size_t height = 1;
194   size_t width = 1;
195   size_t kernel_h = 3;
196   size_t kernel_w = 3;
197   size_t pad_h = 0;
198   size_t pad_w = 0;
199   size_t stride_h = 1;
200   size_t stride_w = 1;
201   size_t dilation_h = 1;
202   size_t dilation_w = 1;
203   // Batch-specific arguments
204   size_t batch_count = 1;
205   std::vector<size_t> x_offsets; // = {0};
206   std::vector<size_t> y_offsets; // = {0};
207   std::vector<size_t> a_offsets; // = {0};
208   std::vector<size_t> b_offsets; // = {0};
209   std::vector<size_t> c_offsets; // = {0};
210   std::vector<T> alphas; // = {ConstantOne<T>()};
211   std::vector<T> betas; // = {ConstantOne<T>()};
212   // Sizes
213   size_t x_size = 1;
214   size_t y_size = 1;
215   size_t a_size = 1;
216   size_t b_size = 1;
217   size_t c_size = 1;
218   size_t ap_size = 1;
219   size_t scalar_size = 1;
220   // Tuner-specific arguments
221   size_t heuristic_selection = 0;
222   double fraction = 1.0;
223   size_t pso_swarm_size = 8;
224   double pso_inf_global = 0.3;
225   double pso_inf_local = 0.6;
226   double pso_inf_random = 0.1;
227   double ann_max_temperature = 1.0; // Is it a valid default value?
228   // Client-specific arguments
229   int compare_clblas = 1;
230   int compare_cblas = 1;
231   int compare_cublas = 1;
232   size_t step = 1;
233   size_t num_steps = 0;
234   size_t num_runs = 10;
235   #ifdef CLBLAST_REF_CUBLAS
236     void* cublas_handle; // cublasHandle_t
237   #endif
238   // Common arguments
239   size_t platform_id = 0;
240   size_t device_id = 0;
241   Precision precision = Precision::kSingle;
242   bool print_help = false;
243   bool silent = false;
244   bool no_abbrv = false;
245 };
246 
247 // =================================================================================================
248 
249 // Converts a value (e.g. an integer) to a string. This also covers special cases for CLBlast
250 // data-types such as the Layout and Transpose data-types.
251 template <typename T>
252 std::string ToString(T value);
253 
254 // =================================================================================================
255 
256 // Parses command-line and environmental-variable arguments into a std::vector of strings
257 std::vector<std::string> RetrieveCommandLineArguments(int argc, char *argv[]);
258 
259 // Helper for the function "GetArgument"
260 template <typename T>
261 T ConvertArgument(const char* value);
262 
263 // Variant of "ConvertArgument" with default values
264 template <typename T>
265 T ConvertArgument(const char* value, T default_value);
266 
267 // Basic argument parser, matching patterns in the form of "-option value" and "--option value"
268 template <typename T>
269 T GetArgument(const std::vector<std::string> &arguments, std::string &help,
270               const std::string &option, const T default_value);
271 
272 // Returns the precision only
273 Precision GetPrecision(const std::vector<std::string> &arguments,
274                        const Precision default_precision = Precision::kSingle);
275 
276 // As in "GetArgument", but now only checks whether an argument is given or not
277 bool CheckArgument(const std::vector<std::string> &arguments, std::string &help, const std::string &option);
278 
279 // =================================================================================================
280 
281 // Test/example data lower and upper limit
282 constexpr auto kTestDataLowerLimit = -2.0;
283 constexpr auto kTestDataUpperLimit = 2.0;
284 
285 // Populates a vector with random data
286 template <typename T>
287 void PopulateVector(std::vector<T> &vector, std::mt19937 &mt, std::uniform_real_distribution<double> &dist);
288 
289 // =================================================================================================
290 
291 // Converts a 'real' value to a 'real argument' value to be passed to a kernel. Normally there is
292 // no conversion, but half-precision is not supported as kernel argument so it is converted to float.
293 template <typename T> struct RealArg { using Type = T; };
294 template <> struct RealArg<half> { using Type = float; };
295 template <typename T> typename RealArg<T>::Type GetRealArg(const T value);
296 
297 // =================================================================================================
298 
299 // Rounding functions
300 size_t CeilDiv(const size_t x, const size_t y);
301 size_t Ceil(const size_t x, const size_t y);
302 
303 // Returns whether or not 'a' is a multiple of 'b'
304 bool IsMultiple(const size_t a, const size_t b);
305 
306 // =================================================================================================
307 
308 // Convert the precision enum into bytes, e.g. a double takes up 8 bytes
309 size_t GetBytes(const Precision precision);
310 
311 // Convert the template argument into a precision value
312 template <typename T>
313 Precision PrecisionValue();
314 
315 // =================================================================================================
316 
317 // Returns false is this precision is not supported by the device
318 template <typename T>
319 bool PrecisionSupported(const Device &device);
320 
321 // =================================================================================================
322 
323 // Device information in a specific CLBlast form
324 std::string GetDeviceType(const Device& device);
325 std::string GetDeviceVendor(const Device& device);
326 std::string GetDeviceArchitecture(const Device& device);
327 std::string GetDeviceName(const Device& device);
328 
329 // =================================================================================================
330 } // namespace clblast
331 
332 // CLBLAST_UTILITIES_H_
333 #endif
334