#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "oneapi/dnnl/dnnl.h"
#ifdef DNNL_WITH_SYCL
#include "oneapi/dnnl/dnnl_sycl.h"
#endif
#include "c_types_map.hpp"
#include "engine.hpp"
#include "host_scalar_memory_storage.hpp"
#include "memory.hpp"
#include "memory_desc_wrapper.hpp"
#include "stream.hpp"
#include "type_helpers.hpp"
#include "utils.hpp"
using namespace dnnl::impl;
using namespace dnnl::impl::utils;
using namespace dnnl::impl::status;
using namespace dnnl::impl::data_type;
namespace dnnl {
namespace impl {
memory_desc_t glob_zero_md = memory_desc_t();
}
}
namespace {
size_t memory_desc_map_size(const memory_desc_t *md, int index = 0) {
auto mdw = memory_desc_wrapper(md);
if (mdw.has_runtime_dims_or_strides()) return runtime_value_for<size_t>();
return mdw.size(index, true, true);
}
}
dnnl_memory::dnnl_memory(dnnl::impl::engine_t *engine,
const dnnl::impl::memory_desc_t *md, const std::vector<unsigned> &flags,
const std::vector<void *> &handles)
: engine_(engine), md_(*md), counter_(1) {
const size_t nhandles = handles.size();
std::vector<std::unique_ptr<dnnl::impl::memory_storage_t>> mem_storages(
nhandles);
for (size_t i = 0; i < nhandles; i++) {
const size_t size = memory_desc_wrapper(md_).size((int)i);
memory_storage_t *memory_storage_ptr;
status_t status = engine->create_memory_storage(
&memory_storage_ptr, flags[i], size, handles[i]);
if (status != success) return;
mem_storages[i].reset(memory_storage_ptr);
}
memory_storages_ = std::move(mem_storages);
}
dnnl_memory::dnnl_memory(dnnl::impl::engine_t *engine,
const dnnl::impl::memory_desc_t *md,
std::unique_ptr<dnnl::impl::memory_storage_t> &&memory_storage)
: engine_(engine), md_(*md), counter_(1) {
this->reset_memory_storage(std::move(memory_storage));
}
dnnl_memory::dnnl_memory(dnnl::impl::engine_t *engine,
const dnnl::impl::memory_desc_t *md,
std::vector<std::unique_ptr<dnnl::impl::memory_storage_t>>
&&memory_storages)
: engine_(engine)
, md_(*md)
, memory_storages_(std::move(memory_storages))
, counter_(1) {}
status_t dnnl_memory::set_data_handle(void *handle, int index) const {
using namespace dnnl::impl;
void *old_handle;
auto *ms = memory_storage(index);
if (!ms) return status::invalid_arguments;
CHECK(ms->get_data_handle(&old_handle));
if (handle != old_handle) {
CHECK(memory_storage(index)->set_data_handle(handle));
}
return status::success;
}
status_t dnnl_memory::reset_memory_storage(
std::unique_ptr<dnnl::impl::memory_storage_t> &&memory_storage) {
if (memory_storage) {
if (memory_storages_.empty())
memory_storages_.emplace_back(std::move(memory_storage));
else
memory_storages_[0] = std::move(memory_storage);
} else {
memory_storage_t *memory_storage_ptr;
status_t status = engine_->create_memory_storage(
&memory_storage_ptr, use_runtime_ptr, 0, nullptr);
if (status != status::success) return status;
if (memory_storages_.empty())
memory_storages_.emplace_back(memory_storage_ptr);
else
memory_storages_[0].reset(memory_storage_ptr);
}
return status::success;
}
status_t dnnl_memory_create(memory_t **memory, const memory_desc_t *md,
engine_t *engine, void *handle) {
#ifdef DNNL_WITH_SYCL
#if DNNL_CPU_RUNTIME != DNNL_RUNTIME_SYCL
if (engine->kind() == engine_kind::gpu)
#endif
return dnnl_sycl_interop_memory_create(
memory, md, engine, dnnl_sycl_interop_usm, handle);
#endif
if (any_null(memory, engine)) return invalid_arguments;
memory_desc_t z_md = types::zero_md();
if (md == nullptr) md = &z_md;
const auto mdw = memory_desc_wrapper(md);
VCHECK_MEMORY(
!mdw.format_any(), invalid_arguments, VERBOSE_UNSUPPORTED_TAG);
VCHECK_MEMORY(!mdw.has_runtime_dims_or_strides(), invalid_arguments,
VERBOSE_UNSUPPORTED_MEM_STRIDE);
VCHECK_MEMORY(!mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
unsigned flags = (handle == DNNL_MEMORY_ALLOCATE)
? memory_flags_t::alloc
: memory_flags_t::use_runtime_ptr;
void *handle_ptr = (handle == DNNL_MEMORY_ALLOCATE) ? nullptr : handle;
auto _memory = new memory_t(engine, md, flags, handle_ptr);
if (_memory == nullptr) return out_of_memory;
if (_memory->memory_storage() == nullptr) {
_memory->release();
return out_of_memory;
}
*memory = _memory;
return success;
}
status_t dnnl_memory_create_v2(memory_t **memory, const memory_desc_t *md,
engine_t *engine, int nhandles, void **handles) {
const bool args_ok = !any_null(memory, engine, handles) && nhandles > 0;
if (!args_ok) return invalid_arguments;
#ifdef DNNL_WITH_SYCL
#if DNNL_CPU_RUNTIME != DNNL_RUNTIME_SYCL
if (engine->kind() == engine_kind::gpu)
#endif
return dnnl_sycl_interop_memory_create_v2(
memory, md, engine, dnnl_sycl_interop_usm, nhandles, handles);
#endif
memory_desc_t z_md = types::zero_md();
if (md == nullptr) md = &z_md;
const auto mdw = memory_desc_wrapper(md);
VCHECK_MEMORY(
!mdw.format_any(), invalid_arguments, VERBOSE_UNSUPPORTED_TAG);
VCHECK_MEMORY(!mdw.has_runtime_dims_or_strides(), invalid_arguments,
VERBOSE_UNSUPPORTED_MEM_STRIDE);
VCHECK_MEMORY(!mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
std::vector<unsigned> flags_vec(nhandles);
std::vector<void *> handles_vec(nhandles);
for (size_t i = 0; i < handles_vec.size(); i++) {
unsigned f = (handles[i] == DNNL_MEMORY_ALLOCATE)
? memory_flags_t::alloc
: memory_flags_t::use_runtime_ptr;
void *h = (handles[i] == DNNL_MEMORY_ALLOCATE) ? nullptr : handles[i];
flags_vec[i] = f;
handles_vec[i] = h;
}
auto _memory = new memory_t(engine, md, flags_vec, handles_vec);
if (_memory == nullptr) return out_of_memory;
for (size_t i = 0; i < handles_vec.size(); i++) {
if (_memory->memory_storage((int)i) == nullptr) {
_memory->release();
return out_of_memory;
}
}
*memory = _memory;
return success;
}
status_t dnnl_memory_create_host_scalar(
memory_t **memory, const memory_desc_t *md, void *scalar_ptr) {
if (any_null(memory, scalar_ptr, md)) return invalid_arguments;
const auto mdw = memory_desc_wrapper(md);
VCHECK_MEMORY(mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
std::unique_ptr<dnnl::impl::host_scalar_memory_storage_t>
memory_storage_ptr(new dnnl::impl::host_scalar_memory_storage_t());
memory_storage_ptr->set_scalar_value(scalar_ptr, mdw.data_type());
memory_t *mem_obj
= new memory_t(nullptr, md, std::move(memory_storage_ptr));
if (mem_obj == nullptr) return out_of_memory;
if (mem_obj->memory_storage() == nullptr) {
mem_obj->release();
return out_of_memory;
}
*memory = mem_obj;
return success;
}
status_t dnnl_memory_get_memory_desc(
const memory_t *memory, const memory_desc_t **md) {
if (any_null(memory, md)) return invalid_arguments;
*md = memory->md();
return success;
}
status_t dnnl_memory_get_engine(const memory_t *memory, engine_t **engine) {
if (any_null(memory, engine)) return invalid_arguments;
*engine = memory->engine();
return success;
}
status_t dnnl_memory_get_data_handle(const memory_t *memory, void **handle) {
if (any_null(handle)) return invalid_arguments;
if (memory == nullptr) {
*handle = nullptr;
return success;
}
const auto mdw = memory_desc_wrapper(memory->md());
if (mdw.is_host_scalar_desc()) return invalid_arguments;
return memory->get_data_handle(handle);
}
status_t dnnl_memory_set_data_handle(memory_t *memory, void *handle) {
if (any_null(memory)) return invalid_arguments;
const auto mdw = memory_desc_wrapper(memory->md());
VCHECK_MEMORY(!mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
CHECK(memory->set_data_handle(handle));
return status::success;
}
status_t dnnl_memory_get_data_handle_v2(
const memory_t *memory, void **handle, int index) {
if (any_null(handle)) return invalid_arguments;
if (memory == nullptr) {
*handle = nullptr;
return success;
}
const auto mdw = memory_desc_wrapper(memory->md());
if (mdw.is_host_scalar_desc()) return invalid_arguments;
return memory->get_data_handle(handle, index);
}
status_t dnnl_memory_set_data_handle_v2(
memory_t *memory, void *handle, int index) {
if (any_null(memory)) return invalid_arguments;
const auto mdw = memory_desc_wrapper(memory->md());
VCHECK_MEMORY(!mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
CHECK(memory->set_data_handle(handle, index));
return status::success;
}
status_t dnnl_memory_get_host_scalar_value(
const memory_t *memory, void *value) {
if (any_null(memory, value)) return invalid_arguments;
const auto mdw = memory_desc_wrapper(memory->md());
VCHECK_MEMORY(mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
auto *scalar_storage
= utils::downcast<dnnl::impl::host_scalar_memory_storage_t *>(
memory->memory_storage(0));
if (!scalar_storage) return invalid_arguments;
return scalar_storage->get_scalar_value(value, mdw.data_type_size());
}
status_t dnnl_memory_set_host_scalar_value(
memory_t *memory, const void *value) {
if (any_null(memory, value)) return invalid_arguments;
const auto mdw = memory_desc_wrapper(memory->md());
VCHECK_MEMORY(mdw.is_host_scalar_desc(), invalid_arguments,
VERBOSE_UNSUPPORTED_FORMAT_KIND);
auto *scalar_storage
= utils::downcast<dnnl::impl::host_scalar_memory_storage_t *>(
memory->memory_storage(0));
if (!scalar_storage) return invalid_arguments;
scalar_storage->set_scalar_value(value, mdw.data_type());
return success;
}
status_t dnnl_memory_map_data_v2(
const memory_t *memory, void **mapped_ptr, int index) {
VCHECK_MEMORY(
!any_null(memory, mapped_ptr), invalid_arguments, VERBOSE_NULL_ARG);
VCHECK_MEMORY((index >= 0 && index < (int)memory->get_num_handles()),
invalid_arguments, VERBOSE_INVALID_MEM_IDX);
const memory_desc_t *md = memory->md();
const size_t map_size = memory_desc_map_size(md, index);
if (map_size == 0) {
*mapped_ptr = nullptr;
return success;
} else if (is_runtime_value(map_size)) {
return invalid_arguments;
}
return memory->memory_storage(index)->map_data(
mapped_ptr, nullptr, map_size);
}
status_t dnnl_memory_unmap_data_v2(
const memory_t *memory, void *mapped_ptr, int index) {
VCHECK_MEMORY(!any_null(memory), invalid_arguments, VERBOSE_NULL_ARG);
VCHECK_MEMORY((index >= 0 && index < (int)memory->get_num_handles()),
invalid_arguments, VERBOSE_INVALID_MEM_IDX);
return memory->memory_storage(index)->unmap_data(mapped_ptr, nullptr);
}
status_t dnnl_memory_map_data(const memory_t *memory, void **mapped_ptr) {
return dnnl_memory_map_data_v2(memory, mapped_ptr, 0);
}
status_t dnnl_memory_unmap_data(const memory_t *memory, void *mapped_ptr) {
return dnnl_memory_unmap_data_v2(memory, mapped_ptr, 0);
}
status_t dnnl_memory_destroy(memory_t *memory) {
if (memory != nullptr) memory->release();
return success;
}