• 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 constexpr int32_t  NUMBER_CACHE_INFO_MEMBERS = 3;
33 const std::string EXTENSION_KEY_MODEL_NAME = "ModelName";
34 const std::string EXTENSION_KEY_FM_SHARED = "NPU_FM_SHARED";
35 const int OPVERSION_SUBSTR_NUM = 2;
36 const std::string CURRENT_VERSION = "0x00000000";
37 const std::string HIAI_VERSION_PATH = "/data/data/hiai/version";
38 
39 struct SerializedTensorDesc {
40 public:
41     SerializedTensorDesc() = default;
42     ~SerializedTensorDesc() = default;
43 
CopyFromTensorDescOHOS::NeuralNetworkRuntime::__anone3af5d9a0111::SerializedTensorDesc44     OH_NN_ReturnCode CopyFromTensorDesc(const std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>& tensorDesc)
45     {
46         if (tensorDesc.first == nullptr) {
47             LOGE("CopyFromTensorDesc failed, tensor desc is nullptr.");
48             return OH_NN_NULL_PTR;
49         }
50         OH_NN_ReturnCode ret = tensorDesc.first->GetDataType(&m_dataType);
51         if (ret != OH_NN_SUCCESS) {
52             LOGE("CopyFromTensorDesc failed, error happened when getting data type from tensor desc.");
53             return ret;
54         }
55 
56         ret = tensorDesc.first->GetFormat(&m_format);
57         if (ret != OH_NN_SUCCESS) {
58             LOGE("CopyFromTensorDesc failed, error happened when getting format from tensor desc.");
59             return ret;
60         }
61 
62         ret = tensorDesc.first->GetShape(&m_shape, &m_shapeNum);
63         if (ret != OH_NN_SUCCESS) {
64             LOGE("CopyFromTensorDesc failed, error happened when getting shape from tensor desc.");
65             return ret;
66         }
67 
68         ret = tensorDesc.first->GetName(&m_name);
69         if (ret != OH_NN_SUCCESS) {
70             LOGE("CopyFromTensorDesc failed, error happened when getting name from tensor desc.");
71             return ret;
72         }
73 
74         m_tensorType = tensorDesc.second;
75 
76         return ret;
77     }
78 
CopyToTensorDescOHOS::NeuralNetworkRuntime::__anone3af5d9a0111::SerializedTensorDesc79     OH_NN_ReturnCode CopyToTensorDesc(TensorDesc& tensorDesc) const
80     {
81         OH_NN_ReturnCode ret = tensorDesc.SetDataType(m_dataType);
82         if (ret != OH_NN_SUCCESS) {
83             LOGE("CopyToTensorDesc failed, error happened when setting data type to tensor desc.");
84             return ret;
85         }
86 
87         ret = tensorDesc.SetFormat(m_format);
88         if (ret != OH_NN_SUCCESS) {
89             LOGE("CopyToTensorDesc failed, error happened when setting format to tensor desc.");
90             return ret;
91         }
92 
93         ret = tensorDesc.SetShape(m_shape, m_shapeNum);
94         if (ret != OH_NN_SUCCESS) {
95             LOGE("CopyToTensorDesc failed, error happened when setting shape to tensor desc.");
96             return ret;
97         }
98 
99         ret = tensorDesc.SetName(m_name);
100         if (ret != OH_NN_SUCCESS) {
101             LOGE("CopyToTensorDesc failed, error happened when setting name to tensor desc.");
102         }
103 
104         return ret;
105     }
106 
107 public:
108     OH_NN_DataType m_dataType{OH_NN_UNKNOWN};
109     OH_NN_Format m_format{OH_NN_FORMAT_NONE};
110     OH_NN_TensorType m_tensorType{OH_NN_TENSOR};
111     size_t m_shapeNum{0};
112     int32_t* m_shape{nullptr};
113     const char* m_name{nullptr}; // null-terminated
114 };
115 
116 const size_t SIZE_OF_DATATYPE = sizeof(SerializedTensorDesc::m_dataType);
117 const size_t SIZE_OF_FORMAT = sizeof(SerializedTensorDesc::m_format);
118 const size_t SIZE_OF_TENSOR_TYPE = sizeof(SerializedTensorDesc::m_tensorType);
119 const size_t SIZE_OF_SHAPE_NUM = sizeof(SerializedTensorDesc::m_shapeNum);
120 } // namespace
121 
NNCompiler(std::shared_ptr<Device> device,size_t backendID)122 NNCompiler::NNCompiler(std::shared_ptr<Device> device, size_t backendID)
123     : m_device(device),
124     m_backendID(backendID) {}
125 
NNCompiler(const void * model,std::shared_ptr<Device> device,size_t backendID)126 NNCompiler::NNCompiler(const void* model, std::shared_ptr<Device> device, size_t backendID)
127     : m_device(device),
128     m_backendID(backendID)
129 {
130     m_innerModel = const_cast<InnerModel*>(reinterpret_cast<const InnerModel*>(model));
131     m_liteGraph = m_innerModel->GetLiteGraphs();
132     m_inputTensorDescs = m_innerModel->GetInputTensorDescs();
133     m_outputTensorDescs = m_innerModel->GetOutputTensorDescs();
134     m_metaGraph = m_innerModel->GetMetaGraph();
135     m_extensionConfig = m_innerModel->GetExtensionConfig();
136 }
137 
~NNCompiler()138 NNCompiler::~NNCompiler()
139 {
140     if (m_preparedModel != nullptr) {
141         m_preparedModel.reset();
142     }
143     m_inputTensorDescs.clear();
144     m_outputTensorDescs.clear();
145 }
146 
GetBackendID() const147 size_t NNCompiler::GetBackendID() const
148 {
149     return m_backendID;
150 }
151 
SetCacheDir(const std::string & cacheModelPath,uint32_t version)152 OH_NN_ReturnCode NNCompiler::SetCacheDir(const std::string& cacheModelPath, uint32_t version)
153 {
154     if (m_device == nullptr) {
155         LOGE("[NNCompiler] SetCacheDir failed, m_device is nullptr");
156         return OH_NN_OPERATION_FORBIDDEN;
157     }
158 
159     bool isSupportedCache {false};
160     OH_NN_ReturnCode ret = m_device->IsModelCacheSupported(isSupportedCache);
161     if (ret != OH_NN_SUCCESS) {
162         LOGE("[NNCompiler] SetCacheDir failed, fail to call device.");
163         return ret;
164     }
165 
166     if (!isSupportedCache && !cacheModelPath.empty()) {
167         LOGE("[NNCompiler] SetCacheDir failed, this device is not support cache setting.");
168         return OH_NN_OPERATION_FORBIDDEN;
169     }
170 
171     m_cachePath = cacheModelPath;
172     m_cacheVersion = version;
173 
174     return OH_NN_SUCCESS;
175 }
176 
SetPerformance(OH_NN_PerformanceMode performance)177 OH_NN_ReturnCode NNCompiler::SetPerformance(OH_NN_PerformanceMode performance)
178 {
179     if (m_device == nullptr) {
180         LOGE("[NNCompiler] SetPerformance failed, m_device is nullptr");
181         return OH_NN_OPERATION_FORBIDDEN;
182     }
183 
184     bool isSupportedPerformance {false};
185     OH_NN_ReturnCode ret = m_device->IsPerformanceModeSupported(isSupportedPerformance);
186     if (ret != OH_NN_SUCCESS) {
187         LOGE("[NNCompiler] SetPerformance failed, fail to call device.");
188         return OH_NN_FAILED;
189     }
190 
191     if (!isSupportedPerformance && (performance != OH_NN_PERFORMANCE_NONE)) {
192         LOGE("[NNCompiler] SetPerformance failed, this device is not support performance setting.");
193         return OH_NN_OPERATION_FORBIDDEN;
194     }
195 
196     if (!Validation::ValidatePerformanceMode(performance)) {
197         LOGE("[NNCompiler] SetPerformance failed, performance=%{public}d is invalid", performance);
198         return OH_NN_INVALID_PARAMETER;
199     }
200 
201     m_performance = performance;
202     return OH_NN_SUCCESS;
203 }
204 
SetPriority(OH_NN_Priority priority)205 OH_NN_ReturnCode NNCompiler::SetPriority(OH_NN_Priority priority)
206 {
207     if (m_device == nullptr) {
208         LOGE("[NNCompiler] SetPriority failed, m_device is nullptr");
209         return OH_NN_OPERATION_FORBIDDEN;
210     }
211 
212     bool isSupportedPriority {false};
213     OH_NN_ReturnCode ret = m_device->IsPrioritySupported(isSupportedPriority);
214     if (ret != OH_NN_SUCCESS) {
215         LOGE("[NNCompiler] SetPriority failed, fail to call device.");
216         return ret;
217     }
218 
219     if (!isSupportedPriority && (priority != OH_NN_PRIORITY_NONE)) {
220         LOGE("[NNCompiler] SetPriority failed, this device is not support priority setting.");
221         return OH_NN_OPERATION_FORBIDDEN;
222     }
223 
224     if (!Validation::ValidatePriority(priority)) {
225         LOGE("[NNCompiler] SetPriority failed, priority=%{public}d is invalid.", priority);
226         return OH_NN_INVALID_PARAMETER;
227     }
228 
229     m_priority = priority;
230     return OH_NN_SUCCESS;
231 }
232 
SetEnableFp16(bool isFp16)233 OH_NN_ReturnCode NNCompiler::SetEnableFp16(bool isFp16)
234 {
235     if (m_device == nullptr) {
236         LOGE("[NNCompiler] SetEnableFp16 failed, m_device is nullptr");
237         return OH_NN_OPERATION_FORBIDDEN;
238     }
239 
240     bool isSupportedFp16 {false};
241     OH_NN_ReturnCode ret = m_device->IsFloat16PrecisionSupported(isSupportedFp16);
242     if (ret != OH_NN_SUCCESS) {
243         LOGE("[NNCompiler] SetEnableFp16 failed, fail to call device.");
244         return ret;
245     }
246 
247     if (!isSupportedFp16 && isFp16) {
248         LOGE("[NNCompiler] SetEnableFp16 failed, this device is not support float16 precision setting.");
249         return OH_NN_OPERATION_FORBIDDEN;
250     }
251 
252     m_enableFp16 = isFp16;
253     return OH_NN_SUCCESS;
254 }
255 
IsBuild() const256 bool NNCompiler::IsBuild() const
257 {
258     return m_isBuild;
259 }
260 
IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph> & liteGraph,bool & isSupportedModel) const261 OH_NN_ReturnCode NNCompiler::IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph>& liteGraph,
262                                               bool& isSupportedModel) const
263 {
264     std::vector<bool> supportedList;
265     OH_NN_ReturnCode ret = m_device->GetSupportedOperation(liteGraph, supportedList);
266     if (ret != OH_NN_SUCCESS) {
267         LOGE("[NNCompiler] Build failed, error happened when getting supported operation.");
268         return ret;
269     }
270 
271     bool isNotSupport = std::any_of(supportedList.begin(), supportedList.end(), [](bool isSupport) {
272         return !isSupport;
273     });
274     if (isNotSupport) {
275         LOGE("[NNCompiler] Build failed, current device not support the model, device id: %{public}zu.", m_backendID);
276         isSupportedModel = false;
277         return OH_NN_FAILED;
278     }
279 
280     isSupportedModel = true;
281     return OH_NN_SUCCESS;
282 }
283 
CheckModelParameter() const284 OH_NN_ReturnCode NNCompiler::CheckModelParameter() const
285 {
286     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
287     if (m_innerModel == nullptr) {
288         LOGW("[NNCompiler] Restoring from cache not need to check model.");
289         return OH_NN_SUCCESS;
290     }
291 
292     // m_innerModel is not constructed completely.
293     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
294         LOGE("[NNCompiler] LiteGraph and metaGraph are empty, m_innerModel is not constructed completely.");
295         return OH_NN_INVALID_PARAMETER;
296     }
297 
298     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
299         LOGE("[NNCompiler] Both LiteGraph and metaGraph are not empty.");
300         return OH_NN_INVALID_PARAMETER;
301     }
302 
303     return OH_NN_SUCCESS;
304 }
305 
IsOfflineModel(bool & isOfflineModel) const306 OH_NN_ReturnCode NNCompiler::IsOfflineModel(bool& isOfflineModel) const
307 {
308     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
309     if (m_innerModel == nullptr) {
310         LOGW("[NNCompiler] Restoring from cache not need to judge offline model.");
311         return OH_NN_SUCCESS;
312     }
313 
314     isOfflineModel = false; // Initialize the returned value
315     if (m_metaGraph != nullptr) {
316         isOfflineModel = false;
317         return OH_NN_SUCCESS;
318     }
319 
320     if (m_liteGraph->all_nodes_.size() == 0) {
321         LOGE("[NNCompiler] Find empty node in the model.");
322         return OH_NN_INVALID_PARAMETER;
323     }
324 
325     // If the model consists of more than 1 node, it will not be considered as offline model.
326     if (m_liteGraph->all_nodes_.size() > 1) {
327         isOfflineModel = false;
328         return OH_NN_SUCCESS;
329     }
330 
331     const mindspore::lite::LiteGraph::Node* pNode = m_liteGraph->all_nodes_[0];
332     if (pNode == nullptr) {
333         LOGE("[NNCompiler] Find invalid node in the model.");
334         return OH_NN_NULL_PTR;
335     }
336 
337     const mindspore::lite::NodeType& nodeType = mindspore::lite::MindIR_Primitive_GetType(pNode->primitive_);
338     if (nodeType == mindspore::lite::NodeType::NODE_TYPE_CUSTOM) {
339         isOfflineModel = true;
340     }
341 
342     return OH_NN_SUCCESS;
343 }
344 
BuildOfflineModel()345 OH_NN_ReturnCode NNCompiler::BuildOfflineModel()
346 {
347     ModelConfig config {m_enableFp16, m_performance, m_priority};
348     OH_NN_ReturnCode ret = m_device->PrepareOfflineModel(m_liteGraph, config, m_preparedModel);
349     if (ret != OH_NN_SUCCESS) {
350         LOGE("[NNCompiler] Preparing model failed when building from offline model.");
351         return ret;
352     }
353 
354     return OH_NN_SUCCESS;
355 }
356 
NormalBuild()357 OH_NN_ReturnCode NNCompiler::NormalBuild()
358 {
359     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
360         LOGE("[NNCompiler] Build failed, both liteGraph and metaGraph are nullptr.");
361         return OH_NN_INVALID_PARAMETER;
362     }
363 
364     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
365         LOGE("[NNCompiler] Build failed, neither liteGraph nor metaGraph are nullptr.");
366         return OH_NN_INVALID_PARAMETER;
367     }
368 
369     // 判断是否支持模型
370     bool isSupportedModel = true;
371     OH_NN_ReturnCode ret = IsSupportedModel(m_liteGraph, isSupportedModel);
372     if (ret != OH_NN_SUCCESS) {
373         LOGE("[NNCompiler] Build failed, error happened when judge if support the model.");
374         return ret;
375     } else if (!isSupportedModel) {
376         LOGE("[NNCompiler] Build failed, current device not support the model.");
377         return OH_NN_FAILED;
378     }
379 
380     ModelConfig config {m_enableFp16, static_cast<OH_NN_PerformanceMode>(m_performance),
381         static_cast<OH_NN_Priority>(m_priority), m_cachePath, m_extensionConfig};
382     if (m_liteGraph != nullptr) {
383         ret = m_device->PrepareModel(m_liteGraph, config, m_preparedModel);
384     }
385     if (m_metaGraph != nullptr) {
386         ret = m_device->PrepareModel(m_metaGraph, config, m_preparedModel);
387     }
388     if (ret != OH_NN_SUCCESS) {
389         LOGE("[NNCompiler] Build failed, fail to prepare model when normally building.");
390         return ret;
391     }
392     m_isBuild = true;
393 
394     // 保存cache
395     if (!m_cachePath.empty()) {
396         ret = SaveToCacheFile();
397         if (ret != OH_NN_SUCCESS) {
398             LOGE("[NNCompiler] Build success, but fail to save cache to file.");
399             return ret;
400         }
401     }
402 
403     return OH_NN_SUCCESS;
404 }
405 
Build()406 OH_NN_ReturnCode NNCompiler::Build()
407 {
408     if (m_isBuild) {
409         LOGE("[NNCompiler] Build failed, cannot build again.");
410         return OH_NN_OPERATION_FORBIDDEN;
411     }
412 
413     if (m_device == nullptr) {
414         LOGE("[NNCompiler] Build failed, the m_device is nullptr.");
415         return OH_NN_OPERATION_FORBIDDEN;
416     }
417 
418     OH_NN_ReturnCode ret = CheckModelParameter();
419     if (ret != OH_NN_SUCCESS) {
420         LOGE("[NNCompiler] CheckModelParameter failed, some error happened when checking model parameter.");
421         return ret;
422     }
423 
424     // Prepare from offline model.
425     bool isOfflineModel {false};
426     ret = IsOfflineModel(isOfflineModel);
427     if (ret != OH_NN_SUCCESS) {
428         LOGE("[NNCompiler] Build failed, fail to identify the offline model.");
429         return ret;
430     }
431 
432     if (isOfflineModel) {
433         ret = BuildOfflineModel();
434         if (ret != OH_NN_SUCCESS) {
435             LOGE("[NNCompiler] Build failed, Failed to build offline model.");
436             return ret;
437         }
438 
439         m_isBuild = true;
440         return OH_NN_SUCCESS;
441     }
442 
443     ret = OnlineBuild();
444     if (ret != OH_NN_SUCCESS) {
445         LOGE("[NNCompiler] OnlineBuild failed, Failed to build model online.");
446         return ret;
447     }
448 
449     return OH_NN_SUCCESS;
450 }
451 
OnlineBuild()452 OH_NN_ReturnCode NNCompiler::OnlineBuild()
453 {
454     // cache存在,从cache直接复原prepareModel、input/output TensorDesc
455     OH_NN_ReturnCode ret = RestoreFromCacheFile();
456     if (ret != OH_NN_SUCCESS) {
457         LOGW("[NNCompiler] cache file is failed, to delete cache file.");
458         char path[PATH_MAX];
459         if (realpath(m_cachePath.c_str(), path) == nullptr) {
460             LOGW("[NNCompiledCache] WriteCacheInfo failed, fail to get the real path of cacheDir.");
461         }
462 
463         std::string cachePath = path;
464         std::string cacheInfo = cachePath + "/" + m_extensionConfig.modelName + "cache_info.nncache";
465         if (std::filesystem::exists(cacheInfo)) {
466             std::filesystem::remove_all(cacheInfo);
467         }
468     }
469 
470     if (ret == OH_NN_OPERATION_FORBIDDEN) {
471         LOGE("[NNCompiler] Build failed, operation is forbidden.");
472         return ret;
473     }
474     if (ret == OH_NN_SUCCESS) {
475         LOGI("[NNCompiler] Build success, restore from cache file.");
476         m_isBuild = true;
477     }
478 
479     // cache不存在或cache restore失败,走在线构图
480     if (!m_isBuild) {
481         ret = NormalBuild();
482         if (ret != OH_NN_SUCCESS) {
483             LOGE("[NNCompiler] Build failed, fail to build model online.");
484             return ret;
485         }
486     }
487 
488     return OH_NN_SUCCESS;
489 }
490 
ReleaseBuffer(std::vector<Buffer> & buffers) const491 void NNCompiler::ReleaseBuffer(std::vector<Buffer>& buffers) const
492 {
493     for (size_t i = 0; i < buffers.size(); ++i) {
494         // release tensor buffer which is allocated by new method.
495         delete[] reinterpret_cast<char*>(buffers[i].data);
496     }
497     buffers.clear();
498 }
499 
ReleaseBufferByDevice(std::vector<Buffer> & buffers) const500 void NNCompiler::ReleaseBufferByDevice(std::vector<Buffer>& buffers) const
501 {
502     for (size_t i = 0; i < buffers.size(); ++i) {
503         // release cache buffer which is allocated by idevice.
504         m_device->ReleaseBuffer(buffers[i].data);
505     }
506     buffers.clear();
507 }
508 
SaveToCacheFile() const509 OH_NN_ReturnCode NNCompiler::SaveToCacheFile() const
510 {
511     if (m_cachePath.empty()) {
512         LOGE("[NNCompiler] SaveToCacheFile failed, m_cachePath is empty.");
513         return OH_NN_INVALID_PARAMETER;
514     }
515 
516     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
517         LOGE("[NNCompiler] SaveToCacheFile failed, cache version is invalid. Please set a valid cache version.");
518         return OH_NN_INVALID_PARAMETER;
519     }
520 
521     if (m_preparedModel == nullptr) {
522         LOGE("[NNCompiler] SaveToCacheFile failed, m_preparedModel is nullptr. Please construct prepareModel first.");
523         return OH_NN_FAILED;
524     }
525 
526     std::vector<Buffer> caches;
527     std::vector<Buffer> tensorBuffers;
528     OH_NN_ReturnCode ret = m_preparedModel->ExportModelCache(caches);
529     if (ret != OH_NN_SUCCESS) {
530         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when exporting model cache.");
531         return ret;
532     }
533 
534     NNCompiledCache compiledCache;
535     ret = compiledCache.SetBackend(m_backendID);
536     if (ret != OH_NN_SUCCESS) {
537         LOGE("[NNCompiler] SaveToCacheFile failed, fail to set backend.");
538         return ret;
539     }
540 
541     Buffer inputTensorDescBuffer;
542     ret = SerializeTensorsToBuffer(m_inputTensorDescs, inputTensorDescBuffer);
543     if (ret != OH_NN_SUCCESS) {
544         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing input tensor desc.");
545         return ret;
546     }
547     caches.emplace_back(inputTensorDescBuffer);
548     tensorBuffers.emplace_back(inputTensorDescBuffer);
549 
550     Buffer outputTensorDescBuffer;
551     ret = SerializeTensorsToBuffer(m_outputTensorDescs, outputTensorDescBuffer);
552     if (ret != OH_NN_SUCCESS) {
553         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing output tensor desc.");
554         ReleaseBuffer(tensorBuffers);
555         return ret;
556     }
557     caches.emplace_back(outputTensorDescBuffer);
558     tensorBuffers.emplace_back(outputTensorDescBuffer);
559 
560     compiledCache.SetModelName(m_extensionConfig.modelName);
561     ret = compiledCache.Save(caches, m_cachePath, m_cacheVersion);
562     if (ret != OH_NN_SUCCESS) {
563         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when saving model cache.");
564         ReleaseBuffer(tensorBuffers);
565         return ret;
566     }
567 
568     ReleaseBuffer(tensorBuffers);
569     LOGI("[NNCompiler] Export model cache successfully.");
570     return OH_NN_SUCCESS;
571 }
572 
RestoreFromCacheFile()573 OH_NN_ReturnCode NNCompiler::RestoreFromCacheFile()
574 {
575     if (m_cachePath.empty()) {
576         LOGE("[NNCompiler] RestoreFromCacheFile failed, path is empty.");
577         return OH_NN_INVALID_PARAMETER;
578     }
579 
580     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
581         LOGE("[NNCompiler] RestoreFromCacheFile failed, cache version is invalid. Please set a valid cache version.");
582         return OH_NN_INVALID_PARAMETER;
583     }
584 
585     if (m_preparedModel != nullptr) {
586         LOGE("[NNCompiler] RestoreFromCacheFile failed, m_preparedModel is not nullptr.");
587         return OH_NN_FAILED;
588     }
589 
590     NNCompiledCache compiledCache;
591     OH_NN_ReturnCode ret = compiledCache.SetBackend(m_backendID);
592     if (ret != OH_NN_SUCCESS) {
593         LOGE("[NNCompiler] RestoreFromCacheFile failed, fail to set backend.");
594         return ret;
595     }
596 
597     std::vector<Buffer> caches;
598     compiledCache.SetModelName(m_extensionConfig.modelName);
599     ret = compiledCache.Restore(m_cachePath, m_cacheVersion, caches);
600     if (ret != OH_NN_SUCCESS) {
601         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when restoring model cache.");
602         ReleaseBufferByDevice(caches);
603         return ret;
604     }
605 
606     size_t cacheNum = caches.size();
607     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> inputTensorDescs;
608     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_INPUT_TENSORDESC_OFFSET], inputTensorDescs);
609     if (ret != OH_NN_SUCCESS) {
610         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing input tensor desc.");
611         ReleaseBufferByDevice(caches);
612         return ret;
613     }
614 
615     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> outputTensorDescs;
616     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_OUTPUT_TENSORDESC_OFFSET], outputTensorDescs);
617     if (ret != OH_NN_SUCCESS) {
618         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing output tensor desc.");
619         ReleaseBufferByDevice(caches);
620         return ret;
621     }
622 
623     ModelConfig config;
624     config.enableFloat16 = m_enableFp16;
625     config.mode = m_performance;
626     config.priority = m_priority;
627     config.extensionConfig.isNpuFmShared = m_extensionConfig.isNpuFmShared;
628     std::vector<Buffer> modelOnlyCaches(caches.begin(), caches.end() - CACHE_INPUT_TENSORDESC_OFFSET);
629     bool isUpdatable = false;
630     ret = m_device->PrepareModelFromModelCache(modelOnlyCaches, config, m_preparedModel, isUpdatable);
631     if (ret != OH_NN_SUCCESS) {
632         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when preparing model from cache.");
633         ReleaseBufferByDevice(caches);
634         return ret;
635     }
636 
637     if (isUpdatable) {
638         LOGI("isUpdatable is true");
639 
640         std::string currentVersion = CURRENT_VERSION;
641         char versionPath[PATH_MAX];
642         if (realpath(HIAI_VERSION_PATH.c_str(), versionPath) != nullptr) {
643             std::ifstream inf(versionPath);
644             if (inf.is_open()) {
645                 getline(inf, currentVersion);
646             }
647             inf.close();
648         }
649         int currentOpVersion = std::stoi(currentVersion.substr(OPVERSION_SUBSTR_NUM));
650 
651         NNCompiledCacheInfo modelCacheInfo;
652         std::string cacheInfoPath = m_cachePath + "/" + m_extensionConfig.modelName + "cache_info.nncache";
653         ret = compiledCache.CheckCacheInfo(modelCacheInfo, cacheInfoPath);
654         if (ret != OH_NN_SUCCESS) {
655             LOGE("[NNCompiledCache] isUpdatable is true to check cache info failed.");
656             return ret;
657         }
658 
659         LOGI("isUpdatable currentOpVersion is: %{public}d", currentOpVersion);
660         LOGI("isUpdatable modelCacheInfo opVersion is %{public}d", static_cast<int>(modelCacheInfo.opVersion));
661 
662         if (currentOpVersion > modelCacheInfo.opVersion) {
663             const size_t cacheNumber = caches.size();
664             uint32_t cacheSize = NUMBER_CACHE_INFO_MEMBERS + cacheNumber + 1;
665             uint32_t infoCharNumber = cacheSize * sizeof(int64_t);
666 
667             std::unique_ptr<int64_t[]> cacheInfo = CreateUniquePtr<int64_t[]>(cacheSize);
668             if (cacheInfo == nullptr) {
669                 LOGE("[NNCompiledCache] isUpdatable is true to create unique failed.");
670                 return OH_NN_MEMORY_ERROR;
671             }
672 
673             auto cacheInfoPtr = cacheInfo.get();
674             *cacheInfoPtr++ = modelCacheInfo.fileNumber;
675             *cacheInfoPtr++ = modelCacheInfo.version - 1;
676             *cacheInfoPtr++ = modelCacheInfo.deviceId;
677 
678             for (size_t i = 0; i < modelCacheInfo.modelCheckSum.size(); ++i) {
679                 *cacheInfoPtr++ = static_cast<int64_t>(modelCacheInfo.modelCheckSum[i]);
680             }
681 
682             *cacheInfoPtr++ = currentOpVersion;
683 
684             ret = compiledCache.WriteCacheInfo(infoCharNumber, cacheInfo, m_cachePath);
685             if (ret != OH_NN_SUCCESS) {
686                 LOGE("[NNCompiledCache] isUpdatable is true to write cache info failed.");
687                 return ret;
688             }
689         }
690     }
691 
692     ReleaseBufferByDevice(caches);
693 
694     m_inputTensorDescs = inputTensorDescs;
695     m_outputTensorDescs = outputTensorDescs;
696     LOGI("[NNCompiler] Restore model cache successfully.");
697     return OH_NN_SUCCESS;
698 }
699 
SaveToCacheBuffer(const void * buffer,size_t length,size_t * modelSize) const700 OH_NN_ReturnCode NNCompiler::SaveToCacheBuffer(const void* buffer, size_t length, size_t* modelSize) const
701 {
702     LOGE("[NNCompiler] SaveToCacheBuffer is not supported currently.");
703     return OH_NN_UNSUPPORTED;
704 }
705 
RestoreFromCacheBuffer(const void * buffer,size_t length)706 OH_NN_ReturnCode NNCompiler::RestoreFromCacheBuffer(const void* buffer, size_t length)
707 {
708     LOGE("[NNCompiler] RestoreFromCacheBuffer is not supported currently.");
709     return OH_NN_UNSUPPORTED;
710 }
711 
SetExtensionConfig(const std::unordered_map<std::string,std::vector<char>> & configs)712 OH_NN_ReturnCode NNCompiler::SetExtensionConfig(const std::unordered_map<std::string, std::vector<char>>& configs)
713 {
714     if (configs.find(EXTENSION_KEY_MODEL_NAME) != configs.end()) {
715         std::vector<char> value = configs.at(EXTENSION_KEY_MODEL_NAME);
716         if (value.empty()) {
717             LOGE("[NNCompiler] SetExtensionConfig get empty model name from configs");
718             return OH_NN_INVALID_PARAMETER;
719         }
720         m_extensionConfig.modelName.assign(value.data(), value.data() + value.size());
721         LOGI("[NNCompiler] SetExtensionConfig get model name:%{public}s.", m_extensionConfig.modelName.c_str());
722     }
723     if (configs.find(EXTENSION_KEY_FM_SHARED) != configs.end()) {
724         m_extensionConfig.isNpuFmShared = true;
725         LOGI("[NNCompiler] SetExtensionConfig NpuFmShared enabled.");
726     }
727     return OH_NN_SUCCESS;
728 }
729 
SetOptions(const std::vector<std::shared_ptr<void>> & options)730 OH_NN_ReturnCode NNCompiler::SetOptions(const std::vector<std::shared_ptr<void>>& options)
731 {
732     LOGE("[NNCompiler] SetOptions is not supported for NN compiler currently.");
733     return OH_NN_UNSUPPORTED;
734 }
735 
GetModelName(std::string & modelName)736 OH_NN_ReturnCode NNCompiler::GetModelName(std::string& modelName)
737 {
738     modelName = m_extensionConfig.modelName;
739     return OH_NN_SUCCESS;
740 }
741 
CreateExecutor()742 NNExecutor* NNCompiler::CreateExecutor()
743 {
744     if (m_device == nullptr) {
745         LOGE("[NNCompiler] CreateExecutor failed, m_device is nullptr");
746         return nullptr;
747     }
748 
749     if (m_preparedModel == nullptr) {
750         LOGE("[NNCompiler] CreateExecutor failed, m_preparedModel is nullptr");
751         return nullptr;
752     }
753 
754     if (m_inputTensorDescs.empty()) {
755         LOGE("[NNCompiler] CreateExecutor failed, m_inputTensorDescs is empty");
756         return nullptr;
757     }
758 
759     if (m_outputTensorDescs.empty()) {
760         LOGE("[NNCompiler] CreateExecutor failed, m_outputTensorDescs is empty");
761         return nullptr;
762     }
763 
764     NNExecutor* nnExecutor = new (std::nothrow) NNExecutor(
765         m_backendID, m_device, m_preparedModel, m_inputTensorDescs, m_outputTensorDescs);
766     if (nnExecutor == nullptr) {
767         LOGE("[NNCompiler] CreateExecutor failed, error happend when allocating NN Executor.");
768         return nullptr;
769     }
770 
771     return nnExecutor;
772 }
773 
SerializeTensorsToBuffer(const std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs,Buffer & buffer) const774 OH_NN_ReturnCode NNCompiler::SerializeTensorsToBuffer(
775     const std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs, Buffer& buffer) const
776 {
777     std::vector<SerializedTensorDesc> immediateTensorDescs;
778     OH_NN_ReturnCode ret = OH_NN_SUCCESS;
779     for (const auto& tensorDesc : tensorDescs) {
780         SerializedTensorDesc immediateTensorDesc;
781         ret = immediateTensorDesc.CopyFromTensorDesc(tensorDesc);
782         if (ret != OH_NN_SUCCESS) {
783             LOGE("[NNCompiler] SerializeInputsToBuffer failed, error happened when copying tensorDesc to "
784                  "SerializedTensorDesc.");
785             immediateTensorDescs.clear();
786             return ret;
787         }
788         immediateTensorDescs.emplace_back(immediateTensorDesc);
789     }
790 
791     size_t totalSize = 0;
792     for (const auto& tensorDesc : immediateTensorDescs) {
793         totalSize += SIZE_OF_DATATYPE;
794         totalSize += SIZE_OF_FORMAT;
795         totalSize += SIZE_OF_TENSOR_TYPE;
796         totalSize += SIZE_OF_SHAPE_NUM;
797         totalSize += tensorDesc.m_shapeNum * sizeof(int32_t);
798         totalSize += strlen(tensorDesc.m_name) + 1;
799     }
800 
801     // Allocate memory for the serialized data
802     char* serializedData = new (std::nothrow) char[totalSize];
803     if (serializedData == nullptr) {
804         LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to create serialized data.");
805         return OH_NN_NULL_PTR;
806     }
807     char* currentPos = serializedData;
808 
809     // Serialize each tensor description
810     for (const auto& tensorDesc : immediateTensorDescs) {
811         auto memRet = memcpy_s(currentPos, SIZE_OF_DATATYPE, &tensorDesc.m_dataType, SIZE_OF_DATATYPE);
812         if (memRet != EOK) {
813             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s data type.");
814             delete[] serializedData;
815             return OH_NN_MEMORY_ERROR;
816         }
817         currentPos += SIZE_OF_DATATYPE;
818 
819         memRet = memcpy_s(currentPos, SIZE_OF_FORMAT, &tensorDesc.m_format, SIZE_OF_FORMAT);
820         if (memRet != EOK) {
821             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s format.");
822             delete[] serializedData;
823             return OH_NN_MEMORY_ERROR;
824         }
825         currentPos += SIZE_OF_FORMAT;
826 
827         memRet = memcpy_s(currentPos, SIZE_OF_TENSOR_TYPE, &tensorDesc.m_tensorType, SIZE_OF_TENSOR_TYPE);
828         if (memRet != EOK) {
829             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s tensor type.");
830             delete[] serializedData;
831             return OH_NN_MEMORY_ERROR;
832         }
833         currentPos += SIZE_OF_TENSOR_TYPE;
834 
835         memRet = memcpy_s(currentPos, SIZE_OF_SHAPE_NUM, &tensorDesc.m_shapeNum, SIZE_OF_SHAPE_NUM);
836         if (memRet != EOK) {
837             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape num.");
838             delete[] serializedData;
839             return OH_NN_MEMORY_ERROR;
840         }
841         currentPos += SIZE_OF_SHAPE_NUM;
842 
843         size_t sizeOfShape = tensorDesc.m_shapeNum * sizeof(int32_t);
844         memRet = memcpy_s(currentPos, sizeOfShape, tensorDesc.m_shape, sizeOfShape);
845         if (memRet != EOK) {
846             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape.");
847             delete[] serializedData;
848             return OH_NN_MEMORY_ERROR;
849         }
850         currentPos += sizeOfShape;
851 
852         memRet = strcpy_s(currentPos, strlen(tensorDesc.m_name) + 1, tensorDesc.m_name);
853         if (memRet != EOK) {
854             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s name.");
855             delete[] serializedData;
856             return OH_NN_MEMORY_ERROR;
857         }
858         currentPos += strlen(tensorDesc.m_name) + 1;
859     }
860 
861     buffer.data = serializedData;
862     buffer.length = totalSize;
863 
864     return OH_NN_SUCCESS;
865 }
866 
ReleaseDescShape(std::vector<SerializedTensorDesc> & immediateTensorDescs)867 void ReleaseDescShape(std::vector<SerializedTensorDesc>& immediateTensorDescs)
868 {
869     for (auto desc : immediateTensorDescs) {
870         delete[] desc.m_shape;
871     }
872     immediateTensorDescs.clear();
873 }
874 
DeserializedTensorsFromBuffer(const Buffer & buffer,std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs)875 OH_NN_ReturnCode NNCompiler::DeserializedTensorsFromBuffer(
876     const Buffer& buffer, std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs)
877 {
878     std::vector<SerializedTensorDesc> immediateTensorDescs;
879     const char* ptr = static_cast<const char*>(buffer.data);
880     const char* end = ptr + buffer.length;
881     while (ptr < end) {
882         SerializedTensorDesc desc;
883 
884         auto memRet = memcpy_s(&desc.m_dataType, SIZE_OF_DATATYPE, ptr, sizeof(desc.m_dataType));
885         if (memRet != EOK) {
886             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s data type.");
887             ReleaseDescShape(immediateTensorDescs);
888             return OH_NN_MEMORY_ERROR;
889         }
890         ptr += sizeof(desc.m_dataType);
891 
892         memRet = memcpy_s(&desc.m_format, SIZE_OF_FORMAT, ptr, sizeof(desc.m_format));
893         if (memRet != EOK) {
894             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s format.");
895             ReleaseDescShape(immediateTensorDescs);
896             return OH_NN_MEMORY_ERROR;
897         }
898         ptr += sizeof(desc.m_format);
899 
900         memRet = memcpy_s(&desc.m_tensorType, SIZE_OF_TENSOR_TYPE, ptr, sizeof(desc.m_tensorType));
901         if (memRet != EOK) {
902             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s tensor type.");
903             ReleaseDescShape(immediateTensorDescs);
904             return OH_NN_MEMORY_ERROR;
905         }
906         ptr += sizeof(desc.m_tensorType);
907 
908         memRet = memcpy_s(&desc.m_shapeNum, SIZE_OF_SHAPE_NUM, ptr, sizeof(desc.m_shapeNum));
909         if (memRet != EOK) {
910             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape num.");
911             ReleaseDescShape(immediateTensorDescs);
912             return OH_NN_MEMORY_ERROR;
913         }
914         ptr += sizeof(desc.m_shapeNum);
915 
916         desc.m_shape = new (std::nothrow) int32_t[desc.m_shapeNum];
917         if (desc.m_shape == nullptr) {
918             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create shape buffer.");
919             ReleaseDescShape(immediateTensorDescs);
920             return OH_NN_NULL_PTR;
921         }
922         memRet = memcpy_s(desc.m_shape, desc.m_shapeNum * sizeof(int32_t), ptr, desc.m_shapeNum * sizeof(int32_t));
923         if (memRet != EOK) {
924             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape.");
925             ReleaseDescShape(immediateTensorDescs);
926             return OH_NN_MEMORY_ERROR;
927         }
928         ptr += desc.m_shapeNum * sizeof(int32_t);
929 
930         desc.m_name = ptr;
931         ptr += std::strlen(desc.m_name) + 1; // +1 for null terminator
932 
933         immediateTensorDescs.push_back(desc);
934     }
935 
936     OH_NN_ReturnCode ret {OH_NN_SUCCESS};
937     for (const auto& immediateTensorDesc : immediateTensorDescs) {
938         std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType> tensorDescPair;
939         tensorDescPair.first = CreateSharedPtr<TensorDesc>();
940         if (tensorDescPair.first == nullptr) {
941             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create tensor desc.");
942             tensorDescs.clear();
943             ReleaseDescShape(immediateTensorDescs);
944             return OH_NN_NULL_PTR;
945         }
946         ret = immediateTensorDesc.CopyToTensorDesc(*(tensorDescPair.first.get()));
947         if (ret != OH_NN_SUCCESS) {
948             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, error happened when copying "
949                  "SerializedTensorDesc to TensorDesc.");
950             tensorDescs.clear();
951             ReleaseDescShape(immediateTensorDescs);
952             return ret;
953         }
954         tensorDescPair.second = immediateTensorDesc.m_tensorType;
955 
956         tensorDescs.emplace_back(tensorDescPair);
957     }
958 
959     ReleaseDescShape(immediateTensorDescs);
960     return ret;
961 }
962 
963 } // NeuralNetworkRuntime
964 } // OHOS
965