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 | |
27 | namespace dnnl { |
28 | |
29 | namespace { |
30 | bool 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 | |
42 | class memory_map_test_c_t |
43 | : public ::testing::TestWithParam<dnnl_engine_kind_t> { |
44 | protected: |
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 | |
64 | class memory_map_test_cpp_t |
65 | : public ::testing::TestWithParam<dnnl_engine_kind_t> {}; |
66 | |
67 | TEST_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 | |
89 | HANDLE_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 | |
152 | HANDLE_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 | |
198 | namespace { |
199 | struct 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 | |
207 | auto all_engine_kinds = ::testing::Values(dnnl_cpu, dnnl_gpu); |
208 | |
209 | } // namespace |
210 | |
211 | INSTANTIATE_TEST_SUITE_P(AllEngineKinds, memory_map_test_c_t, all_engine_kinds, |
212 | print_to_string_param_name_t()); |
213 | |
214 | INSTANTIATE_TEST_SUITE_P(AllEngineKinds, memory_map_test_cpp_t, |
215 | all_engine_kinds, print_to_string_param_name_t()); |
216 | |
217 | } // namespace dnnl |
218 | |