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