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 if (!m_isUserData) {
30 ReleaseMemory();
31 }
32
33 delete m_tensorDesc;
34 m_tensorDesc = nullptr;
35
36 m_data = nullptr;
37 m_fd = 0;
38 m_offset = 0;
39 m_size = 0;
40 m_isUserData = false;
41 }
42
SetTensorDesc(const TensorDesc * tensorDesc)43 OH_NN_ReturnCode NNTensor2_0::SetTensorDesc(const TensorDesc* tensorDesc)
44 {
45 if (m_tensorDesc != nullptr) {
46 delete m_tensorDesc;
47 m_tensorDesc = nullptr;
48 }
49 m_tensorDesc = new (std::nothrow) TensorDesc();
50 if (m_tensorDesc == nullptr) {
51 LOGE("[NNTensor2_0] SetTensorDesc failed, failed to create desc for tensor.");
52 return OH_NN_NULL_PTR;
53 }
54
55 // Copy the member attributes to new tensor description
56 *m_tensorDesc = *tensorDesc;
57
58 return OH_NN_SUCCESS;
59 }
60
CreateData()61 OH_NN_ReturnCode NNTensor2_0::CreateData()
62 {
63 if (m_data != nullptr) {
64 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
65 return OH_NN_FAILED;
66 }
67 if (m_tensorDesc == nullptr) {
68 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
69 return OH_NN_NULL_PTR;
70 }
71
72 size_t byteSize = 0;
73 auto ret = m_tensorDesc->GetByteSize(&byteSize);
74 if (ret != OH_NN_SUCCESS) {
75 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
76 return ret;
77 }
78 if (byteSize > ALLOCATE_BUFFER_LIMIT) {
79 LOGE("NNTensor2_0::CreateData failed, Invalid buffer size, "
80 "it must greater than 0 and less than 1Gb. length=%{public}zu", byteSize);
81 return OH_NN_INVALID_PARAMETER;
82 }
83
84 ret = AllocateMemory(byteSize);
85 if (ret != OH_NN_SUCCESS) {
86 LOGE("NNTensor2_0::CreateData failed, failed to allocate memory.");
87 return ret;
88 }
89 m_isUserData = false;
90 return OH_NN_SUCCESS;
91 }
CreateData(size_t size)92 OH_NN_ReturnCode NNTensor2_0::CreateData(size_t size)
93 {
94 if (m_data != nullptr) {
95 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
96 return OH_NN_FAILED;
97 }
98 if (m_tensorDesc == nullptr) {
99 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
100 return OH_NN_NULL_PTR;
101 }
102 if (size > ALLOCATE_BUFFER_LIMIT) {
103 LOGE("NNTensor2_0::CreateData failed, Invalid buffer size, "
104 "it must greater than 0 and less than 1Gb. length=%{public}zu", size);
105 return OH_NN_INVALID_PARAMETER;
106 }
107 size_t byteSize = 0;
108 auto ret = m_tensorDesc->GetByteSize(&byteSize);
109 if (ret != OH_NN_SUCCESS) {
110 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
111 return ret;
112 }
113 if (size < byteSize) {
114 LOGE("NNTensor2_0::CreateData failed, size:%{public}zu must be larger than "
115 "or equal to byte size:%{public}zu.", size, byteSize);
116 return OH_NN_INVALID_PARAMETER;
117 }
118
119 ret = AllocateMemory(size);
120 if (ret != OH_NN_SUCCESS) {
121 LOGE("NNTensor2_0::CreateData failed, failed to allocate memory.");
122 return ret;
123 }
124 m_isUserData = false;
125 return OH_NN_SUCCESS;
126 }
127
CreateData(int fd,size_t size,size_t offset)128 OH_NN_ReturnCode NNTensor2_0::CreateData(int fd, size_t size, size_t offset)
129 {
130 if (m_data != nullptr) {
131 LOGE("NNTensor2_0::CreateData failed, m_data has been created before.");
132 return OH_NN_FAILED;
133 }
134 if (m_tensorDesc == nullptr) {
135 LOGE("NNTensor2_0::CreateData failed, m_tensorDesc is nullptr.");
136 return OH_NN_NULL_PTR;
137 }
138
139 size_t byteSize = 0;
140 auto ret = m_tensorDesc->GetByteSize(&byteSize);
141 if (ret != OH_NN_SUCCESS) {
142 LOGE("NNTensor2_0::CreateData failed, failed to get byte size from tensorDesc.");
143 return ret;
144 }
145 if (fd < 0) {
146 LOGE("NNTensor2_0::CreateData failed, fd is less than 0.");
147 return OH_NN_INVALID_PARAMETER;
148 }
149 if (size == 0) {
150 LOGE("NNTensor2_0::CreateData failed, size is zero.");
151 return OH_NN_INVALID_PARAMETER;
152 }
153 if (size < offset) {
154 LOGE("NNTensor2_0::CreateData failed, size is smaller than offset.");
155 return OH_NN_INVALID_PARAMETER;
156 }
157 if ((size - offset) < byteSize) {
158 LOGE("NNTensor2_0::CreateData failed, size of fd is insufficient.");
159 return OH_NN_INVALID_PARAMETER;
160 }
161
162 m_data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
163 if (m_data == MAP_FAILED) {
164 LOGE("NNTensor2_0::AllocateMemory failed, Map fd to address failed: %{public}s.", strerror(errno));
165 m_data = nullptr;
166 return OH_NN_MEMORY_ERROR;
167 }
168
169 m_fd = fd;
170 m_size = size;
171 m_offset = offset;
172 m_isUserData = true;
173 return OH_NN_SUCCESS;
174 }
175
GetTensorDesc() const176 TensorDesc* NNTensor2_0::GetTensorDesc() const
177 {
178 return m_tensorDesc;
179 }
180
GetData() const181 void* NNTensor2_0::GetData() const
182 {
183 return m_data;
184 }
185
GetFd() const186 int NNTensor2_0::GetFd() const
187 {
188 return m_fd;
189 }
190
GetSize() const191 size_t NNTensor2_0::GetSize() const
192 {
193 return m_size;
194 }
195
GetOffset() const196 size_t NNTensor2_0::GetOffset() const
197 {
198 return m_offset;
199 }
200
AllocateMemory(size_t length)201 OH_NN_ReturnCode NNTensor2_0::AllocateMemory(size_t length)
202 {
203 BackendManager& backendManager = BackendManager::GetInstance();
204 std::shared_ptr<Backend> backend = backendManager.GetBackend(m_backendID);
205 if (backend == nullptr) {
206 LOGE("NNTensor2_0::AllocateMemory failed, failed to get backend of %{public}zu.", m_backendID);
207 return OH_NN_NULL_PTR;
208 }
209
210 auto* nnBackend = reinterpret_cast<NNBackend*>(backend.get());
211 auto device = nnBackend->GetDevice();
212 if (device == nullptr) {
213 LOGE("NNTensor2_0::AllocateMemory failed, device of nnbackend is nullptr.");
214 return OH_NN_NULL_PTR;
215 }
216 int fd = 0;
217 auto oldRet = device->AllocateBuffer(length, fd);
218 if (oldRet != OH_NN_SUCCESS) {
219 LOGE("NNTensor2_0::AllocateMemory failed, failed to allocate buffer.");
220 return OH_NN_MEMORY_ERROR;
221 }
222 if (fd < 0) {
223 LOGE("NNTensor2_0::AllocateMemory failed, fd must greater than 0.");
224 return OH_NN_INVALID_PARAMETER;
225 }
226
227 m_data = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
228 if (m_data == MAP_FAILED) {
229 LOGE("NNTensor2_0::AllocateMemory failed, Map fd to address failed: %{public}s.", strerror(errno));
230 m_data = nullptr;
231 return OH_NN_MEMORY_ERROR;
232 }
233 m_fd = fd;
234 m_offset = 0;
235 m_size = length;
236
237 return OH_NN_SUCCESS;
238 }
239
ReleaseMemory()240 OH_NN_ReturnCode NNTensor2_0::ReleaseMemory()
241 {
242 if (m_size == 0 || m_data == nullptr) {
243 return OH_NN_SUCCESS;
244 }
245 if (m_fd < 0) {
246 LOGE("NNTensor2_0::ReleaseMemory failed, m_fd must greater than 0.");
247 return OH_NN_INVALID_PARAMETER;
248 }
249
250 BackendManager& backendManager = BackendManager::GetInstance();
251 std::shared_ptr<Backend> backend = backendManager.GetBackend(m_backendID);
252 if (backend == nullptr) {
253 LOGE("NNTensor2_0::ReleaseMemory failed, failed to get backend of %{public}zu.", m_backendID);
254 return OH_NN_NULL_PTR;
255 }
256
257 auto* nnrtBackend = reinterpret_cast<NNBackend*>(backend.get());
258 auto device = nnrtBackend->GetDevice();
259 if (device == nullptr) {
260 LOGE("");
261 return OH_NN_NULL_PTR;
262 }
263 auto oldRet = device->ReleaseBuffer(m_fd, m_size);
264 if (oldRet != OH_NN_SUCCESS) {
265 LOGE("NNTensor2_0::ReleaseMemory failed, failed to release buffer.");
266 return OH_NN_MEMORY_ERROR;
267 }
268
269 auto unmapResult = munmap(m_data, m_size);
270 if (unmapResult != 0) {
271 LOGE("NNTensor2_0::ReleaseMemory failed. Please try again.");
272 return OH_NN_MEMORY_ERROR;
273 }
274 m_data = nullptr;
275 m_size = 0;
276
277 if (close(m_fd) != 0) {
278 LOGE("NNTensor2_0::ReleaseMemory failed. fd=%{public}d", m_fd);
279 return OH_NN_MEMORY_ERROR;
280 }
281 m_fd = 0;
282
283 return OH_NN_SUCCESS;
284 }
285
GetBackendID() const286 size_t NNTensor2_0::GetBackendID() const
287 {
288 return m_backendID;
289 }
290
CheckTensorData() const291 bool NNTensor2_0::CheckTensorData() const
292 {
293 if (m_tensorDesc == nullptr) {
294 LOGE("NNTensor2_0::CheckTensorData failed, m_tensorDesc is nullptr.");
295 return false;
296 }
297
298 size_t byteSize = 0;
299 auto ret = m_tensorDesc->GetByteSize(&byteSize);
300 if (ret != OH_NN_SUCCESS) {
301 LOGE("NNTensor2_0::CheckTensorData failed, failed to get byte size from tensorDesc.");
302 return false;
303 }
304 if ((m_size - m_offset) < byteSize) {
305 LOGE("NNTensor2_0::CheckTensorData failed, m_size is less than byte size.");
306 return false;
307 }
308
309 if (m_data == nullptr) {
310 LOGE("NNTensor2_0::CheckTensorData failed, m_data is nullptr.");
311 return false;
312 }
313
314 if (m_fd < 0) {
315 LOGE("NNTensor2_0::CheckTensorData failed, m_fd is less than zero.");
316 return false;
317 }
318
319 return true;
320 }
321
CheckDimRanges(const std::vector<uint32_t> & minDimRanges,const std::vector<uint32_t> & maxDimRanges) const322 OH_NN_ReturnCode NNTensor2_0::CheckDimRanges(
323 const std::vector<uint32_t>& minDimRanges, const std::vector<uint32_t>& maxDimRanges) const
324 {
325 if (m_tensorDesc == nullptr) {
326 LOGE("NNTensor2_0::CheckInputDimRanges failed, m_tensorDesc is nullptr.");
327 return OH_NN_INVALID_PARAMETER;
328 }
329 int32_t* shape = nullptr;
330 size_t shapeSize = 0;
331 auto ret = m_tensorDesc->GetShape(&shape, &shapeSize);
332 if (ret != OH_NN_SUCCESS) {
333 LOGE("NNTensor2_0::CheckInputDimRanges failed, failed to get shape from desc.");
334 return ret;
335 }
336 for (size_t j = 0; j < shapeSize; ++j) {
337 // Dimensions cannot be negative
338 if (shape[j] < 0) {
339 LOGE("Dimension %{public}zu is %{public}d.", j, shape[j]);
340 return OH_NN_INVALID_PARAMETER;
341 }
342 uint32_t dim = static_cast<uint32_t>(shape[j]);
343 if (dim < minDimRanges[j] || dim > maxDimRanges[j]) {
344 LOGE("Dimension %{public}zu is %{public}u, which is out of range "
345 "[%{public}u, %{public}u]", j, dim, minDimRanges[j], maxDimRanges[j]);
346 return OH_NN_INVALID_PARAMETER;
347 }
348 }
349
350 return OH_NN_SUCCESS;
351 }
352 } // namespace NeuralNetworkRuntime
353 } // namespace OHOS