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