#include "graph/backend/dnnl/executables/gen_index.hpp"
#include "common/compiler_workarounds.hpp"
#include "common/dnnl_thread.hpp"
#include "common/stream.hpp"
namespace dnnl {
namespace impl {
namespace graph {
namespace dnnl_impl {
genindex_executable_t::genindex_executable_t(std::shared_ptr<op_t> &op,
const dnnl::engine &p_engine, pd_cache_t &pd_cache,
const fpmath_t &fpmath, bool use_block_layout)
: axis_(op->get_attr<int64_t>(op_attr::axis)) {
using ltw = logical_tensor_wrapper_t;
const auto &input_lt = op->get_input_logical_tensor(0);
nelems_ = ltw(input_lt).nelems();
ndims_ = ltw(input_lt).ndims();
const auto &output_lt = op->get_output_logical_tensor(0);
for (int i = 0; i < ndims_; i++) {
output_dims_[i] = output_lt.dims[i];
output_strides_[i] = output_lt.layout.strides[i];
}
info_ = std::string(dnnl_engine_kind2str(
static_cast<dnnl_engine_kind_t>(p_engine.get_kind())))
+ "," + op->str();
#if DNNL_GPU_RUNTIME != DNNL_RUNTIME_NONE \
&& DNNL_GPU_VENDOR == DNNL_VENDOR_INTEL
if (p_engine.get_kind() == engine::kind::gpu) {
compute::kernel_ctx_t kernel_ctx;
kernel_ctx.define_int("NDIMS", ndims_);
for (int d = 0; d < MAX_NDIMS; ++d) {
dim_t dim = (d < ndims_) ? output_dims_[d] : 1;
dim_t stride = (d < ndims_) ? output_strides_[d] : 0;
kernel_ctx.define_int(dnnl::impl::utils::format("D%d", d), dim);
kernel_ctx.define_int(dnnl::impl::utils::format("S%d", d), stride);
}
auto *intel_engine
= dnnl::impl::utils::downcast<gpu::intel::engine_t *>(
p_engine.get());
std::vector<compute::kernel_t> kernels(1);
intel_engine->create_kernels(&kernels, {"gen_index"}, kernel_ctx);
kernel_ = kernels[0];
}
#endif
}
void genindex_executable_t::execute_impl(const stream &stream,
const std::unordered_map<int, memory> &args) const {
const auto &it_dst = args.find(DNNL_ARG_DST);
if (it_dst == args.end()) return;
auto &output = it_dst->second;
auto output_ptr = static_cast<int32_t *>(output.get_data_handle());
stream.get()->before_exec_hook();
dnnl::impl::parallel_nd(nelems_, [= COMPAT_THIS_CAPTURE](dim_t i) {
dims_t input_dims; dnnl::impl::utils::l_dims_by_l_offset(
input_dims, i, output_dims_, ndims_);
auto offset
= utils::offset_compute(output_strides_, input_dims, ndims_);
output_ptr[offset] = input_dims[axis_];
});
stream.get()->after_exec_hook();
}
void genindex_executable_t::execute(const stream &stream,
const std::unordered_map<int, memory> &args) const {
if (get_verbose(dnnl::impl::verbose_t::exec_profile,
dnnl::impl::component_t::graph)) {
stream.get()->wait();
double start_ms = dnnl::impl::get_msec();
execute_impl(stream, args);
stream.get()->wait();
double duration_ms = dnnl::impl::get_msec() - start_ms;
VPROF(start_ms, graph, exec, VERBOSE_profile, info_.c_str(),
duration_ms);
} else {
execute_impl(stream, args);
}
}
#ifdef DNNL_WITH_SYCL
std::optional<::sycl::event> genindex_executable_t::execute_sycl_impl(
const stream &stream, const std::unordered_map<int, memory> &args,
const std::vector<::sycl::event> &deps) const {
if (stream.get_engine().get_kind() == engine::kind::cpu) {
auto strm_t = stream.get();
auto *sycl_stream_impl = dnnl::impl::utils::downcast<
dnnl::impl::xpu::sycl::stream_impl_t *>(strm_t->impl());
strm_t->before_exec_hook();
if (!deps.empty()) { sycl_stream_impl->sycl_ctx().set_deps(deps); }
execute(stream, args);
::sycl::event return_event = sycl_stream_impl->get_output_event();
strm_t->after_exec_hook();
return return_event;
}
#if (DNNL_GPU_RUNTIME != DNNL_RUNTIME_NONE) \
&& (DNNL_GPU_VENDOR == DNNL_VENDOR_INTEL)
auto compute_stream
= dnnl::impl::utils::downcast<gpu::intel::stream_t *>(stream.get());
compute::range_t gws = {static_cast<size_t>(nelems_)};
auto nd_range = compute::nd_range_t(gws);
compute::kernel_arg_list_t arg_list;
const auto &dst = *(args.at(DNNL_ARG_DST).get()->memory_storage());
arg_list.set(0, dst);
arg_list.set(1, axis_);
auto *sycl_stream
= dnnl::impl::utils::downcast<sycl::stream_t *>(compute_stream);
sycl_stream->before_exec_hook();
if (!deps.empty()) sycl_stream->sycl_ctx().set_deps(deps);
kernel_.parallel_for(*compute_stream, nd_range, arg_list,
sycl_stream->sycl_ctx().get_deps(),
sycl_stream->sycl_ctx().get_deps());
auto return_event = sycl_stream->get_output_event();
sycl_stream->after_exec_hook();
return return_event;
#else
assertm(false,
"genindex opexcutable is only implemented for intel vendor "
"under SYCL runtime ");
throw std::runtime_error("Unimplement");
#endif
}
std::optional<::sycl::event> genindex_executable_t::execute_sycl(
const stream &stream, const std::unordered_map<int, memory> &args,
const std::vector<::sycl::event> &deps) const {
if (get_verbose(dnnl::impl::verbose_t::exec_profile,
dnnl::impl::component_t::graph)) {
stream.get()->wait();
double start_ms = dnnl::impl::get_msec();
execute_sycl_impl(stream, args, deps);
stream.get()->wait();
double duration_ms = dnnl::impl::get_msec() - start_ms;
VPROF(start_ms, graph, exec, VERBOSE_profile, info_.c_str(),
duration_ms);
return std::nullopt; } else {
return execute_sycl_impl(stream, args, deps);
}
}
#endif
#if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
cl_event genindex_executable_t::execute_ocl_impl(const stream &stream,
const std::unordered_map<int, memory> &args,
const std::vector<cl_event> &deps) const {
#if DNNL_GPU_VENDOR == DNNL_VENDOR_INTEL
auto compute_stream
= dnnl::impl::utils::downcast<gpu::intel::stream_t *>(stream.get());
compute::range_t gws = {static_cast<size_t>(nelems_)};
auto nd_range = compute::nd_range_t(gws);
compute::kernel_arg_list_t arg_list;
const auto &dst = *(args.at(DNNL_ARG_DST).get()->memory_storage());
arg_list.set(0, dst);
arg_list.set(1, axis_);
auto *ocl_stream = dnnl::impl::utils::downcast<gpu::intel::ocl::stream_t *>(
compute_stream);
ocl_stream->before_exec_hook();
if (!deps.empty()) {
std::vector<xpu::ocl::wrapper_t<cl_event>> events(deps.size());
for (size_t i = 0; i < deps.size(); i++)
events[i] = xpu::ocl::wrapper_t<cl_event>(deps[i], true);
ocl_stream->ocl_ctx().set_deps(events);
}
kernel_.parallel_for(*compute_stream, nd_range, arg_list,
compute_stream->ctx().get_deps(), compute_stream->ctx().get_deps());
cl_event return_event = nullptr;
if ((ocl_stream->flags() & stream_flags::in_order) == 0) {
auto last = ocl_stream->get_output_event();
return_event = last.release();
}
ocl_stream->after_exec_hook();
return return_event;
#else
assertm(false,
"genindex opexcutable is only implemented for intel vendor "
"under OCL runtime ");
throw std::runtime_error("Unimplement");
#endif
}
cl_event genindex_executable_t::execute_ocl(const stream &stream,
const std::unordered_map<int, memory> &args,
const std::vector<cl_event> &deps) const {
if (get_verbose(dnnl::impl::verbose_t::exec_profile,
dnnl::impl::component_t::graph)) {
stream.get()->wait();
double start_ms = dnnl::impl::get_msec();
execute_ocl_impl(stream, args, deps);
stream.get()->wait();
double duration_ms = dnnl::impl::get_msec() - start_ms;
VPROF(start_ms, graph, exec, VERBOSE_profile, info_.c_str(),
duration_ms);
return nullptr; } else {
return execute_ocl_impl(stream, args, deps);
}
}
#endif
arg_indices_t genindex_executable_t::get_arg_indices(const op_t *op) {
UNUSED(op);
arg_indices_t args;
args.insert({DNNL_ARG_SRC, {indices_t::type_t::input, 0}});
args.insert({DNNL_ARG_DST, {indices_t::type_t::output, 0}});
return args;
}
} } } }