#include "common/engine.hpp"
#include "common/stream.hpp"
#include "xpu/stream_profiler.hpp"
#include "xpu/ocl/memory_storage.hpp"
#include "xpu/ocl/stream_impl.hpp"
namespace dnnl {
namespace impl {
namespace xpu {
namespace ocl {
status_t stream_impl_t::copy(impl::stream_t *stream,
const memory_storage_t &src, const memory_storage_t &dst, size_t size,
const xpu::event_t &deps, xpu::event_t &out_dep,
xpu::stream_profiler_t *stream_profiler) {
if (size == 0) return status::success;
std::vector<cl_event> events = [&] {
if (flags() & stream_flags::out_of_order) {
const auto &event_wrappers = xpu::ocl::event_t::from(deps).events;
return std::vector<cl_event>(
event_wrappers.begin(), event_wrappers.end());
}
return std::vector<cl_event> {};
}();
cl_uint num_events = (cl_uint)events.size();
const cl_event *events_ptr = events.data();
xpu::ocl::wrapper_t<cl_event> out_event;
bool need_out_event
= is_profiling_enabled() || flags() & stream_flags::out_of_order;
cl_event *out_event_ptr = need_out_event ? &out_event.unwrap() : nullptr;
if (dst.engine()->kind() == engine_kind::gpu
&& src.engine() == dst.engine()) {
auto *ocl_src
= utils::downcast<const xpu::ocl::memory_storage_base_t *>(
&src);
auto *ocl_dst
= utils::downcast<const xpu::ocl::memory_storage_base_t *>(
&dst);
if (ocl_src->memory_kind() == ocl_dst->memory_kind()) {
if (ocl_src->memory_kind() == xpu::ocl::memory_kind::usm
&& ocl_dst->memory_kind() == xpu::ocl::memory_kind::usm) {
const auto *ocl_usm_src = utils::downcast<
const xpu::ocl::usm_memory_storage_t *>(ocl_src);
const auto *ocl_usm_dst = utils::downcast<
const xpu::ocl::usm_memory_storage_t *>(ocl_dst);
CHECK(xpu::ocl::usm::memcpy(stream, ocl_usm_dst->usm_ptr(),
ocl_usm_src->usm_ptr(), size, num_events, events_ptr,
out_event_ptr));
}
if (ocl_src->memory_kind() == xpu::ocl::memory_kind::buffer
&& ocl_dst->memory_kind()
== xpu::ocl::memory_kind::buffer) {
const auto *ocl_buffer_src = utils::downcast<
const xpu::ocl::buffer_memory_storage_t *>(ocl_src);
const auto *ocl_buffer_dst = utils::downcast<
const xpu::ocl::buffer_memory_storage_t *>(ocl_dst);
OCL_CHECK(xpu::ocl::clEnqueueCopyBuffer(queue(),
ocl_buffer_src->mem_object(),
ocl_buffer_dst->mem_object(), src.offset(),
dst.offset(), size, num_events, events_ptr,
out_event_ptr));
}
}
} else if (src.engine()->kind() == engine_kind::cpu
&& is_native_runtime(src.engine()->runtime_kind())) {
assert(dst.engine()->kind() == engine_kind::gpu);
void *src_ptr = nullptr;
src.get_data_handle(&src_ptr);
const auto *ocl_dst
= utils::downcast<const xpu::ocl::memory_storage_base_t *>(
&dst);
bool usm_dst = ocl_dst->memory_kind() == xpu::ocl::memory_kind::usm;
if (usm_dst) {
const auto *ocl_usm_dst
= utils::downcast<const xpu::ocl::usm_memory_storage_t *>(
ocl_dst);
CHECK(xpu::ocl::usm::memcpy(stream, ocl_usm_dst->usm_ptr(), src_ptr,
size, num_events, events_ptr, out_event_ptr));
} else {
const auto *ocl_buffer_dst = utils::downcast<
const xpu::ocl::buffer_memory_storage_t *>(ocl_dst);
cl_mem ocl_mem = ocl_buffer_dst->mem_object();
cl_int err = xpu::ocl::clEnqueueWriteBuffer(queue(), ocl_mem,
CL_TRUE, 0, size, src_ptr, num_events, events_ptr,
out_event_ptr);
OCL_CHECK(err);
}
} else if (dst.engine()->kind() == engine_kind::cpu
&& is_native_runtime(dst.engine()->runtime_kind())) {
assert(src.engine()->kind() == engine_kind::gpu);
void *dst_ptr = nullptr;
dst.get_data_handle(&dst_ptr);
const auto *ocl_src
= utils::downcast<const xpu::ocl::memory_storage_base_t *>(
&src);
bool usm_src = ocl_src->memory_kind() == xpu::ocl::memory_kind::usm;
if (usm_src) {
const auto *ocl_usm_src
= utils::downcast<const xpu::ocl::usm_memory_storage_t *>(
ocl_src);
CHECK(xpu::ocl::usm::memcpy(stream, dst_ptr, ocl_usm_src->usm_ptr(),
size, num_events, events_ptr, out_event_ptr));
} else {
const auto *ocl_buffer_src = utils::downcast<
const xpu::ocl::buffer_memory_storage_t *>(ocl_src);
cl_mem ocl_mem = ocl_buffer_src->mem_object();
cl_int err = xpu::ocl::clEnqueueReadBuffer(queue(), ocl_mem,
CL_TRUE, 0, size, dst_ptr, num_events, events_ptr,
out_event_ptr);
OCL_CHECK(err);
}
} else {
CHECK(wait());
void *src_mapped_ptr;
void *dst_mapped_ptr;
auto *src_map_stream
= src.engine() == stream->engine() ? stream : nullptr;
auto *dst_map_stream
= dst.engine() == stream->engine() ? stream : nullptr;
CHECK(src.map_data(&src_mapped_ptr, src_map_stream, size));
CHECK(dst.map_data(&dst_mapped_ptr, dst_map_stream, size));
std::memcpy(static_cast<void *>(dst_mapped_ptr),
static_cast<const void *>(src_mapped_ptr), size);
CHECK(src.unmap_data(src_mapped_ptr, src_map_stream));
CHECK(dst.unmap_data(dst_mapped_ptr, dst_map_stream));
return status::success;
}
if (is_profiling_enabled()) {
auto ocl_event = utils::make_unique<xpu::ocl::event_t>(
std::vector<xpu::ocl::wrapper_t<cl_event>> {out_event});
stream_profiler->register_event(std::move(ocl_event));
}
if (flags() & stream_flags::out_of_order)
xpu::ocl::event_t::from(out_dep).events = {std::move(out_event)};
return status::success;
}
status_t stream_impl_t::fill(impl::stream_t *stream,
const memory_storage_t &dst, uint8_t pattern, size_t size,
const xpu::event_t &deps, xpu::event_t &out_dep,
xpu::stream_profiler_t *stream_profiler) {
using namespace dnnl::impl::utils;
const auto *ocl_dst
= downcast<const xpu::ocl::memory_storage_base_t *>(&dst);
std::vector<cl_event> events = [&] {
if (flags() & stream_flags::out_of_order) {
const auto &event_wrappers = xpu::ocl::event_t::from(deps).events;
return std::vector<cl_event>(
event_wrappers.begin(), event_wrappers.end());
}
return std::vector<cl_event> {};
}();
cl_uint num_events = (cl_uint)events.size();
const cl_event *events_ptr = events.data();
xpu::ocl::wrapper_t<cl_event> out_event;
bool need_out_event
= is_profiling_enabled() || flags() & stream_flags::out_of_order;
cl_event *out_event_ptr = need_out_event ? &out_event.unwrap() : nullptr;
if (ocl_dst->memory_kind() == xpu::ocl::memory_kind::usm) {
const auto *ocl_usm_dst
= downcast<const xpu::ocl::usm_memory_storage_t *>(ocl_dst);
CHECK(xpu::ocl::usm::fill(stream, ocl_usm_dst->usm_ptr(), &pattern,
sizeof(pattern), size, num_events, events_ptr, out_event_ptr));
} else {
const auto *ocl_buffer_dst
= downcast<const xpu::ocl::buffer_memory_storage_t *>(ocl_dst);
cl_int err = xpu::ocl::clEnqueueFillBuffer(queue(),
ocl_buffer_dst->mem_object(), &pattern, sizeof(uint8_t),
dst.offset(), size, num_events, events_ptr, out_event_ptr);
OCL_CHECK(err);
}
if (is_profiling_enabled()) {
auto ocl_event = utils::make_unique<xpu::ocl::event_t>(
std::vector<xpu::ocl::wrapper_t<cl_event>> {out_event});
stream_profiler->register_event(std::move(ocl_event));
}
if (flags() & stream_flags::out_of_order)
xpu::ocl::event_t::from(out_dep).events = {std::move(out_event)};
return status::success;
}
status_t stream_impl_t::barrier() {
cl_int err = xpu::ocl::clEnqueueMarkerWithWaitList(
queue(), 0, nullptr, nullptr);
OCL_CHECK(err);
return status::success;
}
const xpu::ocl::context_t &stream_impl_t::ocl_ctx() const {
static xpu::ocl::context_t empty_ctx {};
return ctx_.get(empty_ctx);
}
xpu::ocl::context_t &stream_impl_t::ocl_ctx() {
const xpu::ocl::context_t &ctx
= const_cast<const stream_impl_t *>(this)->ocl_ctx();
return *const_cast<xpu::ocl::context_t *>(&ctx);
}
xpu::context_t &stream_impl_t::ctx() {
return ocl_ctx();
}
const xpu::context_t &stream_impl_t::ctx() const {
return ocl_ctx();
}
const xpu::ocl::wrapper_t<cl_event> &stream_impl_t::get_output_event() const {
auto &deps = xpu::ocl::event_t::from(ctx().get_deps());
assert(deps.size() == 1);
return deps[0];
}
} } } }