CLBlast/src/utilities/utilities.hpp

392 lines
14 KiB
C++

// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
// Cedric Nugteren <www.cedricnugteren.nl>
//
// This file provides declarations for the common utility functions such as a command-line
// argument parser. On top of this, it serves as the 'common' header, including the C++ OpenCL
// wrapper.
//
// =================================================================================================
#ifndef CLBLAST_UTILITIES_H_
#define CLBLAST_UTILITIES_H_
#include <string>
#include <functional>
#include <complex>
#include <random>
#include <algorithm>
#include <iterator>
#ifdef OPENCL_API
#include "clpp11.hpp"
#include "clblast.h"
#elif CUDA_API
#include "cupp11.hpp"
#include "clblast_cuda.h"
#endif
#include "clblast_half.h"
#include "utilities/clblast_exceptions.hpp"
#include "utilities/msvc.hpp"
namespace clblast {
// =================================================================================================
// Shorthands for half-precision
using half = unsigned short; // the 'cl_half' OpenCL type is actually an 'unsigned short'
// Shorthands for complex data-types
using float2 = std::complex<float>;
using double2 = std::complex<double>;
// Khronos OpenCL extensions
const std::string kKhronosAttributesAMD = "cl_amd_device_attribute_query";
const std::string kKhronosAttributesNVIDIA = "cl_nv_device_attribute_query";
const std::string kKhronosIntelSubgroups = "cl_intel_subgroups";
// Catched an unknown error
constexpr auto kUnknownError = -999;
// Canary size to add to buffers to check for buffer overflows
constexpr auto kCanarySize = 127;
// =================================================================================================
// The routine-specific arguments in string form
constexpr auto kArgM = "m";
constexpr auto kArgN = "n";
constexpr auto kArgK = "k";
constexpr auto kArgKL = "kl";
constexpr auto kArgKU = "ku";
constexpr auto kArgLayout = "layout";
constexpr auto kArgATransp = "transA";
constexpr auto kArgBTransp = "transB";
constexpr auto kArgSide = "side";
constexpr auto kArgTriangle = "triangle";
constexpr auto kArgDiagonal = "diagonal";
constexpr auto kArgKernelMode = "kernel_mode";
constexpr auto kArgXInc = "incx";
constexpr auto kArgYInc = "incy";
constexpr auto kArgXOffset = "offx";
constexpr auto kArgYOffset = "offy";
constexpr auto kArgALeadDim = "lda";
constexpr auto kArgBLeadDim = "ldb";
constexpr auto kArgCLeadDim = "ldc";
constexpr auto kArgAOffset = "offa";
constexpr auto kArgBOffset = "offb";
constexpr auto kArgCOffset = "offc";
constexpr auto kArgAPOffset = "offap";
constexpr auto kArgDotOffset = "offdot";
constexpr auto kArgNrm2Offset = "offnrm2";
constexpr auto kArgAsumOffset = "offasum";
constexpr auto kArgImaxOffset = "offimax";
constexpr auto kArgAlpha = "alpha";
constexpr auto kArgBeta = "beta";
constexpr auto kArgBatchCount = "batch_num";
constexpr auto kArgNumKernels = "num_kernels";
// Constants for im2col
constexpr auto kArgChannels = "channels";
constexpr auto kArgHeight = "height";
constexpr auto kArgWidth = "width";
constexpr auto kArgKernelH = "kernelh";
constexpr auto kArgKernelW = "kernelw";
constexpr auto kArgPadH = "padh";
constexpr auto kArgPadW = "padw";
constexpr auto kArgStrideH = "strideh";
constexpr auto kArgStrideW = "stridew";
constexpr auto kArgDilationH = "dilationh";
constexpr auto kArgDilationW = "dilationw";
// The tuner-specific arguments in string form
constexpr auto kArgFraction = "fraction";
constexpr auto kArgHeuristicSelection = "heuristic";
constexpr auto kArgMaxL2Norm = "max_l2_norm";
// PSO tuner-specific arguments in string form
constexpr auto kArgPsoSwarmSize = "pso_swarm_size";
constexpr auto kArgPsoInfGlobal = "pso_inf_global";
constexpr auto kArgPsoInfLocal = "pso_inf_local";
constexpr auto kArgPsoInfRandom = "pso_inf_random";
// Annealing tuner-specific arguments in string form
constexpr auto kArgAnnMaxTemp = "ann_max_temperature";
// The common arguments in string form
constexpr auto kArgPlatform = "platform";
constexpr auto kArgDevice = "device";
constexpr auto kArgPrecision = "precision";
constexpr auto kArgHelp = "h";
constexpr auto kArgQuiet = "q";
constexpr auto kArgNoAbbreviations = "no_abbrv";
constexpr auto kArgNumRuns = "runs";
constexpr auto kArgFullStatistics = "full_statistics";
// The buffer names
constexpr auto kBufVecX = "X";
constexpr auto kBufVecY = "Y";
constexpr auto kBufMatA = "A";
constexpr auto kBufMatB = "B";
constexpr auto kBufMatC = "C";
constexpr auto kBufMatAP = "AP";
constexpr auto kBufScalar = "Scalar";
constexpr auto kBufScalarUint = "ScalarUint";
// =================================================================================================
#ifdef VERBOSE
inline void log_debug(const std::string &log_string) {
printf("[DEBUG] %s\n", log_string.c_str());
}
#else
inline void log_debug(const std::string&) { }
#endif
// =================================================================================================
// Converts a regular or complex type to it's base type (e.g. float2 to float)
template <typename T> struct BaseType { using Type = T; };
template <> struct BaseType<float2> { using Type = float; };
template <> struct BaseType<double2> { using Type = double; };
// =================================================================================================
// Returns a scalar with a default value
template <typename T> T GetScalar();
// Fixed value scalars
template <typename T> T ConstantZero();
template <typename T> T ConstantOne();
template <typename T> T ConstantNegOne();
template <typename T> T Constant(const double val);
template <typename T> T SmallConstant();
// Returns the absolute value of a scalar (modulus in case of complex numbers)
template <typename T> typename BaseType<T>::Type AbsoluteValue(const T value);
// =================================================================================================
// Structure containing all possible arguments for test clients, including their default values
template <typename T>
struct Arguments {
// Routine-specific arguments
size_t m = 1;
size_t n = 1;
size_t k = 1;
size_t ku = 1;
size_t kl = 1;
Layout layout = Layout::kRowMajor;
Transpose a_transpose = Transpose::kNo;
Transpose b_transpose = Transpose::kNo;
Side side = Side::kLeft;
Triangle triangle = Triangle::kUpper;
Diagonal diagonal = Diagonal::kUnit;
KernelMode kernel_mode = KernelMode::kCrossCorrelation;
size_t x_inc = 1;
size_t y_inc = 1;
size_t x_offset = 0;
size_t y_offset = 0;
size_t a_ld = 1;
size_t b_ld = 1;
size_t c_ld = 1;
size_t a_offset = 0;
size_t b_offset = 0;
size_t c_offset = 0;
size_t ap_offset = 0;
size_t dot_offset = 0;
size_t nrm2_offset = 0;
size_t asum_offset = 0;
size_t imax_offset = 0;
T alpha = ConstantOne<T>();
T beta = ConstantOne<T>();
// Arguments for im2col and convgemm
size_t channels = 1;
size_t height = 1;
size_t width = 1;
size_t kernel_h = 3;
size_t kernel_w = 3;
size_t pad_h = 0;
size_t pad_w = 0;
size_t stride_h = 1;
size_t stride_w = 1;
size_t dilation_h = 1;
size_t dilation_w = 1;
size_t num_kernels = 1;
// Batch-specific arguments
size_t batch_count = 1;
std::vector<size_t> x_offsets; // = {0};
std::vector<size_t> y_offsets; // = {0};
std::vector<size_t> a_offsets; // = {0};
std::vector<size_t> b_offsets; // = {0};
std::vector<size_t> c_offsets; // = {0};
std::vector<T> alphas; // = {ConstantOne<T>()};
std::vector<T> betas; // = {ConstantOne<T>()};
// Sizes
size_t x_size = 1;
size_t y_size = 1;
size_t a_size = 1;
size_t b_size = 1;
size_t c_size = 1;
size_t ap_size = 1;
size_t scalar_size = 1;
// Tuner-specific arguments
size_t heuristic_selection = 0;
double fraction = 1.0;
size_t pso_swarm_size = 8;
double pso_inf_global = 0.3;
double pso_inf_local = 0.6;
double pso_inf_random = 0.1;
double ann_max_temperature = 1.0; // Is it a valid default value?
// Client-specific arguments
int compare_clblas = 1;
int compare_cblas = 1;
int compare_cublas = 1;
size_t step = 1;
size_t num_steps = 0;
size_t num_runs = 10;
std::vector<std::string> tuner_files = {};
bool full_statistics = false;
#ifdef CLBLAST_REF_CUBLAS
void* cublas_handle; // cublasHandle_t
#endif
// Common arguments
size_t platform_id = 0;
size_t device_id = 0;
Precision precision = Precision::kSingle;
bool print_help = false;
bool silent = false;
bool no_abbrv = false;
};
// =================================================================================================
// Converts a value (e.g. an integer) to a string. This also covers special cases for CLBlast
// data-types such as the Layout and Transpose data-types.
template <typename T>
std::string ToString(T value);
// =================================================================================================
// String splitting by a delimiter
template<typename Out>
void split(const std::string &s, char delimiter, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delimiter)) {
*(result++) = item;
}
}
// See above
inline std::vector<std::string> split(const std::string &s, char delimiter) {
std::vector<std::string> elements;
split(s, delimiter, std::back_inserter(elements));
return elements;
}
// String character removal
inline void remove_character(std::string &str, char to_be_removed) {
str.erase(std::remove(str.begin(), str.end(), to_be_removed), str.end());
}
// =================================================================================================
// Parses command-line and environmental-variable arguments into a std::vector of strings
std::vector<std::string> RetrieveCommandLineArguments(int argc, char *argv[]);
// Helper for the function "GetArgument"
template <typename T>
T ConvertArgument(const char* value);
// Variant of "ConvertArgument" with default values
template <typename T>
T ConvertArgument(const char* value, T default_value);
// Basic argument parser, matching patterns in the form of "-option value" and "--option value"
template <typename T>
T GetArgument(const std::vector<std::string> &arguments, std::string &help,
const std::string &option, const T default_value);
// Returns the precision only
Precision GetPrecision(const std::vector<std::string> &arguments,
const Precision default_precision = Precision::kSingle);
// As in "GetArgument", but now only checks whether an argument is given or not
bool CheckArgument(const std::vector<std::string> &arguments, std::string &help, const std::string &option);
// =================================================================================================
// Test/example data lower and upper limit
constexpr auto kTestDataLowerLimit = -2.0;
constexpr auto kTestDataUpperLimit = 2.0;
// Populates a vector with random data
template <typename T>
void PopulateVector(std::vector<T> &vector, std::mt19937 &mt, std::uniform_real_distribution<double> &dist);
// =================================================================================================
// Converts a 'real' value to a 'real argument' value to be passed to a kernel. Normally there is
// no conversion, but half-precision is not supported as kernel argument so it is converted to float.
template <typename T> struct RealArg { using Type = T; };
template <> struct RealArg<half> { using Type = float; };
template <typename T> typename RealArg<T>::Type GetRealArg(const T value);
// =================================================================================================
// Rounding functions
size_t CeilDiv(const size_t x, const size_t y);
size_t Ceil(const size_t x, const size_t y);
// Returns whether or not 'a' is a multiple of 'b'
bool IsMultiple(const size_t a, const size_t b);
// =================================================================================================
// Convert the precision enum into bytes, e.g. a double takes up 8 bytes
size_t GetBytes(const Precision precision);
// Convert the template argument into a precision value
template <typename T>
Precision PrecisionValue();
// =================================================================================================
// Returns false is this precision is not supported by the device
template <typename T>
bool PrecisionSupported(const Device &device);
// =================================================================================================
// Retrieves the squared difference, used for example for computing the L2 error
template <typename T>
double SquaredDifference(const T val1, const T val2);
// =================================================================================================
// Device information in a specific CLBlast form
std::string GetDeviceType(const Device& device);
std::string GetDeviceVendor(const Device& device);
std::string GetDeviceArchitecture(const Device& device);
std::string GetDeviceName(const Device& device);
// =================================================================================================
void SetOpenCLKernelStandard(const Device &device, std::vector<std::string> &options);
// =================================================================================================
// Solve Bezout's identity
// a * p + b * q = r = GCD(a, b)
void EuclidGCD(int a, int b, int &p, int &q, int &r);
// =================================================================================================
} // namespace clblast
// CLBLAST_UTILITIES_H_
#endif