1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <sys/mman.h>
17 #include <unistd.h>
18
19 #include "common/log.h"
20 #include "backend_manager.h"
21 #include "nnbackend.h"
22 #include "nntensor.h"
23 #include "interfaces/kits/c/neural_network_runtime/neural_network_runtime_type.h"
24
25 namespace OHOS {
26 namespace NeuralNetworkRuntime {
~NNTensor2_0()27 NNTensor2_0::~NNTensor2_0()
28 {
29 ReleaseMemory();
30
31 delete m_tensorDesc;
32 m_tensorDesc = nullptr;
33
34 m_data = nullptr;
35 m_fd = 0;
36 m_offset = 0;
37 m_size = 0;
38 m_isUserData = false;
39 }
40
SetTensorDesc(const TensorDesc * tensorDesc)41 OH_NN_ReturnCode NNTensor2_0::SetTensorDesc(const TensorDesc* tensorDesc)
42 {
43 if (m_tensorDesc != nullptr) {
44 delete m_tensorDesc;
45 m_tensorDesc = nullptr;
46 }
47 m_tensorDesc = new (std::nothrow) TensorDesc();
48 if (m_tensorDesc == nullptr) {
49 LOGE("[NNTensor2_0] SetTensorDesc failed, failed to create desc for tensor.");
50 return OH_NN_NULL_PTR;
51 }
52
53 // Copy the member attributes to new tensor description
54 *m_tensorDesc = *tensorDesc;
55
56 return OH_NN_SUCCESS;
57 }
58
CreateData()59 OH_NN_ReturnCode NNTensor2_0::CreateData()
60 {
61 if (m_data != nullptr) {
62 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
63 return OH_NN_FAILED;
64 }
65 if (m_tensorDesc == nullptr) {
66 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
67 return OH_NN_NULL_PTR;
68 }
69
70 size_t byteSize = 0;
71 auto ret = m_tensorDesc->GetByteSize(&byteSize);
72 if (ret != OH_NN_SUCCESS) {
73 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
74 return ret;
75 }
76 if (byteSize > ALLOCATE_BUFFER_LIMIT) {
77 LOGE("NNTensor2_0::CreateData failed, Invalid buffer size, "
78 "it must greater than 0 and less than 1Gb. length=%{public}zu", byteSize);
79 return OH_NN_INVALID_PARAMETER;
80 }
81
82 ret = AllocateMemory(byteSize);
83 if (ret != OH_NN_SUCCESS) {
84 LOGE("NNTensor2_0::CreateData failed, failed to allocate memory.");
85 return ret;
86 }
87 m_isUserData = false;
88 return OH_NN_SUCCESS;
89 }
CreateData(size_t size)90 OH_NN_ReturnCode NNTensor2_0::CreateData(size_t size)
91 {
92 if (m_data != nullptr) {
93 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
94 return OH_NN_FAILED;
95 }
96 if (m_tensorDesc == nullptr) {
97 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
98 return OH_NN_NULL_PTR;
99 }
100 if (size > ALLOCATE_BUFFER_LIMIT) {
101 LOGE("NNTensor2_0::CreateData failed, Invalid buffer size, "
102 "it must greater than 0 and less than 1Gb. length=%{public}zu", size);
103 return OH_NN_INVALID_PARAMETER;
104 }
105 size_t byteSize = 0;
106 auto ret = m_tensorDesc->GetByteSize(&byteSize);
107 if (ret != OH_NN_SUCCESS) {
108 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
109 return ret;
110 }
111 if (size < byteSize) {
112 LOGE("NNTensor2_0::CreateData failed, size:%{public}zu must be larger than "
113 "or equal to byte size:%{public}zu.", size, byteSize);
114 return OH_NN_INVALID_PARAMETER;
115 }
116
117 ret = AllocateMemory(size);
118 if (ret != OH_NN_SUCCESS) {
119 LOGE("NNTensor2_0::CreateData failed, failed to allocate memory.");
120 return ret;
121 }
122 m_isUserData = false;
123 return OH_NN_SUCCESS;
124 }
125
CreateData(int fd,size_t size,size_t offset)126 OH_NN_ReturnCode NNTensor2_0::CreateData(int fd, size_t size, size_t offset)
127 {
128 if (m_data != nullptr) {
129 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
130 return OH_NN_FAILED;
131 }
132 if (m_tensorDesc == nullptr) {
133 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
134 return OH_NN_NULL_PTR;
135 }
136
137 size_t byteSize = 0;
138 auto ret = m_tensorDesc->GetByteSize(&byteSize);
139 if (ret != OH_NN_SUCCESS) {
140 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
141 return ret;
142 }
143 if (fd < 0) {
144 LOGE("NNTensor2_0::CreateData failed, fd is less than 0.");
145 return OH_NN_INVALID_PARAMETER;
146 }
147 if (size == 0) {
148 LOGE("NNTensor2_0::CreateData failed, size is zero.");
149 return OH_NN_INVALID_PARAMETER;
150 }
151 if (size < offset) {
152 LOGE("NNTensor2_0::CreateData failed, size is smaller than offset.");
153 return OH_NN_INVALID_PARAMETER;
154 }
155 if ((size - offset) < byteSize) {
156 LOGE("NNTensor2_0::CreateData failed, size of fd is insufficient.");
157 return OH_NN_INVALID_PARAMETER;
158 }
159
160 m_data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
161 if (m_data == MAP_FAILED) {
162 LOGE("NNTensor2_0::AllocateMemory failed, Map fd to address failed: %{public}s.", strerror(errno));
163 m_data = nullptr;
164 return OH_NN_MEMORY_ERROR;
165 }
166
167 m_fd = fd;
168 m_size = size;
169 m_offset = offset;
170 m_isUserData = true;
171 return OH_NN_SUCCESS;
172 }
173
GetTensorDesc() const174 TensorDesc* NNTensor2_0::GetTensorDesc() const
175 {
176 return m_tensorDesc;
177 }
178
GetData() const179 void* NNTensor2_0::GetData() const
180 {
181 return m_data;
182 }
183
SetData(void * data)184 void NNTensor2_0::SetData(void* data)
185 {
186 m_data = data;
187 }
188
GetFd() const189 int NNTensor2_0::GetFd() const
190 {
191 return m_fd;
192 }
193
SetFd(int fd)194 void NNTensor2_0::SetFd(int fd)
195 {
196 m_fd = fd;
197 }
198
GetSize() const199 size_t NNTensor2_0::GetSize() const
200 {
201 return m_size;
202 }
203
SetSize(size_t size)204 void NNTensor2_0::SetSize(size_t size)
205 {
206 m_size = size;
207 }
208
GetOffset() const209 size_t NNTensor2_0::GetOffset() const
210 {
211 return m_offset;
212 }
213
SetOffset(size_t offset)214 void NNTensor2_0::SetOffset(size_t offset)
215 {
216 m_offset = offset;
217 }
218
AllocateMemory(size_t length)219 OH_NN_ReturnCode NNTensor2_0::AllocateMemory(size_t length)
220 {
221 BackendManager& backendManager = BackendManager::GetInstance();
222 std::shared_ptr<Backend> backend = backendManager.GetBackend(m_backendID);
223 if (backend == nullptr) {
224 LOGE("NNTensor2_0::AllocateMemory failed, failed to get backend of %{public}zu.", m_backendID);
225 return OH_NN_NULL_PTR;
226 }
227
228 auto* nnBackend = reinterpret_cast<NNBackend*>(backend.get());
229 auto device = nnBackend->GetDevice();
230 if (device == nullptr) {
231 LOGE("NNTensor2_0::AllocateMemory failed, device of nnbackend is nullptr.");
232 return OH_NN_NULL_PTR;
233 }
234 int fd = 0;
235 auto oldRet = device->AllocateBuffer(length, fd);
236 if (oldRet != OH_NN_SUCCESS) {
237 LOGE("NNTensor2_0::AllocateMemory failed, failed to allocate buffer.");
238 return OH_NN_MEMORY_ERROR;
239 }
240 if (fd < 0) {
241 LOGE("NNTensor2_0::AllocateMemory failed, fd must greater than 0.");
242 return OH_NN_INVALID_PARAMETER;
243 }
244
245 m_data = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
246 if (m_data == MAP_FAILED) {
247 LOGE("NNTensor2_0::AllocateMemory failed, Map fd to address failed: %{public}s.", strerror(errno));
248 m_data = nullptr;
249 return OH_NN_MEMORY_ERROR;
250 }
251 m_fd = fd;
252 m_offset = 0;
253 m_size = length;
254
255 return OH_NN_SUCCESS;
256 }
257
ReleaseMemory()258 OH_NN_ReturnCode NNTensor2_0::ReleaseMemory()
259 {
260 if (m_size == 0 || m_data == nullptr) {
261 return OH_NN_SUCCESS;
262 }
263 if (m_fd < 0) {
264 LOGE("NNTensor2_0::ReleaseMemory failed, m_fd must greater than 0.");
265 return OH_NN_INVALID_PARAMETER;
266 }
267
268 auto unmapResult = munmap(m_data, m_size);
269 if (unmapResult != 0) {
270 LOGE("NNTensor2_0::ReleaseMemory failed. Please try again.");
271 return OH_NN_MEMORY_ERROR;
272 }
273
274 if (!m_isUserData) {
275 BackendManager& backendManager = BackendManager::GetInstance();
276 std::shared_ptr<Backend> backend = backendManager.GetBackend(m_backendID);
277 if (backend == nullptr) {
278 LOGE("NNTensor2_0::ReleaseMemory failed, failed to get backend of %{public}zu.", m_backendID);
279 return OH_NN_NULL_PTR;
280 }
281
282 auto* nnrtBackend = reinterpret_cast<NNBackend*>(backend.get());
283 auto device = nnrtBackend->GetDevice();
284 if (device == nullptr) {
285 LOGE("");
286 return OH_NN_NULL_PTR;
287 }
288 auto oldRet = device->ReleaseBuffer(m_fd, m_size);
289 if (oldRet != OH_NN_SUCCESS) {
290 LOGE("NNTensor2_0::ReleaseMemory failed, failed to release buffer.");
291 return OH_NN_MEMORY_ERROR;
292 }
293 }
294
295 m_data = nullptr;
296 m_size = 0;
297 m_fd = 0;
298
299 return OH_NN_SUCCESS;
300 }
301
GetBackendID() const302 size_t NNTensor2_0::GetBackendID() const
303 {
304 return m_backendID;
305 }
306
CheckTensorData() const307 bool NNTensor2_0::CheckTensorData() const
308 {
309 if (m_tensorDesc == nullptr) {
310 LOGE("NNTensor2_0::CheckTensorData failed, m_tensorDesc is nullptr.");
311 return false;
312 }
313
314 size_t byteSize = 0;
315 auto ret = m_tensorDesc->GetByteSize(&byteSize);
316 if (ret != OH_NN_SUCCESS) {
317 LOGE("NNTensor2_0::CheckTensorData failed, failed to get byte size from tensorDesc.");
318 return false;
319 }
320 if ((m_size - m_offset) < byteSize) {
321 LOGE("NNTensor2_0::CheckTensorData failed, m_size is less than byte size.");
322 return false;
323 }
324
325 if (m_data == nullptr) {
326 LOGE("NNTensor2_0::CheckTensorData failed, m_data is nullptr.");
327 return false;
328 }
329
330 if (m_fd < 0) {
331 LOGE("NNTensor2_0::CheckTensorData failed, m_fd is less than zero.");
332 return false;
333 }
334
335 return true;
336 }
337
CheckDimRanges(const std::vector<uint32_t> & minDimRanges,const std::vector<uint32_t> & maxDimRanges) const338 OH_NN_ReturnCode NNTensor2_0::CheckDimRanges(
339 const std::vector<uint32_t>& minDimRanges, const std::vector<uint32_t>& maxDimRanges) const
340 {
341 if (m_tensorDesc == nullptr) {
342 LOGE("NNTensor2_0::CheckInputDimRanges failed, m_tensorDesc is nullptr.");
343 return OH_NN_INVALID_PARAMETER;
344 }
345 int32_t* shape = nullptr;
346 size_t shapeSize = 0;
347 auto ret = m_tensorDesc->GetShape(&shape, &shapeSize);
348 if (ret != OH_NN_SUCCESS) {
349 LOGE("NNTensor2_0::CheckInputDimRanges failed, failed to get shape from desc.");
350 return ret;
351 }
352 for (size_t j = 0; j < shapeSize; ++j) {
353 // Dimensions cannot be negative
354 if (shape[j] < 0) {
355 LOGE("Dimension %{public}zu is %{public}d.", j, shape[j]);
356 return OH_NN_INVALID_PARAMETER;
357 }
358 uint32_t dim = static_cast<uint32_t>(shape[j]);
359 if (dim < minDimRanges[j] || dim > maxDimRanges[j]) {
360 LOGE("Dimension %{public}zu is %{public}u, which is out of range "
361 "[%{public}u, %{public}u]", j, dim, minDimRanges[j], maxDimRanges[j]);
362 return OH_NN_INVALID_PARAMETER;
363 }
364 }
365
366 return OH_NN_SUCCESS;
367 }
368 } // namespace NeuralNetworkRuntime
369 } // namespace OHOS