#ifndef GPU_INTEL_UTILS_HPP
#define GPU_INTEL_UTILS_HPP
#include <iostream>
#include "common/cpp_compat.hpp"
#include "common/utils.hpp"
#include "gpu/intel/compute/device_info.hpp"
#define VCHECK_KERNEL(stat, msg, ...) \
VCHECK(common, create, check, runtime, stat, msg, ##__VA_ARGS__);
#if defined(__GNUC__)
#define XE_DEFINE_DUMP() \
__attribute__((noinline)) \
__attribute__((used)) \
void dump() const { \
printf("%s\n", str().c_str()); \
}
#else
#define XE_DEFINE_DUMP()
#endif
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
enum { OCL_BUFFER_ALIGNMENT = 128 };
const char *get_kernel_header(const std::string &name);
const char *get_kernel_source(const char *name);
#define MAX_NDIMS 6
#define MAX_POST_OPS_SUPPORTED 32
using dim_idx_t = uint32_t;
namespace dim_idx {
constexpr dim_idx_t invalid = static_cast<dim_idx_t>(-1);
inline char as_tag(dim_idx_t idx, bool is_outer = false) {
return (is_outer ? 'A' : 'a') + static_cast<char>(idx);
}
}
namespace gpu_utils {
class error_stream_t {
public:
error_stream_t(const char *file, int line, const char *assert_msg) {
out_ << "Assertion " << assert_msg << " failed at " << file << ":"
<< line << std::endl;
}
operator bool() const { return true; }
template <typename T>
error_stream_t &operator<<(const T &t) {
out_ << t;
return *this;
}
~error_stream_t() noexcept(false) {
if (cpp_compat::uncaught_exceptions()) return;
std::cout << out_.str() << std::endl;
#ifdef GPU_ABORT_ON_ERROR
std::abort();
#else
throw std::runtime_error(out_.str());
#endif
}
private:
ostringstream_t out_;
};
#if !defined(NDEBUG) || defined(DNNL_DEV_MODE)
#define gpu_assert(cond) \
!(cond) \
&& dnnl::impl::gpu::intel::gpu_utils::error_stream_t( \
__FILE__, __LINE__, #cond)
#else
#define gpu_assert(cond) \
(false) && !(cond) \
&& dnnl::impl::gpu::intel::gpu_utils::error_stream_t( \
__FILE__, __LINE__, #cond)
#endif
#define gpu_error_not_expected() gpu_assert(false) << "Not expected. "
#define gpu_except_not_implemented(msg) \
throw std::runtime_error(std::string(msg) + std::string(" at ") \
+ std::string(__FILENAME__) + std::string(":") \
+ std::to_string(__LINE__))
template <typename out_type, typename in_type,
typename std::enable_if<!std::is_fundamental<out_type>::value
|| !std::is_fundamental<in_type>::value>::type>
inline bool validate_into(in_type in) {
return true;
}
template <typename out_type, typename in_type,
typename std::enable_if<std::is_fundamental<out_type>::value
&& std::is_fundamental<in_type>::value>::type>
inline bool validate_into(in_type in) {
const double in_compare = static_cast<double>(in);
const double out_max
= static_cast<double>(std::numeric_limits<out_type>::max());
const double out_lowest
= static_cast<double>(std::numeric_limits<out_type>::lowest());
return in_compare <= out_max && in_compare >= out_lowest;
}
template <typename out_type>
inline bool validate_into(bool b) {
return std::is_integral<out_type>::value;
}
inline int dev_getenv(const char *name, int default_value) {
#ifdef DNNL_DEV_MODE
return getenv_int(name, default_value);
#else
return default_value;
#endif
}
inline bool dev_getenv(const char *s, bool def) {
return dev_getenv(s, def ? 1 : 0) != 0;
}
inline std::string dev_getenv(const char *s, const std::string &def) {
#ifdef DNNL_DEV_MODE
char buf[1024];
int ret = getenv(s, buf, sizeof(buf));
if (ret > 0) return buf;
return def;
#else
return def;
#endif
}
inline compute::gpu_arch_t dev_getenv(const char *s, compute::gpu_arch_t arch,
int *eu_count = nullptr, int *max_wg_size = nullptr) {
#ifdef DNNL_DEV_MODE
char buf[1024];
int ret = getenv(s, buf, sizeof(buf));
if (ret > 0) {
char *arch_str = buf, *eu_str = nullptr;
for (int i = 0; i < ret; i++) {
if (buf[i] == ',') {
buf[i] = 0;
if (i < ret - 1) { eu_str = &buf[i + 1]; }
break;
}
}
arch = compute::str2gpu_arch(arch_str);
if (eu_count && eu_str) { *eu_count = atoi(eu_str); }
if (max_wg_size) {
const int max_eus_per_wg
= compute::device_info_t::max_eus_per_wg(arch);
const int simd_size = 16;
const int thr_per_eu = utils::rnd_down_pow2(
compute::device_info_t::threads_per_eu(arch));
*max_wg_size = simd_size * max_eus_per_wg * thr_per_eu;
}
}
return arch;
#else
return arch;
#endif
}
inline bool to_bool(const std::string &s) {
if (s == "0" || s == "false") return false;
return true;
}
inline std::vector<std::string> split(const std::string &s,
const std::string &delimiter = std::string(1, ' ')) {
size_t beg = 0;
size_t end = 0;
std::vector<std::string> ret;
do {
end = s.find(delimiter, beg);
size_t len
= (end == std::string::npos) ? std::string::npos : (end - beg);
ret.push_back(s.substr(beg, len));
beg = end + delimiter.size();
} while (end != std::string::npos);
return ret;
}
inline std::string join(
const std::string &delimiter, const std::vector<std::string> &parts) {
ostringstream_t oss;
bool is_first = true;
for (auto &p : parts) {
if (!is_first) oss << delimiter;
oss << p;
is_first = false;
}
return oss.str();
}
bool is_jit_dump_enabled();
status_t dump_kernel_binary(
const std::vector<uint8_t> &binary, const std::string &name);
using device_id_t = std::tuple<int, uint64_t, uint64_t>;
struct device_id_hash_t {
size_t operator()(const device_id_t &id) const {
size_t result = 0;
result = hash_combine(result, std::get<0>(id));
result = hash_combine(result, std::get<1>(id));
result = hash_combine(result, std::get<2>(id));
return result;
}
};
}
template <typename out_type, typename in_type>
inline out_type into(in_type in) {
gpu_assert(gpu_utils::validate_into<out_type>(in))
<< "Value " << in << " cannot be converted into type "
<< typeid(out_type).name();
return static_cast<out_type>(in);
}
} } } } #endif