1 /*
2 * Copyright (c) 2022 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 "hdi_device_v2_0.h"
17
18 #include "hdf_base.h"
19 #include "mindir.h"
20 #include "securec.h"
21
22 #include "hdi_prepared_model_v2_0.h"
23 #include "lite_graph_to_hdi_model_v2_0.h"
24 #include "hdi_returncode_utils.h"
25 #include "memory_manager.h"
26 #include "transform.h"
27 #include "common/log.h"
28 #include "common/utils.h"
29
30 namespace OHOS {
31 namespace NeuralNetworkRuntime {
32 const size_t OFFLINE_MODEL_MINIMUM_INPUT_SIZE = 2;
33
34 namespace {
TransHDIDeviceV2_0Type(const V2_0::DeviceType & iDeviceType)35 OH_NN_DeviceType TransHDIDeviceV2_0Type(const V2_0::DeviceType& iDeviceType)
36 {
37 switch (iDeviceType) {
38 case V2_0::DeviceType::CPU:
39 return OH_NN_CPU;
40 case V2_0::DeviceType::GPU:
41 return OH_NN_GPU;
42 case V2_0::DeviceType::ACCELERATOR:
43 return OH_NN_ACCELERATOR;
44 default:
45 return OH_NN_OTHERS;
46 }
47 }
48
TransHDIDeviceV2_0Status(const V2_0::DeviceStatus & iDeviceStatus)49 DeviceStatus TransHDIDeviceV2_0Status(const V2_0::DeviceStatus& iDeviceStatus)
50 {
51 switch (iDeviceStatus) {
52 case V2_0::DeviceStatus::AVAILABLE:
53 return DeviceStatus::AVAILABLE;
54 case V2_0::DeviceStatus::BUSY:
55 return DeviceStatus::BUSY;
56 case V2_0::DeviceStatus::OFFLINE:
57 return DeviceStatus::OFFLINE;
58 default:
59 return DeviceStatus::UNKNOWN;
60 }
61 }
62
TransPerformanceMode(const OH_NN_PerformanceMode & mode)63 V2_0::PerformanceMode TransPerformanceMode(const OH_NN_PerformanceMode& mode)
64 {
65 switch (mode) {
66 case OH_NN_PERFORMANCE_LOW:
67 return V2_0::PerformanceMode::PERFORMANCE_LOW;
68 case OH_NN_PERFORMANCE_MEDIUM:
69 return V2_0::PerformanceMode::PERFORMANCE_MEDIUM;
70 case OH_NN_PERFORMANCE_HIGH:
71 return V2_0::PerformanceMode::PERFORMANCE_HIGH;
72 case OH_NN_PERFORMANCE_EXTREME:
73 return V2_0::PerformanceMode::PERFORMANCE_EXTREME;
74 default:
75 return V2_0::PerformanceMode::PERFORMANCE_NONE;
76 }
77 }
78
TransPriority(const OH_NN_Priority & priority)79 V2_0::Priority TransPriority(const OH_NN_Priority& priority)
80 {
81 switch (priority) {
82 case OH_NN_PRIORITY_LOW:
83 return V2_0::Priority::PRIORITY_LOW;
84 case OH_NN_PRIORITY_MEDIUM:
85 return V2_0::Priority::PRIORITY_MEDIUM;
86 case OH_NN_PRIORITY_HIGH:
87 return V2_0::Priority::PRIORITY_HIGH;
88 default:
89 return V2_0::Priority::PRIORITY_NONE;
90 }
91 }
92
IsOfflineModel(std::shared_ptr<const mindspore::lite::LiteGraph> liteGraph,bool & isOfflineModel)93 OH_NN_ReturnCode IsOfflineModel(std::shared_ptr<const mindspore::lite::LiteGraph> liteGraph, bool& isOfflineModel)
94 {
95 isOfflineModel = false; // Initialize the returned value
96 if (liteGraph == nullptr) {
97 LOGE("LiteGraph is empty when identifying the offline model.");
98 return OH_NN_NULL_PTR;
99 }
100
101 if (liteGraph->all_nodes_.size() == 0) {
102 LOGE("Find empty node in the model.");
103 return OH_NN_INVALID_PARAMETER;
104 }
105
106 // If the model consists of more than 1 node, it will not be considered as offline model.
107 if (liteGraph->all_nodes_.size() > 1) {
108 isOfflineModel = false;
109 return OH_NN_SUCCESS;
110 }
111
112 const mindspore::lite::LiteGraph::Node* pNode = liteGraph->all_nodes_[0];
113 if (pNode == nullptr) {
114 LOGE("Find invalid node in the model.");
115 return OH_NN_NULL_PTR;
116 }
117
118 if (pNode->primitive_ == nullptr) {
119 LOGE("Find invalid node primitive in the model.");
120 return OH_NN_NULL_PTR;
121 }
122
123 const mindspore::lite::NodeType& nodeType = mindspore::lite::MindIR_Primitive_GetType(pNode->primitive_);
124 if (nodeType == mindspore::lite::NodeType::NODE_TYPE_CUSTOM) {
125 isOfflineModel = true;
126 }
127
128 return OH_NN_SUCCESS;
129 }
130 } // unamed namespace
131
HDIDeviceV2_0(OHOS::sptr<V2_0::INnrtDevice> device)132 HDIDeviceV2_0::HDIDeviceV2_0(OHOS::sptr<V2_0::INnrtDevice> device) : m_iDevice(device)
133 {}
134
GetDeviceName(std::string & name)135 OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceName(std::string& name)
136 {
137 auto ret = m_iDevice->GetDeviceName(name);
138 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
139 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get HDI device name failed");
140 }
141 return OH_NN_SUCCESS;
142 }
143
GetVendorName(std::string & name)144 OH_NN_ReturnCode HDIDeviceV2_0::GetVendorName(std::string& name)
145 {
146 auto ret = m_iDevice->GetVendorName(name);
147 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
148 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get HDI vendor name failed");
149 }
150 return OH_NN_SUCCESS;
151 }
152
GetVersion(std::string & version)153 OH_NN_ReturnCode HDIDeviceV2_0::GetVersion(std::string& version)
154 {
155 auto ret = m_iDevice->GetVersion(m_hdiVersion.first, m_hdiVersion.second);
156 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
157 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get HDI version failed");
158 }
159 version = 'v' + std::to_string(m_hdiVersion.first) + '_' + std::to_string(m_hdiVersion.second);
160 return OH_NN_SUCCESS;
161 }
162
GetDeviceType(OH_NN_DeviceType & deviceType)163 OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceType(OH_NN_DeviceType& deviceType)
164 {
165 V2_0::DeviceType iDeviceType;
166 auto ret = m_iDevice->GetDeviceType(iDeviceType);
167 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
168 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get HDI device type failed");
169 }
170
171 deviceType = TransHDIDeviceV2_0Type(iDeviceType);
172 return OH_NN_SUCCESS;
173 }
174
GetDeviceStatus(DeviceStatus & status)175 OH_NN_ReturnCode HDIDeviceV2_0::GetDeviceStatus(DeviceStatus& status)
176 {
177 V2_0::DeviceStatus iDeviceStatus;
178 auto ret = m_iDevice->GetDeviceStatus(iDeviceStatus);
179 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
180 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get HDI device status failed");
181 }
182 status = TransHDIDeviceV2_0Status(iDeviceStatus);
183 return OH_NN_SUCCESS;
184 }
185
GetSupportedOperation(std::shared_ptr<const mindspore::lite::LiteGraph> model,std::vector<bool> & ops)186 OH_NN_ReturnCode HDIDeviceV2_0::GetSupportedOperation(std::shared_ptr<const mindspore::lite::LiteGraph> model,
187 std::vector<bool>& ops)
188 {
189 if (model == nullptr) {
190 LOGE("Model is nullptr, cannot query supported operation.");
191 return OH_NN_NULL_PTR;
192 }
193
194 bool isOfflineModel {false};
195 OH_NN_ReturnCode innerRet = IsOfflineModel(model, isOfflineModel);
196 if (innerRet != OH_NN_SUCCESS) {
197 LOGE("Check offline model failed.");
198 return innerRet;
199 }
200
201 // Permanently return a [true] array for offline model.
202 if (isOfflineModel) {
203 ops.clear();
204 ops.emplace_back(true);
205 return OH_NN_SUCCESS;
206 }
207
208 OHOS::HDI::Nnrt::V2_0::SharedBuffer tensorBuffer {INVALID_FD, 0, 0, 0};
209 size_t tensorSize = mindspore::lite::MindIR_LiteGraph_GetConstTensorSize(model.get());
210 int32_t ret {0};
211 if (tensorSize > 0) {
212 ret = m_iDevice->AllocateBuffer(tensorSize, tensorBuffer);
213 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS || tensorBuffer.fd == INVALID_FD) {
214 return CheckReturnCode(ret, OH_NN_FAILED, "Allocate tensor buffer error when get supported operation");
215 }
216 }
217
218 auto iModel = V2::LiteGraph_To_HDIModel(model.get(), tensorBuffer);
219 if (iModel == nullptr) {
220 LOGE("Parse litegraph to hdi model failed.");
221 ReleaseSharedBuffer(tensorBuffer);
222 return OH_NN_FAILED;
223 }
224
225 ret = m_iDevice->GetSupportedOperation(*iModel, ops);
226
227 V2::HDIModel_Destroy(&iModel);
228 innerRet = ReleaseSharedBuffer(tensorBuffer);
229 if (innerRet != OH_NN_SUCCESS) {
230 LOGE("Release tensorBuffer failed.");
231 return OH_NN_FAILED;
232 }
233 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
234 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Get supported operation failed");
235 }
236 return OH_NN_SUCCESS;
237 }
238
IsFloat16PrecisionSupported(bool & isSupported)239 OH_NN_ReturnCode HDIDeviceV2_0::IsFloat16PrecisionSupported(bool& isSupported)
240 {
241 auto ret = m_iDevice->IsFloat16PrecisionSupported(isSupported);
242 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
243 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Query fp16 precision supported failed");
244 }
245 return OH_NN_SUCCESS;
246 }
247
IsPerformanceModeSupported(bool & isSupported)248 OH_NN_ReturnCode HDIDeviceV2_0::IsPerformanceModeSupported(bool& isSupported)
249 {
250 auto ret = m_iDevice->IsPerformanceModeSupported(isSupported);
251 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
252 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Query performance mode supported failed");
253 }
254 return OH_NN_SUCCESS;
255 }
256
IsPrioritySupported(bool & isSupported)257 OH_NN_ReturnCode HDIDeviceV2_0::IsPrioritySupported(bool& isSupported)
258 {
259 auto ret = m_iDevice->IsPrioritySupported(isSupported);
260 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
261 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Query priority supported failed");
262 }
263 return OH_NN_SUCCESS;
264 }
265
IsDynamicInputSupported(bool & isSupported)266 OH_NN_ReturnCode HDIDeviceV2_0::IsDynamicInputSupported(bool& isSupported)
267 {
268 auto ret = m_iDevice->IsDynamicInputSupported(isSupported);
269 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
270 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Query dynamic input supported failed");
271 }
272 return OH_NN_SUCCESS;
273 }
274
IsModelCacheSupported(bool & isSupported)275 OH_NN_ReturnCode HDIDeviceV2_0::IsModelCacheSupported(bool& isSupported)
276 {
277 auto ret = m_iDevice->IsModelCacheSupported(isSupported);
278 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
279 return CheckReturnCode(ret, OH_NN_UNAVAILABLE_DEVICE, "Query cache model supported failed");
280 }
281 return OH_NN_SUCCESS;
282 }
283
PrepareModel(std::shared_ptr<const mindspore::lite::LiteGraph> model,const ModelConfig & config,std::shared_ptr<PreparedModel> & preparedModel)284 OH_NN_ReturnCode HDIDeviceV2_0::PrepareModel(std::shared_ptr<const mindspore::lite::LiteGraph> model,
285 const ModelConfig& config, std::shared_ptr<PreparedModel>& preparedModel)
286 {
287 if (model == nullptr) {
288 LOGE("Model is nullptr, cannot prepare model.");
289 return OH_NN_INVALID_PARAMETER;
290 }
291
292 OHOS::HDI::Nnrt::V2_0::SharedBuffer tensorBuffer {INVALID_FD, 0, 0, 0};
293 size_t tensorSize = mindspore::lite::MindIR_LiteGraph_GetConstTensorSize(model.get());
294 int32_t ret {0};
295 if (tensorSize > 0) {
296 ret = m_iDevice->AllocateBuffer(tensorSize, tensorBuffer);
297 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS || tensorBuffer.fd == INVALID_FD) {
298 return CheckReturnCode(ret, OH_NN_FAILED, "Allocate tensor buffer error when prepare model");
299 }
300 }
301
302 V2_0::Model* iModel = V2::LiteGraph_To_HDIModel(model.get(), tensorBuffer);
303 if (iModel == nullptr) {
304 LOGE("Parse litegraph to hdi model failed.");
305 ReleaseSharedBuffer(tensorBuffer);
306 return OH_NN_FAILED;
307 }
308
309 V2_0::ModelConfig iModelConfig;
310 iModelConfig.enableFloat16 = config.enableFloat16;
311 iModelConfig.mode = TransPerformanceMode(config.mode);
312 iModelConfig.priority = TransPriority(config.priority);
313 OHOS::sptr<V2_0::IPreparedModel> iPreparedModel;
314
315 ret = m_iDevice->PrepareModel(*iModel, iModelConfig, iPreparedModel);
316
317 V2::HDIModel_Destroy(&iModel);
318 auto innerRet = ReleaseSharedBuffer(tensorBuffer);
319 if (innerRet != OH_NN_SUCCESS) {
320 LOGE("Release tensorBuffer failed.");
321 return OH_NN_FAILED;
322 }
323 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS || iPreparedModel == nullptr) {
324 return CheckReturnCode(ret, OH_NN_FAILED, "Prepare model failed");
325 }
326
327 preparedModel = CreateSharedPtr<HDIPreparedModelV2_0>(iPreparedModel);
328 if (preparedModel == nullptr) {
329 LOGE("Prepare model failed, because fail to create preparedModel instance.");
330 return OH_NN_MEMORY_ERROR;
331 }
332
333 return OH_NN_SUCCESS;
334 }
335
PrepareModel(const void * metaGraph,const ModelConfig & config,std::shared_ptr<PreparedModel> & preparedModel)336 OH_NN_ReturnCode HDIDeviceV2_0::PrepareModel(const void* metaGraph,
337 const ModelConfig& config,
338 std::shared_ptr<PreparedModel>& preparedModel)
339 {
340 return OH_NN_OPERATION_FORBIDDEN;
341 }
342
PrepareModelFromModelCache(const std::vector<Buffer> & modelCache,const ModelConfig & config,std::shared_ptr<PreparedModel> & preparedModel,bool & isUpdatable)343 OH_NN_ReturnCode HDIDeviceV2_0::PrepareModelFromModelCache(const std::vector<Buffer>& modelCache,
344 const ModelConfig& config, std::shared_ptr<PreparedModel>& preparedModel, bool& isUpdatable)
345 {
346 std::vector<V2_0::SharedBuffer> iBuffers;
347 auto memManager = MemoryManager::GetInstance();
348 Memory memory;
349 OH_NN_ReturnCode ret;
350 size_t modelCacheSize = modelCache.size();
351 for (size_t i = 0; i < modelCacheSize; i++) {
352 ret = memManager->GetMemory(modelCache[i].data, memory);
353 if (ret != OH_NN_SUCCESS) {
354 LOGE("The %{public}zuth model cache is invalid. Please put valid model cache.", i + 1);
355 return ret;
356 }
357 iBuffers.emplace_back(V2_0::SharedBuffer {memory.fd, memory.length, 0, memory.length});
358 }
359
360 V2_0::ModelConfig iModelConfig;
361 iModelConfig.enableFloat16 = config.enableFloat16;
362 iModelConfig.mode = TransPerformanceMode(config.mode);
363 iModelConfig.priority = TransPriority(config.priority);
364
365 OHOS::sptr<V2_0::IPreparedModel> iPreparedModel;
366 auto nnrtRet = m_iDevice->PrepareModelFromModelCache(iBuffers, iModelConfig, iPreparedModel);
367 if (nnrtRet != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
368 return CheckReturnCode(nnrtRet, OH_NN_FAILED, "Prepare model from cache failed");
369 }
370
371 preparedModel = CreateSharedPtr<HDIPreparedModelV2_0>(iPreparedModel);
372 if (preparedModel == nullptr) {
373 LOGE("Prepare model from model cache failed, because fail to create preparedModel instance.");
374 return OH_NN_MEMORY_ERROR;
375 }
376 return OH_NN_SUCCESS;
377 }
378
AllocateBuffer(size_t length)379 void* HDIDeviceV2_0::AllocateBuffer(size_t length)
380 {
381 if (length == 0) {
382 LOGE("The length param is invalid, length=0");
383 return nullptr;
384 }
385
386 V2_0::SharedBuffer buffer;
387 auto ret = m_iDevice->AllocateBuffer(length, buffer);
388 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
389 return CheckReturnCode(ret, nullptr, "Allocate buffer error");
390 }
391
392 auto memManager = MemoryManager::GetInstance();
393 auto addr = memManager->MapMemory(buffer.fd, length);
394 if (addr == nullptr) {
395 LOGE("Map fd to address failed.");
396 m_iDevice->ReleaseBuffer(buffer);
397 }
398 return addr;
399 }
400
AllocateBuffer(size_t length,int & fd)401 OH_NN_ReturnCode HDIDeviceV2_0::AllocateBuffer(size_t length, int& fd)
402 {
403 if (length == 0) {
404 LOGE("The length param is invalid, length=0");
405 return OH_NN_INVALID_PARAMETER;
406 }
407
408 V2_0::SharedBuffer buffer;
409 auto ret = m_iDevice->AllocateBuffer(length, buffer);
410 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
411 return CheckReturnCode(ret, OH_NN_MEMORY_ERROR, "Allocate buffer error");
412 }
413
414 fd = buffer.fd;
415 return OH_NN_SUCCESS;
416 }
417
ReleaseBuffer(int fd,size_t length)418 OH_NN_ReturnCode HDIDeviceV2_0::ReleaseBuffer(int fd, size_t length)
419 {
420 V2_0::SharedBuffer hdiBuffer {fd, length, 0, length};
421 auto deviceResult = m_iDevice->ReleaseBuffer(hdiBuffer);
422 if (deviceResult != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
423 return CheckReturnCode(deviceResult, OH_NN_FAILED, "Device release buffer error");
424 }
425 return OH_NN_SUCCESS;
426 }
427
AllocateTensorBuffer(size_t length,std::shared_ptr<TensorDesc> tensor)428 void* HDIDeviceV2_0::AllocateTensorBuffer(size_t length, std::shared_ptr<TensorDesc> tensor)
429 {
430 return AllocateBuffer(length);
431 }
432
AllocateTensorBuffer(size_t length,std::shared_ptr<NNTensor> tensor)433 void* HDIDeviceV2_0::AllocateTensorBuffer(size_t length, std::shared_ptr<NNTensor> tensor)
434 {
435 return AllocateBuffer(length);
436 }
437
ReleaseBuffer(const void * buffer)438 OH_NN_ReturnCode HDIDeviceV2_0::ReleaseBuffer(const void* buffer)
439 {
440 if (buffer == nullptr) {
441 LOGE("Buffer is nullptr, no need to release.");
442 return OH_NN_INVALID_PARAMETER;
443 }
444
445 auto memManager = MemoryManager::GetInstance();
446 Memory memory;
447 auto ret = memManager->GetMemory(buffer, memory);
448 if (ret != OH_NN_SUCCESS) {
449 LOGE("Invalid Buffer, it is not NNRt buffer.");
450 return ret;
451 }
452
453 V2_0::SharedBuffer hdiBuffer {memory.fd, memory.length, 0, memory.length};
454 auto deviceResult = m_iDevice->ReleaseBuffer(hdiBuffer);
455 if (deviceResult != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
456 return CheckReturnCode(deviceResult, OH_NN_FAILED, "Device release buffer error");
457 }
458
459 ret = memManager->UnMapMemory(buffer);
460 if (ret != OH_NN_SUCCESS) {
461 LOGE("Unmap memory failed.");
462 return ret;
463 }
464
465 return OH_NN_SUCCESS;
466 }
467
ReleaseSharedBuffer(const V2_0::SharedBuffer & buffer)468 OH_NN_ReturnCode HDIDeviceV2_0::ReleaseSharedBuffer(const V2_0::SharedBuffer& buffer)
469 {
470 if (buffer.fd == INVALID_FD) {
471 LOGI("No need to release. fd=%{public}d", INVALID_FD);
472 return OH_NN_SUCCESS;
473 }
474
475 auto ret = m_iDevice->ReleaseBuffer(buffer);
476 if (ret != V2_0::NNRT_ReturnCode::NNRT_SUCCESS) {
477 return CheckReturnCode(ret, OH_NN_FAILED, "Device release buffer error");
478 }
479 return OH_NN_SUCCESS;
480 }
481
GetOfflineModelFromLiteGraph(std::shared_ptr<const mindspore::lite::LiteGraph> graph,std::vector<std::vector<uint8_t>> & offlineModels)482 OH_NN_ReturnCode HDIDeviceV2_0::GetOfflineModelFromLiteGraph(std::shared_ptr<const mindspore::lite::LiteGraph> graph,
483 std::vector<std::vector<uint8_t>>& offlineModels)
484 {
485 // graph has been checked in PrepareOfflineModel, no need to check twice.
486 offlineModels.clear();
487
488 const size_t inputNum = graph->all_nodes_[0]->input_indices_.size();
489 if (inputNum < OFFLINE_MODEL_MINIMUM_INPUT_SIZE) {
490 LOGE("LiteGraph with offline model should have at least two input tensors, only get %zu.", inputNum);
491 return OH_NN_INVALID_PARAMETER;
492 }
493
494 // The offline model is integrated into the last input tensor.
495 uint32_t index = graph->all_nodes_[0]->input_indices_[inputNum - 1];
496 mindspore::lite::TensorPtr pTensor = graph->all_tensors_[index];
497 std::vector<uint8_t> offlineModel = mindspore::lite::MindIR_Tensor_GetData(pTensor);
498 if (offlineModel.size() == (size_t) 0) {
499 LOGE("Offline model has size of 0, please check the ms model.");
500 return OH_NN_INVALID_PARAMETER;
501 }
502 offlineModels.emplace_back(std::move(offlineModel));
503
504 return OH_NN_SUCCESS;
505 }
506
AllocateDeviceBufferForOfflineModel(const std::vector<std::vector<uint8_t>> & offlineModels,std::vector<Buffer> & deviceBuffers)507 OH_NN_ReturnCode HDIDeviceV2_0::AllocateDeviceBufferForOfflineModel(
508 const std::vector<std::vector<uint8_t>>& offlineModels, std::vector<Buffer>& deviceBuffers)
509 {
510 // offlineModels is guaranteed to have at least one element in GetOfflineModelFromLiteGraph, no need to check size.
511 deviceBuffers.clear();
512
513 for (const std::vector<uint8_t>& offlineModel : offlineModels) {
514 const size_t offlineModelSize = offlineModel.size();
515
516 void* newModelBuffer = AllocateBuffer(offlineModelSize);
517 if (newModelBuffer == nullptr) {
518 // Release allocated model buffer if error happens.
519 OH_NN_ReturnCode status {OH_NN_SUCCESS};
520 for (const Buffer& deviceBuffer : deviceBuffers) {
521 status = ReleaseBuffer(deviceBuffer.data);
522 if (status != OH_NN_SUCCESS) {
523 LOGE("Release shared buffer of offline model failed.");
524 return status;
525 }
526 }
527
528 deviceBuffers.clear();
529 LOGE("Error happens when allocating shared buffer for offline model.");
530 return OH_NN_MEMORY_ERROR;
531 }
532
533 Buffer modelBuffer {nullptr, 0};
534 modelBuffer.data = newModelBuffer;
535 modelBuffer.length = offlineModelSize;
536 deviceBuffers.emplace_back(modelBuffer);
537 }
538
539 return OH_NN_SUCCESS;
540 }
541
CopyOfflineModelToDevice(const std::vector<std::vector<uint8_t>> & offlineModels,std::vector<Buffer> & deviceBuffers)542 OH_NN_ReturnCode HDIDeviceV2_0::CopyOfflineModelToDevice(const std::vector<std::vector<uint8_t>>& offlineModels,
543 std::vector<Buffer>& deviceBuffers)
544 {
545 if (offlineModels.size() != deviceBuffers.size()) {
546 LOGE("CopyOfflineModelToDevice failed, number of offlineModels not equal to allocated buffers.");
547 return OH_NN_INVALID_PARAMETER;
548 }
549
550 const void* offlineModel {nullptr};
551 size_t offlineModelSize {0};
552 void* deviceBuffer {nullptr};
553 size_t deviceBufferSize {0};
554
555 size_t offlineModelsSize = offlineModels.size();
556 for (size_t i = 0; i < offlineModelsSize; i++) {
557 offlineModel = offlineModels[i].data();
558 offlineModelSize = offlineModels[i].size();
559 deviceBuffer = deviceBuffers[i].data;
560 deviceBufferSize = deviceBuffers[i].length;
561
562 // Copy offline model to shared buffer of device.
563 errno_t errorCode = memcpy_s(deviceBuffer, deviceBufferSize, offlineModel, offlineModelSize);
564 if (errorCode != EOK) {
565 LOGE("Error happened when copy offline model to device buffer. Error code: %d.", errorCode);
566 return OH_NN_MEMORY_ERROR;
567 }
568 }
569
570 return OH_NN_SUCCESS;
571 }
572
PrepareOfflineModel(std::vector<Buffer> & deviceBuffers,const ModelConfig & config,const std::map<std::string,std::vector<int8_t>> & extensions,std::shared_ptr<PreparedModel> & preparedModel)573 OH_NN_ReturnCode HDIDeviceV2_0::PrepareOfflineModel(std::vector<Buffer>& deviceBuffers,
574 const ModelConfig& config,
575 const std::map<std::string, std::vector<int8_t>>& extensions,
576 std::shared_ptr<PreparedModel>& preparedModel)
577 {
578 V2_0::ModelConfig iModelConfig;
579 iModelConfig.enableFloat16 = config.enableFloat16;
580 iModelConfig.mode = TransPerformanceMode(config.mode);
581 iModelConfig.priority = TransPriority(config.priority);
582 iModelConfig.extensions = extensions;
583 OHOS::sptr<V2_0::IPreparedModel> iPreparedModel;
584
585 std::vector<V2_0::SharedBuffer> iBuffers;
586 auto memManager = MemoryManager::GetInstance();
587 Memory memory;
588 OH_NN_ReturnCode ret;
589 size_t numOfflineModel = deviceBuffers.size();
590 for (size_t i = 0; i < numOfflineModel; i++) {
591 ret = memManager->GetMemory(deviceBuffers[i].data, memory);
592 if (ret != OH_NN_SUCCESS) {
593 LOGE("Retrieve the memory of %zuth device buffer failed.", i);
594 return ret;
595 }
596 iBuffers.emplace_back(V2_0::SharedBuffer {memory.fd, memory.length, 0, memory.length});
597 }
598
599 auto preparedRet = m_iDevice->PrepareOfflineModel(iBuffers, iModelConfig, iPreparedModel);
600
601 // Release allocated model buffer after prepare model.
602 OH_NN_ReturnCode status {OH_NN_SUCCESS};
603 for (const Buffer& deviceBuffer : deviceBuffers) {
604 status = ReleaseBuffer(deviceBuffer.data);
605 if (status != OH_NN_SUCCESS) {
606 LOGE("Release shared buffer of offline model failed.");
607 return status;
608 }
609 }
610 deviceBuffers.clear();
611
612 if (preparedRet != V2_0::NNRT_ReturnCode::NNRT_SUCCESS || iPreparedModel == nullptr) {
613 return CheckReturnCode(preparedRet, OH_NN_FAILED, "Prepare offline model failed");
614 }
615
616 preparedModel = CreateSharedPtr<HDIPreparedModelV2_0>(iPreparedModel);
617 if (preparedModel == nullptr) {
618 LOGE("Prepare model failed, because fail to create preparedModel instance.");
619 return OH_NN_MEMORY_ERROR;
620 }
621
622 return OH_NN_SUCCESS;
623 }
624
PrepareOfflineModel(std::shared_ptr<const mindspore::lite::LiteGraph> model,const ModelConfig & config,std::shared_ptr<PreparedModel> & preparedModel)625 OH_NN_ReturnCode HDIDeviceV2_0::PrepareOfflineModel(std::shared_ptr<const mindspore::lite::LiteGraph> model,
626 const ModelConfig& config,
627 std::shared_ptr<PreparedModel>& preparedModel)
628 {
629 if (model == nullptr) {
630 LOGE("LiteGraph is empty when identifying the offline model.");
631 return OH_NN_NULL_PTR;
632 }
633
634 std::vector<std::vector<uint8_t>> offlineModels;
635 OH_NN_ReturnCode status = GetOfflineModelFromLiteGraph(model, offlineModels);
636 if (status != OH_NN_SUCCESS) {
637 LOGE("Error happens when getting offline models from lite graph.");
638 return status;
639 }
640
641 std::vector<Buffer> deviceBuffers;
642 status = AllocateDeviceBufferForOfflineModel(offlineModels, deviceBuffers);
643 if (status != OH_NN_SUCCESS) {
644 LOGE("Error happens when allocating device buffers for offline model.");
645 return status;
646 }
647
648 status = CopyOfflineModelToDevice(offlineModels, deviceBuffers);
649 if (status != OH_NN_SUCCESS) {
650 LOGE("Error happened when copying offline models to device buffers.");
651
652 OH_NN_ReturnCode ret {OH_NN_SUCCESS};
653 // Release allocated model buffer if error happens.
654 for (const Buffer& deviceBuffer : deviceBuffers) {
655 ret = ReleaseBuffer(deviceBuffer.data);
656 if (ret != OH_NN_SUCCESS) {
657 LOGE("Releasing device buffer failed after copying offline models to device buffers failed.");
658 return ret;
659 }
660 }
661
662 return status;
663 }
664
665 // Retrieve offline model configs from Custom primitive and insert to extensions.
666 std::string key;
667 std::vector<uint8_t> valueFromCustomPrimitive;
668 std::vector<int8_t> value;
669 std::map<std::string, std::vector<int8_t>> extensions;
670 std::vector<const mindspore::schema::Attribute*> attributes =
671 mindspore::lite::MindIR_Custom_GetAttr(model->all_nodes_[0]->primitive_);
672 for (const auto& attribute : attributes) {
673 key = mindspore::lite::MindIR_Attribute_GetName(*attribute);
674 valueFromCustomPrimitive = mindspore::lite::MindIR_Attribute_GetData(*attribute);
675 value.assign(valueFromCustomPrimitive.begin(), valueFromCustomPrimitive.end());
676 extensions.insert(std::pair<std::string, std::vector<int8_t>>(key, value));
677 }
678
679 status = PrepareOfflineModel(deviceBuffers, config, extensions, preparedModel);
680 if (status != OH_NN_SUCCESS) {
681 LOGE("PrepareOfflineModel failed.");
682 return status;
683 }
684
685 return OH_NN_SUCCESS;
686 }
687 } // namespace NeuralNetworkRuntime
688 } // namespace OHOS
689