#include "gpu/intel/primitive_attr.hpp"
#ifdef DNNL_DEV_MODE
#include "common/c_types_map.hpp"
#include "common/utils.hpp"
#include "gpu/intel/compute/device_info.hpp"
#include "gpu/intel/compute/utils.hpp"
#include "gpu/intel/engine.hpp"
#include "gpu/intel/reduction/jit.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace reduction {
using namespace gpu_utils;
status_t gen_t::pd_t::init_conf(impl::engine_t *engine) {
const memory_desc_wrapper src_mdw(src_md());
const memory_desc_wrapper dst_mdw(dst_md());
const int ndims = src_mdw.ndims();
const dim_t *src_dims = src_mdw.dims();
const dim_t *dst_dims = dst_mdw.dims();
bool plain_case = true;
plain_case &= (src_mdw.blocking_desc().inner_nblks == 0);
plain_case &= (dst_mdw.blocking_desc().inner_nblks == 0);
VDISPATCH_REDUCTION_IC(plain_case, VERBOSE_UNSUPPORTED_FORMAT_KIND);
for (int i = 0; i < ndims; i++) {
bool is_reduced = (src_dims[i] != dst_dims[i]);
VDISPATCH_REDUCTION_IC(!(is_reduced && reduction_size),
VERBOSE_INCONSISTENT_DIM, "src", i, "dst", i);
if (is_reduced) {
reduction_size = src_dims[i];
reduction_stride = src_mdw.blocking_desc().strides[i];
}
}
assert(reduction_size);
assert(reduction_stride);
dim_t dst_nelems = dst_mdw.nelems();
dim_t inner_nelems = reduction_stride;
int dt_size = into<int>(sizeof(float));
auto &intel_engine = *utils::downcast<intel::engine_t *>(engine);
const compute::device_info_t &device_info = *intel_engine.device_info();
int reg_size = device_info.grf_size();
int elems_per_reg = reg_size / dt_size;
int default_nregs
= utils::max_div(into<int>(inner_nelems / elems_per_reg), 16);
nregs = dev_getenv("jit_reduction_nregs", into<int>(default_nregs));
VDISPATCH_REDUCTION_IC(inner_nelems % (elems_per_reg * nregs) == 0,
"register size mismatch");
dim_t gws0 = inner_nelems / nregs;
dim_t nthreads = gws0 / elems_per_reg;
int tg_size = [this, &device_info, &nthreads]() {
const compute::gpu_arch_t arch = device_info.gpu_arch();
auto *gpu_attr = utils::downcast<gpu_primitive_attr_t *>(
attr()->gpu_attr_.get());
const int threads_per_eu = gpu_attr
? gpu_attr->threads_per_eu()
: compute::device_info_t::threads_per_eu(arch);
int tg_size = utils::rnd_down_pow2(
device_info.max_eus_per_wg() * threads_per_eu);
while (nthreads % tg_size != 0) {
tg_size /= 2;
}
tg_size = dev_getenv("jit_reduction_tg_size", tg_size);
return tg_size;
}();
gpu_assert(nthreads % tg_size == 0) << "Invalid tg_size";
dim_t outer_nelems = dst_nelems / inner_nelems;
compute::range_t gws(into<size_t>(gws0), into<size_t>(outer_nelems));
compute::range_t lws(into<size_t>(tg_size * elems_per_reg), 1);
nd_range = compute::nd_range_t(gws, lws);
return status::success;
}
status_t gen_t::execute(const exec_ctx_t &ctx) const {
auto &src = CTX_IN_STORAGE(DNNL_ARG_SRC);
auto &dst = CTX_OUT_STORAGE(DNNL_ARG_DST);
compute::kernel_arg_list_t reduction_arg_list;
reduction_arg_list.append(src);
reduction_arg_list.append(dst);
CHECK(parallel_for(ctx, pd()->nd_range, kernel_, reduction_arg_list));
return status::success;
}
} } } } }
#endif