• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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