• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nncompiler.h"
17 
18 #include <sys/stat.h>
19 #include <fstream>
20 #include <climits>
21 #include <securec.h>
22 
23 #include "validation.h"
24 #include "nncompiled_cache.h"
25 #include "common/utils.h"
26 
27 namespace OHOS {
28 namespace NeuralNetworkRuntime {
29 namespace {
30 const int CACHE_INPUT_TENSORDESC_OFFSET = 2;
31 const int CACHE_OUTPUT_TENSORDESC_OFFSET = 1;
32 
33 struct SerializedTensorDesc {
34 public:
35     SerializedTensorDesc() = default;
36     ~SerializedTensorDesc() = default;
37 
CopyFromTensorDescOHOS::NeuralNetworkRuntime::__anon1002949b0111::SerializedTensorDesc38     OH_NN_ReturnCode CopyFromTensorDesc(const std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>& tensorDesc)
39     {
40         if (tensorDesc.first == nullptr) {
41             LOGE("CopyFromTensorDesc failed, tensor desc is nullptr.");
42             return OH_NN_NULL_PTR;
43         }
44         OH_NN_ReturnCode ret = tensorDesc.first->GetDataType(&m_dataType);
45         if (ret != OH_NN_SUCCESS) {
46             LOGE("CopyFromTensorDesc failed, error happened when getting data type from tensor desc.");
47             return ret;
48         }
49 
50         ret = tensorDesc.first->GetFormat(&m_format);
51         if (ret != OH_NN_SUCCESS) {
52             LOGE("CopyFromTensorDesc failed, error happened when getting format from tensor desc.");
53             return ret;
54         }
55 
56         ret = tensorDesc.first->GetShape(&m_shape, &m_shapeNum);
57         if (ret != OH_NN_SUCCESS) {
58             LOGE("CopyFromTensorDesc failed, error happened when getting shape from tensor desc.");
59             return ret;
60         }
61 
62         ret = tensorDesc.first->GetName(&m_name);
63         if (ret != OH_NN_SUCCESS) {
64             LOGE("CopyFromTensorDesc failed, error happened when getting name from tensor desc.");
65             return ret;
66         }
67 
68         m_tensorType = tensorDesc.second;
69 
70         return ret;
71     }
72 
CopyToTensorDescOHOS::NeuralNetworkRuntime::__anon1002949b0111::SerializedTensorDesc73     OH_NN_ReturnCode CopyToTensorDesc(TensorDesc& tensorDesc) const
74     {
75         OH_NN_ReturnCode ret = tensorDesc.SetDataType(m_dataType);
76         if (ret != OH_NN_SUCCESS) {
77             LOGE("CopyToTensorDesc failed, error happened when setting data type to tensor desc.");
78             return ret;
79         }
80 
81         ret = tensorDesc.SetFormat(m_format);
82         if (ret != OH_NN_SUCCESS) {
83             LOGE("CopyToTensorDesc failed, error happened when setting format to tensor desc.");
84             return ret;
85         }
86 
87         ret = tensorDesc.SetShape(m_shape, m_shapeNum);
88         if (ret != OH_NN_SUCCESS) {
89             LOGE("CopyToTensorDesc failed, error happened when setting shape to tensor desc.");
90             return ret;
91         }
92 
93         ret = tensorDesc.SetName(m_name);
94         if (ret != OH_NN_SUCCESS) {
95             LOGE("CopyToTensorDesc failed, error happened when setting name to tensor desc.");
96         }
97 
98         return ret;
99     }
100 
101 public:
102     OH_NN_DataType m_dataType{OH_NN_UNKNOWN};
103     OH_NN_Format m_format{OH_NN_FORMAT_NONE};
104     OH_NN_TensorType m_tensorType{OH_NN_TENSOR};
105     size_t m_shapeNum{0};
106     int32_t* m_shape{nullptr};
107     const char* m_name{nullptr}; // null-terminated
108 };
109 
110 const size_t SIZE_OF_DATATYPE = sizeof(SerializedTensorDesc::m_dataType);
111 const size_t SIZE_OF_FORMAT = sizeof(SerializedTensorDesc::m_format);
112 const size_t SIZE_OF_TENSOR_TYPE = sizeof(SerializedTensorDesc::m_tensorType);
113 const size_t SIZE_OF_SHAPE_NUM = sizeof(SerializedTensorDesc::m_shapeNum);
114 } // namespace
115 
NNCompiler(std::shared_ptr<Device> device,size_t backendID)116 NNCompiler::NNCompiler(std::shared_ptr<Device> device, size_t backendID)
117     : m_device(device),
118     m_backendID(backendID) {}
119 
NNCompiler(const void * model,std::shared_ptr<Device> device,size_t backendID)120 NNCompiler::NNCompiler(const void* model, std::shared_ptr<Device> device, size_t backendID)
121     : m_device(device),
122     m_backendID(backendID)
123 {
124     m_innerModel = const_cast<InnerModel*>(reinterpret_cast<const InnerModel*>(model));
125     m_liteGraph = m_innerModel->GetLiteGraphs();
126     m_inputTensorDescs = m_innerModel->GetInputTensorDescs();
127     m_outputTensorDescs = m_innerModel->GetOutputTensorDescs();
128     m_metaGraph = m_innerModel->GetMetaGraph();
129     m_quantBuffer = m_innerModel->GetQuantBuffer();
130     m_modelName = m_innerModel->GetModelName();
131 }
132 
~NNCompiler()133 NNCompiler::~NNCompiler()
134 {
135     if (m_preparedModel != nullptr) {
136         m_preparedModel.reset();
137     }
138     m_inputTensorDescs.clear();
139     m_outputTensorDescs.clear();
140 }
141 
GetBackendID() const142 size_t NNCompiler::GetBackendID() const
143 {
144     return m_backendID;
145 }
146 
SetCacheDir(const std::string & cacheModelPath,uint32_t version)147 OH_NN_ReturnCode NNCompiler::SetCacheDir(const std::string& cacheModelPath, uint32_t version)
148 {
149     if (m_device == nullptr) {
150         LOGE("[NNCompiler] SetCacheDir failed, m_device is nullptr");
151         return OH_NN_OPERATION_FORBIDDEN;
152     }
153 
154     bool isSupportedCache {false};
155     OH_NN_ReturnCode ret = m_device->IsModelCacheSupported(isSupportedCache);
156     if (ret != OH_NN_SUCCESS) {
157         LOGE("[NNCompiler] SetCacheDir failed, fail to call device.");
158         return ret;
159     }
160 
161     if (!isSupportedCache && !cacheModelPath.empty()) {
162         LOGE("[NNCompiler] SetCacheDir failed, this device is not support cache setting.");
163         return OH_NN_OPERATION_FORBIDDEN;
164     }
165 
166     m_cachePath = cacheModelPath;
167     m_cacheVersion = version;
168 
169     return OH_NN_SUCCESS;
170 }
171 
SetPerformance(OH_NN_PerformanceMode performance)172 OH_NN_ReturnCode NNCompiler::SetPerformance(OH_NN_PerformanceMode performance)
173 {
174     if (m_device == nullptr) {
175         LOGE("[NNCompiler] SetPerformance failed, m_device is nullptr");
176         return OH_NN_OPERATION_FORBIDDEN;
177     }
178 
179     bool isSupportedPerformance {false};
180     OH_NN_ReturnCode ret = m_device->IsPerformanceModeSupported(isSupportedPerformance);
181     if (ret != OH_NN_SUCCESS) {
182         LOGE("[NNCompiler] SetPerformance failed, fail to call device.");
183         return OH_NN_FAILED;
184     }
185 
186     if (!isSupportedPerformance && (performance != OH_NN_PERFORMANCE_NONE)) {
187         LOGE("[NNCompiler] SetPerformance failed, this device is not support performance setting.");
188         return OH_NN_OPERATION_FORBIDDEN;
189     }
190 
191     if (!Validation::ValidatePerformanceMode(performance)) {
192         LOGE("[NNCompiler] SetPerformance failed, performance=%{public}d is invalid", performance);
193         return OH_NN_INVALID_PARAMETER;
194     }
195 
196     m_performance = performance;
197     return OH_NN_SUCCESS;
198 }
199 
SetPriority(OH_NN_Priority priority)200 OH_NN_ReturnCode NNCompiler::SetPriority(OH_NN_Priority priority)
201 {
202     if (m_device == nullptr) {
203         LOGE("[NNCompiler] SetPriority failed, m_device is nullptr");
204         return OH_NN_OPERATION_FORBIDDEN;
205     }
206 
207     bool isSupportedPriority {false};
208     OH_NN_ReturnCode ret = m_device->IsPrioritySupported(isSupportedPriority);
209     if (ret != OH_NN_SUCCESS) {
210         LOGE("[NNCompiler] SetPriority failed, fail to call device.");
211         return ret;
212     }
213 
214     if (!isSupportedPriority && (priority != OH_NN_PRIORITY_NONE)) {
215         LOGE("[NNCompiler] SetPriority failed, this device is not support priority setting.");
216         return OH_NN_OPERATION_FORBIDDEN;
217     }
218 
219     if (!Validation::ValidatePriority(priority)) {
220         LOGE("[NNCompiler] SetPriority failed, priority=%{public}d is invalid.", priority);
221         return OH_NN_INVALID_PARAMETER;
222     }
223 
224     m_priority = priority;
225     return OH_NN_SUCCESS;
226 }
227 
SetEnableFp16(bool isFp16)228 OH_NN_ReturnCode NNCompiler::SetEnableFp16(bool isFp16)
229 {
230     if (m_device == nullptr) {
231         LOGE("[NNCompiler] SetEnableFp16 failed, m_device is nullptr");
232         return OH_NN_OPERATION_FORBIDDEN;
233     }
234 
235     bool isSupportedFp16 {false};
236     OH_NN_ReturnCode ret = m_device->IsFloat16PrecisionSupported(isSupportedFp16);
237     if (ret != OH_NN_SUCCESS) {
238         LOGE("[NNCompiler] SetEnableFp16 failed, fail to call device.");
239         return ret;
240     }
241 
242     if (!isSupportedFp16 && isFp16) {
243         LOGE("[NNCompiler] SetEnableFp16 failed, this device is not support float16 precision setting.");
244         return OH_NN_OPERATION_FORBIDDEN;
245     }
246 
247     m_enableFp16 = isFp16;
248     return OH_NN_SUCCESS;
249 }
250 
IsBuild() const251 bool NNCompiler::IsBuild() const
252 {
253     return m_isBuild;
254 }
255 
IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph> & liteGraph,bool & isSupportedModel) const256 OH_NN_ReturnCode NNCompiler::IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph>& liteGraph,
257                                               bool& isSupportedModel) const
258 {
259     std::vector<bool> supportedList;
260     OH_NN_ReturnCode ret = m_device->GetSupportedOperation(liteGraph, supportedList);
261     if (ret != OH_NN_SUCCESS) {
262         LOGE("[NNCompiler] Build failed, error happened when getting supported operation.");
263         return ret;
264     }
265 
266     bool isNotSupport = std::any_of(supportedList.begin(), supportedList.end(), [](bool isSupport) {
267         return !isSupport;
268     });
269     if (isNotSupport) {
270         LOGE("[NNCompiler] Build failed, current device not support the model, device id: %{public}zu.", m_backendID);
271         isSupportedModel = false;
272         return OH_NN_FAILED;
273     }
274 
275     isSupportedModel = true;
276     return OH_NN_SUCCESS;
277 }
278 
CheckModelParameter() const279 OH_NN_ReturnCode NNCompiler::CheckModelParameter() const
280 {
281     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
282     if (m_innerModel == nullptr) {
283         LOGW("[NNCompiler] Restoring from cache not need to check model.");
284         return OH_NN_SUCCESS;
285     }
286 
287     // m_innerModel is not constructed completely.
288     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
289         LOGE("[NNCompiler] LiteGraph and metaGraph are empty, m_innerModel is not constructed completely.");
290         return OH_NN_INVALID_PARAMETER;
291     }
292 
293     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
294         LOGE("[NNCompiler] Both LiteGraph and metaGraph are not empty.");
295         return OH_NN_INVALID_PARAMETER;
296     }
297 
298     return OH_NN_SUCCESS;
299 }
300 
IsOfflineModel(bool & isOfflineModel) const301 OH_NN_ReturnCode NNCompiler::IsOfflineModel(bool& isOfflineModel) const
302 {
303     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
304     if (m_innerModel == nullptr) {
305         LOGW("[NNCompiler] Restoring from cache not need to judge offline model.");
306         return OH_NN_SUCCESS;
307     }
308 
309     isOfflineModel = false; // Initialize the returned value
310     if (m_metaGraph != nullptr) {
311         isOfflineModel = false;
312         return OH_NN_SUCCESS;
313     }
314 
315     if (m_liteGraph->all_nodes_.size() == 0) {
316         LOGE("[NNCompiler] Find empty node in the model.");
317         return OH_NN_INVALID_PARAMETER;
318     }
319 
320     // If the model consists of more than 1 node, it will not be considered as offline model.
321     if (m_liteGraph->all_nodes_.size() > 1) {
322         isOfflineModel = false;
323         return OH_NN_SUCCESS;
324     }
325 
326     const mindspore::lite::LiteGraph::Node* pNode = m_liteGraph->all_nodes_[0];
327     if (pNode == nullptr) {
328         LOGE("[NNCompiler] Find invalid node in the model.");
329         return OH_NN_NULL_PTR;
330     }
331 
332     const mindspore::lite::NodeType& nodeType = mindspore::lite::MindIR_Primitive_GetType(pNode->primitive_);
333     if (nodeType == mindspore::lite::NodeType::NODE_TYPE_CUSTOM) {
334         isOfflineModel = true;
335     }
336 
337     return OH_NN_SUCCESS;
338 }
339 
BuildOfflineModel()340 OH_NN_ReturnCode NNCompiler::BuildOfflineModel()
341 {
342     ModelConfig config {m_enableFp16, m_performance, m_priority};
343     OH_NN_ReturnCode ret = m_device->PrepareOfflineModel(m_liteGraph, config, m_preparedModel);
344     if (ret != OH_NN_SUCCESS) {
345         LOGE("[NNCompiler] Preparing model failed when building from offline model.");
346         return ret;
347     }
348 
349     return OH_NN_SUCCESS;
350 }
351 
NormalBuild()352 OH_NN_ReturnCode NNCompiler::NormalBuild()
353 {
354     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
355         LOGW("[NNCompiler] Build failed, both liteGraph and metaGraph are nullptr.");
356         return OH_NN_INVALID_PARAMETER;
357     }
358 
359     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
360         LOGE("[NNCompiler] Build failed, neither liteGraph nor metaGraph are nullptr.");
361         return OH_NN_INVALID_PARAMETER;
362     }
363 
364     // 判断是否支持模型
365     bool isSupportedModel = true;
366     OH_NN_ReturnCode ret = IsSupportedModel(m_liteGraph, isSupportedModel);
367     if (ret != OH_NN_SUCCESS) {
368         LOGE("[NNCompiler] Build failed, error happened when judge if support the model.");
369         return ret;
370     } else if (!isSupportedModel) {
371         LOGE("[NNCompiler] Build failed, current device not support the model.");
372         return OH_NN_FAILED;
373     }
374 
375     ModelConfig config {m_enableFp16, static_cast<OH_NN_PerformanceMode>(m_performance),
376         static_cast<OH_NN_Priority>(m_priority)};
377     if (m_liteGraph != nullptr) {
378         ret = m_device->PrepareModel(m_liteGraph, config, m_preparedModel);
379     }
380     if (m_metaGraph != nullptr) {
381         ret = m_device->PrepareModel(m_metaGraph, m_quantBuffer, config, m_preparedModel);
382     }
383     if (ret != OH_NN_SUCCESS) {
384         LOGE("[NNCompiler] Build failed, fail to prepare model when normally building.");
385         return ret;
386     }
387     m_isBuild = true;
388 
389     // 保存cache
390     if (!m_cachePath.empty()) {
391         ret = SaveToCacheFile();
392         if (ret != OH_NN_SUCCESS) {
393             LOGE("[NNCompiler] Build success, but fail to save cache to file.");
394             return ret;
395         }
396     }
397 
398     return OH_NN_SUCCESS;
399 }
400 
Build()401 OH_NN_ReturnCode NNCompiler::Build()
402 {
403     if (m_isBuild) {
404         LOGE("[NNCompiler] Build failed, cannot build again.");
405         return OH_NN_OPERATION_FORBIDDEN;
406     }
407 
408     if (m_device == nullptr) {
409         LOGE("[NNCompiler] Build failed, the m_device is nullptr.");
410         return OH_NN_OPERATION_FORBIDDEN;
411     }
412 
413     OH_NN_ReturnCode ret = CheckModelParameter();
414     if (ret != OH_NN_SUCCESS) {
415         LOGE("[NNCompiler] CheckModelParameter failed, some error happened when checking model parameter.");
416         return ret;
417     }
418 
419     // Prepare from offline model.
420     bool isOfflineModel {false};
421     ret = IsOfflineModel(isOfflineModel);
422     if (ret != OH_NN_SUCCESS) {
423         LOGE("[NNCompiler] Build failed, fail to identify the offline model.");
424         return ret;
425     }
426 
427     if (isOfflineModel) {
428         ret = BuildOfflineModel();
429         if (ret != OH_NN_SUCCESS) {
430             LOGE("[NNCompiler] Build failed, Failed to build offline model.");
431             return ret;
432         }
433 
434         m_isBuild = true;
435         return OH_NN_SUCCESS;
436     }
437 
438     // cache存在,从cache直接复原prepareModel、input/output TensorDesc
439     ret = RestoreFromCacheFile();
440     if (ret == OH_NN_OPERATION_FORBIDDEN) {
441         LOGE("[NNCompiler] Build failed, operation is forbidden.");
442         return ret;
443     }
444     if (ret == OH_NN_SUCCESS) {
445         LOGI("[NNCompiler] Build success, restore from cache file.");
446         m_isBuild = true;
447         return OH_NN_SUCCESS;
448     }
449 
450     // cache不存在或cache restore失败,走在线构图
451     ret = NormalBuild();
452     if (ret != OH_NN_SUCCESS) {
453         LOGE("[NNCompiler] Build failed, fail to build model online.");
454         return ret;
455     }
456 
457     return OH_NN_SUCCESS;
458 }
459 
ReleaseBuffer(std::vector<Buffer> & buffers) const460 void NNCompiler::ReleaseBuffer(std::vector<Buffer>& buffers) const
461 {
462     for (size_t i = 0; i < buffers.size(); ++i) {
463         // release tensor buffer which is allocated by new method.
464         delete[] reinterpret_cast<char*>(buffers[i].data);
465     }
466     buffers.clear();
467 }
468 
ReleaseBufferByDevice(std::vector<Buffer> & buffers) const469 void NNCompiler::ReleaseBufferByDevice(std::vector<Buffer>& buffers) const
470 {
471     for (size_t i = 0; i < buffers.size(); ++i) {
472         // release cache buffer which is allocated by idevice.
473         m_device->ReleaseBuffer(buffers[i].data);
474     }
475     buffers.clear();
476 }
477 
SaveToCacheFile() const478 OH_NN_ReturnCode NNCompiler::SaveToCacheFile() const
479 {
480     if (m_cachePath.empty()) {
481         LOGE("[NNCompiler] SaveToCacheFile failed, m_cachePath is empty.");
482         return OH_NN_INVALID_PARAMETER;
483     }
484 
485     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
486         LOGE("[NNCompiler] SaveToCacheFile failed, cache version is invalid. Please set a valid cache version.");
487         return OH_NN_INVALID_PARAMETER;
488     }
489 
490     if (m_preparedModel == nullptr) {
491         LOGE("[NNCompiler] SaveToCacheFile failed, m_preparedModel is nullptr. Please construct prepareModel first.");
492         return OH_NN_FAILED;
493     }
494 
495     std::vector<Buffer> caches;
496     std::vector<Buffer> tensorBuffers;
497     OH_NN_ReturnCode ret = m_preparedModel->ExportModelCache(caches);
498     if (ret != OH_NN_SUCCESS) {
499         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when exporting model cache.");
500         return ret;
501     }
502 
503     NNCompiledCache compiledCache;
504     ret = compiledCache.SetBackend(m_backendID);
505     if (ret != OH_NN_SUCCESS) {
506         LOGE("[NNCompiler] SaveToCacheFile failed, fail to set backend.");
507         return ret;
508     }
509 
510     Buffer inputTensorDescBuffer;
511     ret = SerializeTensorsToBuffer(m_inputTensorDescs, inputTensorDescBuffer);
512     if (ret != OH_NN_SUCCESS) {
513         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing input tensor desc.");
514         return ret;
515     }
516     caches.emplace_back(inputTensorDescBuffer);
517     tensorBuffers.emplace_back(inputTensorDescBuffer);
518 
519     Buffer outputTensorDescBuffer;
520     ret = SerializeTensorsToBuffer(m_outputTensorDescs, outputTensorDescBuffer);
521     if (ret != OH_NN_SUCCESS) {
522         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing output tensor desc.");
523         ReleaseBuffer(tensorBuffers);
524         return ret;
525     }
526     caches.emplace_back(outputTensorDescBuffer);
527     tensorBuffers.emplace_back(outputTensorDescBuffer);
528 
529     compiledCache.SetModelName(m_modelName);
530     ret = compiledCache.Save(caches, m_cachePath, m_cacheVersion);
531     if (ret != OH_NN_SUCCESS) {
532         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when saving model cache.");
533         ReleaseBuffer(tensorBuffers);
534         return ret;
535     }
536 
537     ReleaseBuffer(tensorBuffers);
538     LOGI("[NNCompiler] Export model cache successfully.");
539     return OH_NN_SUCCESS;
540 }
541 
RestoreFromCacheFile()542 OH_NN_ReturnCode NNCompiler::RestoreFromCacheFile()
543 {
544     if (m_cachePath.empty()) {
545         LOGE("[NNCompiler] RestoreFromCacheFile failed, path is empty.");
546         return OH_NN_INVALID_PARAMETER;
547     }
548 
549     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
550         LOGE("[NNCompiler] RestoreFromCacheFile failed, cache version is invalid. Please set a valid cache version.");
551         return OH_NN_INVALID_PARAMETER;
552     }
553 
554     if (m_preparedModel != nullptr) {
555         LOGE("[NNCompiler] RestoreFromCacheFile failed, m_preparedModel is not nullptr.");
556         return OH_NN_FAILED;
557     }
558 
559     NNCompiledCache compiledCache;
560     OH_NN_ReturnCode ret = compiledCache.SetBackend(m_backendID);
561     if (ret != OH_NN_SUCCESS) {
562         LOGE("[NNCompiler] RestoreFromCacheFile failed, fail to set backend.");
563         return ret;
564     }
565 
566     std::vector<Buffer> caches;
567     compiledCache.SetModelName(m_modelName);
568     ret = compiledCache.Restore(m_cachePath, m_cacheVersion, caches);
569     if (ret != OH_NN_SUCCESS) {
570         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when restoring model cache.");
571         ReleaseBufferByDevice(caches);
572         return ret;
573     }
574 
575     size_t cacheNum = caches.size();
576     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> inputTensorDescs;
577     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_INPUT_TENSORDESC_OFFSET], inputTensorDescs);
578     if (ret != OH_NN_SUCCESS) {
579         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing input tensor desc.");
580         ReleaseBufferByDevice(caches);
581         return ret;
582     }
583 
584     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> outputTensorDescs;
585     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_OUTPUT_TENSORDESC_OFFSET], outputTensorDescs);
586     if (ret != OH_NN_SUCCESS) {
587         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing output tensor desc.");
588         ReleaseBufferByDevice(caches);
589         return ret;
590     }
591 
592     ModelConfig config;
593     config.enableFloat16 = m_enableFp16;
594     config.mode = m_performance;
595     config.priority = m_priority;
596     std::vector<Buffer> modelOnlyCaches(caches.begin(), caches.end() - CACHE_INPUT_TENSORDESC_OFFSET);
597     ret = m_device->PrepareModelFromModelCache(modelOnlyCaches, config, m_preparedModel);
598     if (ret != OH_NN_SUCCESS) {
599         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when preparing model from cache.");
600         ReleaseBufferByDevice(caches);
601         return ret;
602     }
603     ReleaseBufferByDevice(caches);
604 
605     m_inputTensorDescs = inputTensorDescs;
606     m_outputTensorDescs = outputTensorDescs;
607     LOGI("[NNCompiler] Restore model cache successfully.");
608     return OH_NN_SUCCESS;
609 }
610 
SaveToCacheBuffer(const void * buffer,size_t length,size_t * modelSize) const611 OH_NN_ReturnCode NNCompiler::SaveToCacheBuffer(const void* buffer, size_t length, size_t* modelSize) const
612 {
613     LOGE("[NNCompiler] SaveToCacheBuffer is not supported currently.");
614     return OH_NN_UNSUPPORTED;
615 }
616 
RestoreFromCacheBuffer(const void * buffer,size_t length)617 OH_NN_ReturnCode NNCompiler::RestoreFromCacheBuffer(const void* buffer, size_t length)
618 {
619     LOGE("[NNCompiler] RestoreFromCacheBuffer is not supported currently.");
620     return OH_NN_UNSUPPORTED;
621 }
622 
SetExtensionConfig(const std::unordered_map<std::string,std::vector<char>> & configs)623 OH_NN_ReturnCode NNCompiler::SetExtensionConfig(const std::unordered_map<std::string, std::vector<char>>& configs)
624 {
625     LOGI("[NNCompiler] SetExtensionConfig successfully.");
626     return OH_NN_SUCCESS;
627 }
628 
SetOptions(const std::vector<std::shared_ptr<void>> & options)629 OH_NN_ReturnCode NNCompiler::SetOptions(const std::vector<std::shared_ptr<void>>& options)
630 {
631     LOGE("[NNCompiler] SetOptions is not supported for NN compiler currently.");
632     return OH_NN_UNSUPPORTED;
633 }
634 
CreateExecutor()635 NNExecutor* NNCompiler::CreateExecutor()
636 {
637     if (m_device == nullptr) {
638         LOGE("[NNCompiler] CreateExecutor failed, m_device is nullptr");
639         return nullptr;
640     }
641 
642     if (m_preparedModel == nullptr) {
643         LOGE("[NNCompiler] CreateExecutor failed, m_device is nullptr");
644         return nullptr;
645     }
646 
647     if (m_inputTensorDescs.empty()) {
648         LOGE("[NNCompiler] CreateExecutor failed, m_inputTensorDescs is empty");
649         return nullptr;
650     }
651 
652     if (m_outputTensorDescs.empty()) {
653         LOGE("[NNCompiler] CreateExecutor failed, m_outputTensorDescs is empty");
654         return nullptr;
655     }
656 
657     NNExecutor* nnExecutor = new (std::nothrow) NNExecutor(
658         m_backendID, m_device, m_preparedModel, m_inputTensorDescs, m_outputTensorDescs);
659     if (nnExecutor == nullptr) {
660         LOGE("[NNCompiler] CreateExecutor failed, error happend when allocating NN Executor.");
661         return nullptr;
662     }
663 
664     return nnExecutor;
665 }
666 
SerializeTensorsToBuffer(const std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs,Buffer & buffer) const667 OH_NN_ReturnCode NNCompiler::SerializeTensorsToBuffer(
668     const std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs, Buffer& buffer) const
669 {
670     std::vector<SerializedTensorDesc> immediateTensorDescs;
671     OH_NN_ReturnCode ret = OH_NN_SUCCESS;
672     for (const auto& tensorDesc : tensorDescs) {
673         SerializedTensorDesc immediateTensorDesc;
674         ret = immediateTensorDesc.CopyFromTensorDesc(tensorDesc);
675         if (ret != OH_NN_SUCCESS) {
676             LOGE("[NNCompiler] SerializeInputsToBuffer failed, error happened when copying tensorDesc to "
677                  "SerializedTensorDesc.");
678             immediateTensorDescs.clear();
679             return ret;
680         }
681         immediateTensorDescs.emplace_back(immediateTensorDesc);
682     }
683 
684     size_t totalSize = 0;
685     for (const auto& tensorDesc : immediateTensorDescs) {
686         totalSize += SIZE_OF_DATATYPE;
687         totalSize += SIZE_OF_FORMAT;
688         totalSize += SIZE_OF_TENSOR_TYPE;
689         totalSize += SIZE_OF_SHAPE_NUM;
690         totalSize += tensorDesc.m_shapeNum * sizeof(int32_t);
691         totalSize += strlen(tensorDesc.m_name) + 1;
692     }
693 
694     // Allocate memory for the serialized data
695     char* serializedData = new (std::nothrow) char[totalSize];
696     if (serializedData == nullptr) {
697         LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to create serialized data.");
698         return OH_NN_NULL_PTR;
699     }
700     char* currentPos = serializedData;
701 
702     // Serialize each tensor description
703     for (const auto& tensorDesc : immediateTensorDescs) {
704         auto memRet = memcpy_s(currentPos, SIZE_OF_DATATYPE, &tensorDesc.m_dataType, SIZE_OF_DATATYPE);
705         if (memRet != EOK) {
706             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s data type.");
707             delete[] serializedData;
708             return OH_NN_MEMORY_ERROR;
709         }
710         currentPos += SIZE_OF_DATATYPE;
711 
712         memRet = memcpy_s(currentPos, SIZE_OF_FORMAT, &tensorDesc.m_format, SIZE_OF_FORMAT);
713         if (memRet != EOK) {
714             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s format.");
715             delete[] serializedData;
716             return OH_NN_MEMORY_ERROR;
717         }
718         currentPos += SIZE_OF_FORMAT;
719 
720         memRet = memcpy_s(currentPos, SIZE_OF_TENSOR_TYPE, &tensorDesc.m_tensorType, SIZE_OF_TENSOR_TYPE);
721         if (memRet != EOK) {
722             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s tensor type.");
723             delete[] serializedData;
724             return OH_NN_MEMORY_ERROR;
725         }
726         currentPos += SIZE_OF_TENSOR_TYPE;
727 
728         memRet = memcpy_s(currentPos, SIZE_OF_SHAPE_NUM, &tensorDesc.m_shapeNum, SIZE_OF_SHAPE_NUM);
729         if (memRet != EOK) {
730             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape num.");
731             delete[] serializedData;
732             return OH_NN_MEMORY_ERROR;
733         }
734         currentPos += SIZE_OF_SHAPE_NUM;
735 
736         size_t sizeOfShape = tensorDesc.m_shapeNum * sizeof(int32_t);
737         memRet = memcpy_s(currentPos, sizeOfShape, tensorDesc.m_shape, sizeOfShape);
738         if (memRet != EOK) {
739             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape.");
740             delete[] serializedData;
741             return OH_NN_MEMORY_ERROR;
742         }
743         currentPos += sizeOfShape;
744 
745         memRet = strcpy_s(currentPos, strlen(tensorDesc.m_name) + 1, tensorDesc.m_name);
746         if (memRet != EOK) {
747             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s name.");
748             delete[] serializedData;
749             return OH_NN_MEMORY_ERROR;
750         }
751         currentPos += strlen(tensorDesc.m_name) + 1;
752     }
753 
754     buffer.data = serializedData;
755     buffer.length = totalSize;
756 
757     return OH_NN_SUCCESS;
758 }
759 
ReleaseDescShape(std::vector<SerializedTensorDesc> & immediateTensorDescs)760 void ReleaseDescShape(std::vector<SerializedTensorDesc>& immediateTensorDescs)
761 {
762     for (auto desc : immediateTensorDescs) {
763         delete[] desc.m_shape;
764     }
765     immediateTensorDescs.clear();
766 }
767 
DeserializedTensorsFromBuffer(const Buffer & buffer,std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs)768 OH_NN_ReturnCode NNCompiler::DeserializedTensorsFromBuffer(
769     const Buffer& buffer, std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs)
770 {
771     std::vector<SerializedTensorDesc> immediateTensorDescs;
772     const char* ptr = static_cast<const char*>(buffer.data);
773     const char* end = ptr + buffer.length;
774     while (ptr < end) {
775         SerializedTensorDesc desc;
776 
777         auto memRet = memcpy_s(&desc.m_dataType, SIZE_OF_DATATYPE, ptr, sizeof(desc.m_dataType));
778         if (memRet != EOK) {
779             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s data type.");
780             ReleaseDescShape(immediateTensorDescs);
781             return OH_NN_MEMORY_ERROR;
782         }
783         ptr += sizeof(desc.m_dataType);
784 
785         memRet = memcpy_s(&desc.m_format, SIZE_OF_FORMAT, ptr, sizeof(desc.m_format));
786         if (memRet != EOK) {
787             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s format.");
788             ReleaseDescShape(immediateTensorDescs);
789             return OH_NN_MEMORY_ERROR;
790         }
791         ptr += sizeof(desc.m_format);
792 
793         memRet = memcpy_s(&desc.m_tensorType, SIZE_OF_TENSOR_TYPE, ptr, sizeof(desc.m_tensorType));
794         if (memRet != EOK) {
795             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s tensor type.");
796             ReleaseDescShape(immediateTensorDescs);
797             return OH_NN_MEMORY_ERROR;
798         }
799         ptr += sizeof(desc.m_tensorType);
800 
801         memRet = memcpy_s(&desc.m_shapeNum, SIZE_OF_SHAPE_NUM, ptr, sizeof(desc.m_shapeNum));
802         if (memRet != EOK) {
803             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape num.");
804             ReleaseDescShape(immediateTensorDescs);
805             return OH_NN_MEMORY_ERROR;
806         }
807         ptr += sizeof(desc.m_shapeNum);
808 
809         desc.m_shape = new (std::nothrow) int32_t[desc.m_shapeNum];
810         if (desc.m_shape == nullptr) {
811             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create shape buffer.");
812             ReleaseDescShape(immediateTensorDescs);
813             return OH_NN_NULL_PTR;
814         }
815         memRet = memcpy_s(desc.m_shape, desc.m_shapeNum * sizeof(int32_t), ptr, desc.m_shapeNum * sizeof(int32_t));
816         if (memRet != EOK) {
817             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape.");
818             ReleaseDescShape(immediateTensorDescs);
819             return OH_NN_MEMORY_ERROR;
820         }
821         ptr += desc.m_shapeNum * sizeof(int32_t);
822 
823         desc.m_name = ptr;
824         ptr += std::strlen(desc.m_name) + 1; // +1 for null terminator
825 
826         immediateTensorDescs.push_back(desc);
827     }
828 
829     OH_NN_ReturnCode ret {OH_NN_SUCCESS};
830     for (const auto& immediateTensorDesc : immediateTensorDescs) {
831         std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType> tensorDescPair;
832         tensorDescPair.first = CreateSharedPtr<TensorDesc>();
833         if (tensorDescPair.first == nullptr) {
834             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create tensor desc.");
835             tensorDescs.clear();
836             ReleaseDescShape(immediateTensorDescs);
837             return OH_NN_NULL_PTR;
838         }
839         ret = immediateTensorDesc.CopyToTensorDesc(*(tensorDescPair.first.get()));
840         if (ret != OH_NN_SUCCESS) {
841             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, error happened when copying "
842                  "SerializedTensorDesc to TensorDesc.");
843             tensorDescs.clear();
844             ReleaseDescShape(immediateTensorDescs);
845             return ret;
846         }
847         tensorDescPair.second = immediateTensorDesc.m_tensorType;
848 
849         tensorDescs.emplace_back(tensorDescPair);
850     }
851 
852     ReleaseDescShape(immediateTensorDescs);
853     return ret;
854 }
855 
856 } // NeuralNetworkRuntime
857 } // OHOS