#include "gpu/intel/conv/jit/model_bridge.hpp"
#include <mutex>
#include "gpu/intel/conv/jit/config.hpp"
#include "gpu/intel/conv/jit/model.hpp"
#include "gpu/intel/conv/jit/model_data.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace conv {
namespace jit {
namespace model {
type_t to_type(data_type_t dt) {
switch (static_cast<int>(dt)) {
case data_type::s8:
case data_type::f4_e2m1:
case data_type::f4_e3m0:
case data_type::f8_e5m2:
case data_type::f8_e4m3:
case data_type::u8: return type_t::d8;
case data_type::f16:
case data_type::bf16: return type_t::d16;
case data_type::tf32:
case data_type::f32:
case data_type::s32: return type_t::d32;
case data_type::f64: return type_t::d64;
default: gpu_error_not_expected() << "Unknown type: " << dt;
}
return type_t::undef;
}
hw_t to_hw(ngen::HW hw) {
using intel::jit::to_string;
switch (hw) {
case ngen::HW::XeLP:
case ngen::HW::XeHP:
case ngen::HW::XeHPG: return hw_t::xehpg;
case ngen::HW::XeHPC: return hw_t::xehpc;
case ngen::HW::Xe2: return hw_t::xehpc;
case ngen::HW::Xe3: return hw_t::xehpc;
case ngen::HW::XE3P_35_10:
case ngen::HW::XE3P_35_11:
case ngen::HW::XE3P_UNKNOWN: return hw_t::xehpc;
default: gpu_error_not_expected() << "Unknown HW: " << to_string(hw);
}
return hw_t::undef;
}
fma_t to_fma(fma_kind_t fma) {
switch (fma) {
case fma_kind_t::mad: return fma_t::mad;
case fma_kind_t::dp4a:
case fma_kind_t::dpas:
case fma_kind_t::dpasw: return fma_t::dpas;
default:
gpu_error_not_expected() << "Unknown FMA kind: " << to_string(fma);
}
return fma_t::undef;
}
hw_config_t to_hw_config(const config_t &cfg) {
auto &prb = cfg.prb();
auto &hw = cfg.hw();
return hw_config_t(to_hw(hw), to_fma(cfg.fma_kind()),
to_type(prb.a_data_type), hw.eu_count());
}
conv_sample_t to_sample(const config_t &cfg, const blocking_params_t ¶ms) {
auto &prb = cfg.prb();
conv_sample_t ret;
ret.prop = (prb.is_fwd ? prop_t::fwd
: (prb.is_bwd_d ? prop_t::bwd_d : prop_t::bwd_w));
ret.src_type = to_type(prb.a_data_type);
ret.dst_type = to_type(prb.c_data_type);
ret.hw_cfg = to_hw_config(cfg);
ret.transpose = prb.ab_swap_transpose;
auto &blk = params.blocking();
auto shape = cfg.shape(false);
#define HANDLE(name) \
do { \
ret.shape.name = -1; \
ret.loop.name = -1; \
ret.tg.name = -1; \
ret.iter.name = -1; \
if (!shape.has(pvars::name)) break; \
ret.shape.name = shape.get(pvars::name); \
ret.loop.name = blk.loop().get(pvars::name, 1); \
ret.tg.name = blk.thread_group().get(pvars::name, 1); \
ret.iter.name = blk.iter().get(pvars::name, 1); \
} while (false)
HANDLE(g);
HANDLE(mb);
HANDLE(oc);
HANDLE(ic);
HANDLE(id);
HANDLE(ih);
HANDLE(iw);
HANDLE(od);
HANDLE(oh);
HANDLE(ow);
HANDLE(kd);
HANDLE(kh);
HANDLE(kw);
#undef HANDLE
ret.pad();
return ret;
}
conv_sample_t fixup(const conv_sample_t &sample) {
auto ret = sample;
if (sample.prop == prop_t::bwd_w && sample.dst_type < type_t::d32)
ret.dst_type = type_t::d32;
if (sample.prop == prop_t::fwd && sample.src_type == type_t::d8)
ret.dst_type = type_t::d8;
return ret;
}
enum class gbr_kind_t {
all_common,
xehpc_common,
xehpc_dw,
xehpg_common,
xehpg_dw,
_max
};
using gbr_kind_hash_t = ir_utils::enum_hash_t<gbr_kind_t>;
gbr_kind_t get_gbr_kind(const config_t &cfg) {
auto &prb = cfg.prb();
if (cfg.hw() >= ngen::HW::XeHPC) {
if (prb.is_dw) return gbr_kind_t::xehpc_dw;
return gbr_kind_t::xehpc_common;
}
if (prb.is_dw) return gbr_kind_t::xehpg_dw;
return gbr_kind_t::xehpg_common;
}
inline bool is_big_endian() {
uint32_t u = 0x01020304;
uint8_t a[4] = {};
std::memcpy(a, &u, sizeof(u));
return a[0] == 0x01;
}
std::vector<uint8_t> unpack_data(const std::vector<uint64_t> &data_u64) {
size_t size = data_u64.size() * sizeof(data_u64[0]);
std::vector<uint8_t> data_u8(size);
std::memcpy(data_u8.data(), data_u64.data(), size);
if (is_big_endian()) {
size_t elem_len = sizeof(data_u64[0]);
for (size_t i = 0; i < size; i += elem_len) {
for (size_t j = 0; j < elem_len / 2; j++) {
std::swap(data_u8[i + j], data_u8[i + elem_len - j]);
}
}
}
return data_u8;
}
gradient_boost_regressor_t &get_gbr(const config_t &cfg) {
static const std::unordered_map<gbr_kind_t,
const std::vector<uint64_t> *, gbr_kind_hash_t>
kind2data = {
{gbr_kind_t::xehpc_common, &get_model_xehpc_common_data()},
{gbr_kind_t::xehpg_common, &get_model_xehpg_common_data()},
{gbr_kind_t::xehpc_dw, &get_model_xehpc_dw_data()},
{gbr_kind_t::xehpg_dw, &get_model_xehpg_dw_data()}
};
static std::unordered_map<gbr_kind_t, gradient_boost_regressor_t,
gbr_kind_hash_t>
gbr_map;
static std::once_flag flag;
std::call_once(flag, [&] {
for (auto &kv : kind2data) {
auto kind = kv.first;
auto &data = *kv.second;
auto s = serialization_stream_t::from_data(unpack_data(data));
deserializer_t d(s);
gbr_map[kind] = gradient_boost_regressor_t::deserialize(d);
}
});
auto kind = get_gbr_kind(cfg);
return gbr_map.at(kind);
}
float get_score(const config_t &cfg, const blocking_params_t ¶ms) {
auto sample = to_sample(cfg, params);
sample = fixup(sample);
auto bmnk_sample = sample.to_bmnk_conv_sample();
return get_gbr(cfg).predict(bmnk_sample.to_x());
}
} } } } } } }