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 <cstring>
18#include <memory>
19#include <tuple>
20
21#include "dnnl_test_common.hpp"
22#include "gtest/gtest.h"
23
24#include "oneapi/dnnl/dnnl.hpp"
25
26namespace dnnl {
27
28using data_t = float;
29
30struct params_t {
31 memory::dims dims;
32 memory::format_tag fmt_tag;
33 dnnl_status_t expected_status;
34};
35
36using params_w_engine_t = std::tuple<dnnl::engine::kind, params_t>;
37
38class memory_creation_test_t
39 : public ::testing::TestWithParam<params_w_engine_t> {
40protected:
41 void SetUp() override {
42 params_w_engine_t pwe
43 = ::testing::TestWithParam<decltype(pwe)>::GetParam();
44
45 auto engine_kind = std::get<0>(pwe);
46 if (dnnl::engine::get_count(engine_kind) == 0) return;
47
48 eng = dnnl::engine(engine_kind, 0);
49 p = std::get<1>(pwe);
50 }
51
52 void Test() {
53 dnnl::memory::desc md(p.dims, memory::data_type::f32, p.fmt_tag);
54 dnnl::memory::dim phys_size = md.get_size() / sizeof(data_t);
55
56#ifdef DNNL_SYCL_CUDA
57 const dnnl::impl::memory_desc_wrapper mdw(md.get());
58 SKIP_IF(!mdw.is_plain() && !mdw.format_any(),
59 "Non-plain formats are not supported on CUDA backend");
60#endif
61
62 // mem0
63 // Initially spoiled by putting non-zero values in padded area.
64 auto mem0 = test::make_memory(md, eng);
65
66 // `runtime`-aware buffer for future mem1
67 auto mem1_placeholder = test::make_memory(md, eng);
68
69 // Map-unmap section
70 {
71 // Put non-zeros even to the padded area
72 auto mem0_ptr = map_memory<data_t>(mem0);
73 if (phys_size) GTEST_EXPECT_NE(mem0_ptr, nullptr);
74 fill_data<data_t>(phys_size, mem0_ptr);
75
76 // mem1_placeholder = copy(mem0)
77 auto mem1_ph_ptr = map_memory<data_t>(mem1_placeholder);
78 if (phys_size) GTEST_EXPECT_NE(mem1_ph_ptr, nullptr);
79 for (dnnl::memory::dim i = 0; i < phys_size; ++i)
80 mem1_ph_ptr[i] = mem0_ptr[i];
81 }
82
83 auto mem1 = test::make_memory(md, eng, nullptr);
84 mem1.set_data_handle(mem1_placeholder.get_data_handle());
85
86 // Map-unmap section
87 {
88 auto mem0_ptr = map_memory<data_t>(mem0);
89 if (phys_size) GTEST_EXPECT_NE(mem0_ptr, nullptr);
90 auto mem1_ptr = map_memory<data_t>(mem1);
91 if (phys_size) GTEST_EXPECT_NE(mem1_ptr, nullptr);
92
93 // Check if mem0 == mem1
94 for (dnnl::memory::dim i = 0; i < phys_size; ++i)
95 ASSERT_EQ(mem0_ptr[i], mem1_ptr[i]) << i;
96 }
97 }
98
99 dnnl::engine eng;
100 params_t p;
101};
102
103TEST_P(memory_creation_test_t, TestsMemoryCreation) {
104 SKIP_IF(eng.get(true) == nullptr, "Engine is not supported");
105 catch_expected_failures([=]() { Test(); },
106 p.expected_status != dnnl_success, p.expected_status);
107}
108
109namespace {
110auto all_engine_kinds
111 = ::testing::Values(dnnl::engine::kind::cpu, dnnl::engine::kind::gpu);
112
113using fmt = dnnl::memory::format_tag;
114
115auto cases_expect_to_fail = ::testing::Values(
116 params_t {{2, 2, -1, 1}, fmt::nchw, dnnl_invalid_arguments},
117 params_t {{1, 2, 3, 4}, fmt::any, dnnl_invalid_arguments});
118
119auto cases_zero_dim = ::testing::Values(params_t {{2, 0, 1, 1}, fmt::nChw16c},
120 params_t {{0, 1, 0, 1}, fmt::nhwc}, params_t {{2, 1, 0, 1}, fmt::nchw});
121
122auto cases_generic = ::testing::Values(params_t {{2, 15, 3, 2}, fmt::nChw16c},
123 params_t {{2, 15, 3, 2, 4}, fmt::nCdhw8c},
124 params_t {{2, 9, 3}, fmt::OIw8o4i},
125 params_t {{2, 9, 3, 2}, fmt::OIhw8o4i},
126 params_t {{2, 9, 3, 2}, fmt::OIhw8o8i},
127 params_t {{2, 9, 3, 2}, fmt::OIhw8i16o2i},
128 params_t {{2, 9, 3, 2}, fmt::OIhw8o16i2o},
129 params_t {{2, 9, 3, 2}, fmt::OIhw16o16i},
130 params_t {{2, 9, 3, 2}, fmt::OIhw16i16o},
131 params_t {{2, 9, 3, 2}, fmt::OIhw4i16o4i},
132 params_t {{2, 9, 3, 2}, fmt::OIhw2i8o4i},
133 params_t {{2, 9, 3, 2, 4}, fmt::OIdhw8o4i},
134 params_t {{2, 17, 9, 2}, fmt::gOIw8o4i},
135 params_t {{2, 9, 3}, fmt::OwI16o4i},
136 params_t {{2, 9, 3, 2}, fmt::OhwI16o4i},
137 params_t {{2, 15, 9, 3, 2}, fmt::OdhwI16o4i},
138 params_t {{2, 15, 9, 3}, fmt::gOwI16o4i},
139 params_t {{2, 15, 9, 3, 2}, fmt::gOhwI16o4i},
140 params_t {{3, 18, 9, 3, 2, 3}, fmt::gOdhwI16o4i},
141 params_t {{3, 18, 9, 3, 2, 3}, fmt::gOIdhw4i16o4i},
142 params_t {{2, 18, 8, 4, 2, 3}, fmt::gOIdhw2i8o4i},
143 params_t {{1, 2, 9, 3, 3, 2}, fmt::gOIdhw4o4i},
144 params_t {{2, 9, 3, 2}, fmt::OIhw16i16o4i},
145 params_t {{2, 9, 3, 2}, fmt::OIhw16i16o2i},
146 params_t {{2, 9, 3, 2}, fmt::OIhw16o16i2o},
147 params_t {{2, 9, 4, 3, 2}, fmt::OIdhw16i16o4i},
148 params_t {{2, 9, 4, 3, 2}, fmt::OIdhw16i16o2i},
149 params_t {{2, 9, 4, 3, 2}, fmt::gOihw16o},
150 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw8o4i},
151 params_t {{1, 2, 9, 3, 2}, fmt::gOIhw8o8i},
152 params_t {{1, 2, 9, 3, 2}, fmt::gOIhw4o4i},
153 params_t {{1, 2, 9, 3, 2}, fmt::gOIhw8i8o},
154 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw4i16o4i},
155 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw2i8o4i},
156 params_t {{2, 17, 9, 3, 2, 4}, fmt::gOIdhw8o4i},
157 params_t {{2, 16, 16, 3}, fmt::gOIw2i4o2i},
158 params_t {{2, 8, 6, 3, 3}, fmt::gOIhw2i4o2i},
159 params_t {{2, 14, 18, 3, 3, 4}, fmt::gOIdhw2i4o2i},
160 params_t {{2, 16, 16, 3}, fmt::gOIw4i8o2i},
161 params_t {{2, 12, 18, 3, 2}, fmt::gOIhw4i8o2i},
162 params_t {{2, 10, 6, 3, 5, 3}, fmt::gOIdhw4i8o2i},
163 params_t {{2, 2, 3, 4}, fmt::gOIw2o4i2o},
164 params_t {{2, 18, 8, 3, 3}, fmt::gOIhw2o4i2o},
165 params_t {{2, 10, 6, 6, 3, 3}, fmt::gOIdhw2o4i2o},
166 params_t {{2, 2, 4, 3}, fmt::gOIw4o8i2o},
167 params_t {{2, 14, 10, 3, 3}, fmt::gOIhw4o8i2o},
168 params_t {{2, 8, 8, 3, 3, 3}, fmt::gOIdhw4o8i2o},
169 params_t {{15, 16, 16, 3, 3}, fmt::Goihw8g},
170 params_t {{2, 9, 3}, fmt::OIw2i8o4i},
171 params_t {{2, 17, 9, 3}, fmt::gOIw2i8o4i},
172 params_t {{15, 16, 16, 3}, fmt::Goiw8g},
173 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw16i16o4i},
174 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw16i16o2i},
175 params_t {{2, 17, 9, 3, 2}, fmt::gOIhw16o16i2o},
176 params_t {{2, 15, 17, 9, 3, 2}, fmt::gOIdhw16i16o4i},
177 params_t {{2, 15, 17, 9, 3, 2}, fmt::gOIdhw16i16o2i});
178} // namespace
179
180INSTANTIATE_TEST_SUITE_P(TestMemoryCreationEF, memory_creation_test_t,
181 ::testing::Combine(all_engine_kinds, cases_expect_to_fail));
182
183INSTANTIATE_TEST_SUITE_P(TestMemoryCreationZeroDim, memory_creation_test_t,
184 ::testing::Combine(all_engine_kinds, cases_zero_dim));
185
186INSTANTIATE_TEST_SUITE_P(TestMemoryCreationOK, memory_creation_test_t,
187 ::testing::Combine(all_engine_kinds, cases_generic));
188
189class c_api_memory_test_t : public ::testing::Test {
190 void SetUp() override {}
191};
192
193TEST_F(c_api_memory_test_t, TestZeroPadBoom) {
194#if defined(DNNL_WITH_SYCL) || DNNL_CPU_RUNTIME == DNNL_RUNTIME_NONE
195 SKIP_IF(true, "Test does not support SYCL and GPU only.");
196#endif
197
198 dnnl::impl::memory_desc_t md {};
199
200 md.ndims = 2;
201 md.data_type = dnnl_f32;
202 md.offset0 = 0;
203 md.dims[0] = 1;
204 md.dims[1] = 1001;
205 md.padded_dims[0] = 1;
206 md.padded_dims[1] = 1008;
207 md.padded_offsets[0] = 0;
208 md.padded_offsets[1] = 0;
209
210 md.extra.flags = dnnl::impl::memory_extra_flags::none;
211
212 md.format_kind = dnnl_blocked;
213 md.format_desc.blocking.inner_nblks = 1;
214 md.format_desc.blocking.inner_blks[0] = 16;
215 md.format_desc.blocking.inner_idxs[0] = 1;
216 md.format_desc.blocking.strides[0] = 1008;
217 md.format_desc.blocking.strides[1] = 16;
218
219 dnnl_engine_t e;
220 ASSERT_TRUE(dnnl_success == dnnl_engine_create(&e, dnnl_cpu, 0));
221
222 dnnl_memory_t m;
223 ASSERT_TRUE(
224 dnnl_success == dnnl_memory_create(&m, &md, e, DNNL_MEMORY_NONE));
225
226 void *p = malloc(dnnl_memory_desc_get_size(&md));
227 ASSERT_TRUE(p != nullptr);
228 ASSERT_TRUE(dnnl_success == dnnl_memory_set_data_handle(m, p)); // Boom
229
230 ASSERT_TRUE(dnnl_success == dnnl_memory_destroy(m));
231 free(p);
232
233 ASSERT_TRUE(dnnl_success == dnnl_engine_destroy(e));
234}
235
236#if DNNL_CPU_RUNTIME != DNNL_RUNTIME_DPCPP \
237 && DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE
238TEST(memory_test_cpp, TestSetDataHandleCPU) {
239 engine eng = engine(engine::kind::cpu, 0);
240
241 const memory::dim N = 1, C = 5, W = 7, H = 7;
242 memory::desc data_md(
243 {N, C, W, H}, memory::data_type::f32, memory::format_tag::nChw16c);
244 auto mem = test::make_memory(data_md, eng, DNNL_MEMORY_NONE);
245
246 float *p = (float *)malloc(mem.get_desc().get_size());
247 ASSERT_TRUE(p != nullptr);
248 mem.set_data_handle(p);
249
250 ASSERT_TRUE(N == 1);
251 ASSERT_TRUE(C < 16);
252 ASSERT_TRUE(data_md.get_format_kind() == memory::format_kind::blocked);
253 ASSERT_TRUE(data_md.get_inner_nblks() == 1);
254 ASSERT_TRUE(data_md.get_inner_blks()[0] == 16);
255
256 free(p);
257}
258#endif
259
260} // namespace dnnl
261