1/*******************************************************************************
2* Copyright 2019-2022 Intel Corporation
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*******************************************************************************/
16
17#include "dnnl_test_common.hpp"
18#include "gtest/gtest.h"
19
20#include "oneapi/dnnl/dnnl.h"
21
22#include <algorithm>
23#include <memory>
24#include <sstream>
25#include <vector>
26
27namespace dnnl {
28
29namespace {
30bool is_sycl_engine(dnnl_engine_kind_t eng_kind) {
31#if DNNL_CPU_RUNTIME == DNNL_RUNTIME_SYCL
32 if (eng_kind == dnnl_cpu) return true;
33#endif
34
35#if DNNL_GPU_RUNTIME == DNNL_RUNTIME_SYCL
36 if (eng_kind == dnnl_gpu) return true;
37#endif
38 return false;
39}
40} // namespace
41
42class memory_map_test_c_t
43 : public ::testing::TestWithParam<dnnl_engine_kind_t> {
44protected:
45 void SetUp() override {
46 eng_kind = GetParam();
47 if (dnnl_engine_get_count(eng_kind) == 0) return;
48
49 DNNL_CHECK(dnnl_engine_create(&engine, eng_kind, 0));
50 DNNL_CHECK(
51 dnnl_stream_create(&stream, engine, dnnl_stream_default_flags));
52 }
53
54 void TearDown() override {
55 if (engine) { DNNL_CHECK(dnnl_engine_destroy(engine)); }
56 if (stream) { DNNL_CHECK(dnnl_stream_destroy(stream)); }
57 }
58
59 dnnl_engine_kind_t eng_kind;
60 dnnl_engine_t engine = nullptr;
61 dnnl_stream_t stream = nullptr;
62};
63
64class memory_map_test_cpp_t
65 : public ::testing::TestWithParam<dnnl_engine_kind_t> {};
66
67TEST_P(memory_map_test_c_t, MapNullMemory) {
68 SKIP_IF(!engine, "Engine kind is not supported.");
69 SKIP_IF(is_sycl_engine(eng_kind), "Do not test C API with SYCL.");
70
71 int ndims = 4;
72 dnnl_dims_t dims = {2, 3, 4, 5};
73 dnnl_memory_desc_t mem_d;
74 dnnl_memory_t mem;
75
76 DNNL_CHECK(dnnl_memory_desc_create_with_tag(
77 &mem_d, ndims, dims, dnnl_f32, dnnl_nchw));
78 DNNL_CHECK(dnnl_memory_create(&mem, mem_d, engine, nullptr));
79 DNNL_CHECK(dnnl_memory_desc_destroy(mem_d));
80
81 void *mapped_ptr;
82 DNNL_CHECK(dnnl_memory_map_data(mem, &mapped_ptr));
83 ASSERT_EQ(mapped_ptr, nullptr);
84
85 DNNL_CHECK(dnnl_memory_unmap_data(mem, mapped_ptr));
86 DNNL_CHECK(dnnl_memory_destroy(mem));
87}
88
89HANDLE_EXCEPTIONS_FOR_TEST_P(memory_map_test_c_t, Map) {
90 SKIP_IF(!engine, "Engine kind is not supported.");
91 SKIP_IF(is_sycl_engine(eng_kind), "Do not test C API with SYCL.");
92
93 const int ndims = 1;
94 const dnnl_dim_t N = 15;
95 const dnnl_dims_t dims = {N};
96
97 dnnl_memory_desc_t mem_d;
98 DNNL_CHECK(dnnl_memory_desc_create_with_tag(
99 &mem_d, ndims, dims, dnnl_f32, dnnl_x));
100
101 // Create and fill mem_ref to use as a reference
102 dnnl_memory_t mem_ref;
103 DNNL_CHECK(
104 dnnl_memory_create(&mem_ref, mem_d, engine, DNNL_MEMORY_ALLOCATE));
105
106 float buffer_ref[N];
107 std::iota(buffer_ref, buffer_ref + N, 1);
108
109 void *mapped_ptr_ref = nullptr;
110 DNNL_CHECK(dnnl_memory_map_data(mem_ref, &mapped_ptr_ref));
111 float *mapped_ptr_ref_f32 = static_cast<float *>(mapped_ptr_ref);
112 GTEST_EXPECT_NE(mapped_ptr_ref_f32, nullptr);
113 std::copy(buffer_ref, buffer_ref + N, mapped_ptr_ref_f32);
114 DNNL_CHECK(dnnl_memory_unmap_data(mem_ref, mapped_ptr_ref));
115
116 // Create memory for the tested engine
117 dnnl_memory_t mem;
118 DNNL_CHECK(dnnl_memory_create(&mem, mem_d, engine, DNNL_MEMORY_ALLOCATE));
119
120 // Reorder mem_ref to memory
121 dnnl_primitive_desc_t reorder_pd;
122 DNNL_CHECK(dnnl_reorder_primitive_desc_create(
123 &reorder_pd, mem_d, engine, mem_d, engine, nullptr));
124
125 dnnl_primitive_t reorder;
126 DNNL_CHECK(dnnl_primitive_create(&reorder, reorder_pd));
127
128 dnnl_exec_arg_t reorder_args[2]
129 = {{DNNL_ARG_SRC, mem_ref}, {DNNL_ARG_DST, mem}};
130 DNNL_CHECK(dnnl_primitive_execute(reorder, stream, 2, reorder_args));
131 DNNL_CHECK(dnnl_stream_wait(stream));
132
133 // Validate the results
134 void *mapped_ptr = nullptr;
135 DNNL_CHECK(dnnl_memory_map_data(mem, &mapped_ptr));
136 float *mapped_ptr_f32 = static_cast<float *>(mapped_ptr);
137 GTEST_EXPECT_NE(mapped_ptr_f32, nullptr);
138 for (size_t i = 0; i < N; i++) {
139 ASSERT_EQ(mapped_ptr_f32[i], buffer_ref[i]);
140 }
141 DNNL_CHECK(dnnl_memory_unmap_data(mem, mapped_ptr));
142
143 // Clean up
144 DNNL_CHECK(dnnl_primitive_destroy(reorder));
145 DNNL_CHECK(dnnl_primitive_desc_destroy(reorder_pd));
146
147 DNNL_CHECK(dnnl_memory_desc_destroy(mem_d));
148 DNNL_CHECK(dnnl_memory_destroy(mem));
149 DNNL_CHECK(dnnl_memory_destroy(mem_ref));
150}
151
152HANDLE_EXCEPTIONS_FOR_TEST_P(memory_map_test_cpp_t, Map) {
153
154#ifdef DNNL_SYCL_HIP
155 SKIP_IF(true,
156 "memory_map_test_cpp_t.Mapgpu is skipped for HIP because of "
157 "unimplemented Reorder");
158#endif
159
160 auto engine_kind = static_cast<engine::kind>(GetParam());
161
162 SKIP_IF(engine::get_count(engine_kind) == 0,
163 "Engine kind is not supported");
164
165 engine eng(engine_kind, 0);
166
167 const dnnl::memory::dim N = 7;
168 memory::desc mem_d({N}, memory::data_type::f32, memory::format_tag::x);
169
170 auto mem_ref = test::make_memory(mem_d, eng);
171
172 float buffer_ref[N];
173 std::iota(buffer_ref, buffer_ref + N, 1);
174
175 float *mapped_ptr_ref = mem_ref.map_data<float>();
176 GTEST_EXPECT_NE(mapped_ptr_ref, nullptr);
177 std::copy(buffer_ref, buffer_ref + N, mapped_ptr_ref);
178 mem_ref.unmap_data(mapped_ptr_ref);
179
180 auto mem = test::make_memory(mem_d, eng);
181
182 reorder::primitive_desc reorder_pd(
183 eng, mem_d, eng, mem_d, primitive_attr());
184 reorder reorder_prim(reorder_pd);
185
186 stream strm(eng);
187 reorder_prim.execute(strm, mem_ref, mem);
188 strm.wait();
189
190 float *mapped_ptr = mem.map_data<float>();
191 GTEST_EXPECT_NE(mapped_ptr, nullptr);
192 for (size_t i = 0; i < N; i++) {
193 ASSERT_EQ(mapped_ptr[i], buffer_ref[i]);
194 }
195 mem.unmap_data(mapped_ptr);
196}
197
198namespace {
199struct print_to_string_param_name_t {
200 template <class ParamType>
201 std::string operator()(
202 const ::testing::TestParamInfo<ParamType> &info) const {
203 return to_string(info.param);
204 }
205};
206
207auto all_engine_kinds = ::testing::Values(dnnl_cpu, dnnl_gpu);
208
209} // namespace
210
211INSTANTIATE_TEST_SUITE_P(AllEngineKinds, memory_map_test_c_t, all_engine_kinds,
212 print_to_string_param_name_t());
213
214INSTANTIATE_TEST_SUITE_P(AllEngineKinds, memory_map_test_cpp_t,
215 all_engine_kinds, print_to_string_param_name_t());
216
217} // namespace dnnl
218