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