• 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 #include "neural_network_runtime/neural_network_runtime.h"
18 
19 #include <sys/stat.h>
20 #include <fstream>
21 #include <climits>
22 #include <securec.h>
23 
24 #include "validation.h"
25 #include "nncompiled_cache.h"
26 #include "utils.h"
27 #include "nlohmann/json.hpp"
28 
29 namespace OHOS {
30 namespace NeuralNetworkRuntime {
31 namespace {
32 const int CACHE_INPUT_TENSORDESC_OFFSET = 2;
33 const int CACHE_OUTPUT_TENSORDESC_OFFSET = 1;
34 constexpr int32_t  NUMBER_CACHE_INFO_MEMBERS = 3;
35 constexpr int32_t NUMBER_CACHE_INFO_EXTENSION_MEMBERS = 2;
36 const std::string EXTENSION_KEY_MODEL_NAME = "ModelName";
37 const std::string EXTENSION_KEY_FM_SHARED = "NPU_FM_SHARED";
38 const std::string EXTENSION_KEY_IS_EXCEED_RAMLIMIT = "isExceedRamLimit";
39 constexpr size_t INPUT_OUTPUT_MAX_NUM = 200;
40 constexpr size_t MORE_MODEL_MAX_LIMIT = 201 * 1024 * 1024; // 201MB
41 constexpr size_t MODEL_MAX_LIMIT = 200 * 1024 * 1024; // 200MB
42 constexpr size_t CHECK_SUM_ZERO = 0;
43 constexpr size_t CHECK_SUM_ONE = 1;
44 constexpr size_t CHECK_SUM_TWO = 2;
45 constexpr size_t EXTRACT_NODE_LAYER = 3;
46 constexpr int32_t MINDSPORE_CONST_NODE_TYPE = 0;
47 
48 struct SerializedTensorDesc {
49 public:
50     SerializedTensorDesc() = default;
51     ~SerializedTensorDesc() = default;
52 
CopyFromTensorDescOHOS::NeuralNetworkRuntime::__anona43de1bc0111::SerializedTensorDesc53     OH_NN_ReturnCode CopyFromTensorDesc(const std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>& tensorDesc)
54     {
55         if (tensorDesc.first == nullptr) {
56             LOGE("CopyFromTensorDesc failed, tensor desc is nullptr.");
57             return OH_NN_NULL_PTR;
58         }
59         OH_NN_ReturnCode ret = tensorDesc.first->GetDataType(&m_dataType);
60         if (ret != OH_NN_SUCCESS) {
61             LOGE("CopyFromTensorDesc failed, error happened when getting data type from tensor desc.");
62             return ret;
63         }
64 
65         ret = tensorDesc.first->GetFormat(&m_format);
66         if (ret != OH_NN_SUCCESS) {
67             LOGE("CopyFromTensorDesc failed, error happened when getting format from tensor desc.");
68             return ret;
69         }
70 
71         ret = tensorDesc.first->GetShape(&m_shape, &m_shapeNum);
72         if (ret != OH_NN_SUCCESS) {
73             LOGE("CopyFromTensorDesc failed, error happened when getting shape from tensor desc.");
74             return ret;
75         }
76 
77         ret = tensorDesc.first->GetName(&m_name);
78         if (ret != OH_NN_SUCCESS) {
79             LOGE("CopyFromTensorDesc failed, error happened when getting name from tensor desc.");
80             return ret;
81         }
82 
83         m_tensorType = tensorDesc.second;
84 
85         return ret;
86     }
87 
CopyToTensorDescOHOS::NeuralNetworkRuntime::__anona43de1bc0111::SerializedTensorDesc88     OH_NN_ReturnCode CopyToTensorDesc(TensorDesc& tensorDesc) const
89     {
90         OH_NN_ReturnCode ret = tensorDesc.SetDataType(m_dataType);
91         if (ret != OH_NN_SUCCESS) {
92             LOGE("CopyToTensorDesc failed, error happened when setting data type to tensor desc.");
93             return ret;
94         }
95 
96         ret = tensorDesc.SetFormat(m_format);
97         if (ret != OH_NN_SUCCESS) {
98             LOGE("CopyToTensorDesc failed, error happened when setting format to tensor desc.");
99             return ret;
100         }
101 
102         ret = tensorDesc.SetShape(m_shape, m_shapeNum);
103         if (ret != OH_NN_SUCCESS) {
104             LOGE("CopyToTensorDesc failed, error happened when setting shape to tensor desc.");
105             return ret;
106         }
107 
108         ret = tensorDesc.SetName(m_name);
109         if (ret != OH_NN_SUCCESS) {
110             LOGE("CopyToTensorDesc failed, error happened when setting name to tensor desc.");
111         }
112 
113         return ret;
114     }
115 
116 public:
117     OH_NN_DataType m_dataType{OH_NN_UNKNOWN};
118     OH_NN_Format m_format{OH_NN_FORMAT_NONE};
119     OH_NN_TensorType m_tensorType{OH_NN_TENSOR};
120     size_t m_shapeNum{0};
121     int32_t* m_shape{nullptr};
122     const char* m_name{nullptr}; // null-terminated
123 };
124 
125 const size_t SIZE_OF_DATATYPE = sizeof(SerializedTensorDesc::m_dataType);
126 const size_t SIZE_OF_FORMAT = sizeof(SerializedTensorDesc::m_format);
127 const size_t SIZE_OF_TENSOR_TYPE = sizeof(SerializedTensorDesc::m_tensorType);
128 const size_t SIZE_OF_SHAPE_NUM = sizeof(SerializedTensorDesc::m_shapeNum);
129 } // namespace
130 
NNCompiler(std::shared_ptr<Device> device,size_t backendID)131 NNCompiler::NNCompiler(std::shared_ptr<Device> device, size_t backendID)
132     : m_device(device),
133     m_backendID(backendID) {}
134 
NNCompiler(const void * model,std::shared_ptr<Device> device,size_t backendID)135 NNCompiler::NNCompiler(const void* model, std::shared_ptr<Device> device, size_t backendID)
136     : m_device(device),
137     m_backendID(backendID)
138 {
139     m_innerModel = const_cast<InnerModel*>(reinterpret_cast<const InnerModel*>(model));
140     m_liteGraph = m_innerModel->GetLiteGraphs();
141     m_inputTensorDescs = m_innerModel->GetInputTensorDescs();
142     m_outputTensorDescs = m_innerModel->GetOutputTensorDescs();
143     m_metaGraph = m_innerModel->GetMetaGraph();
144     m_extensionConfig = m_innerModel->GetExtensionConfig();
145 }
146 
~NNCompiler()147 NNCompiler::~NNCompiler()
148 {
149     if (m_preparedModel != nullptr) {
150         m_preparedModel.reset();
151     }
152     m_inputTensorDescs.clear();
153     m_outputTensorDescs.clear();
154 }
155 
GetBackendID() const156 size_t NNCompiler::GetBackendID() const
157 {
158     return m_backendID;
159 }
160 
SetCacheDir(const std::string & cacheModelPath,uint32_t version)161 OH_NN_ReturnCode NNCompiler::SetCacheDir(const std::string& cacheModelPath, uint32_t version)
162 {
163     if (m_device == nullptr) {
164         LOGE("[NNCompiler] SetCacheDir failed, m_device is nullptr");
165         return OH_NN_OPERATION_FORBIDDEN;
166     }
167 
168     bool isSupportedCache {false};
169     OH_NN_ReturnCode ret = m_device->IsModelCacheSupported(isSupportedCache);
170     if (ret != OH_NN_SUCCESS) {
171         LOGE("[NNCompiler] SetCacheDir failed, fail to call device.");
172         return ret;
173     }
174 
175     if (!isSupportedCache && !cacheModelPath.empty()) {
176         LOGE("[NNCompiler] SetCacheDir failed, this device is not support cache setting.");
177         return OH_NN_OPERATION_FORBIDDEN;
178     }
179 
180     m_cachePath = cacheModelPath;
181     m_cacheVersion = version;
182 
183     return OH_NN_SUCCESS;
184 }
185 
SetPerformance(OH_NN_PerformanceMode performance)186 OH_NN_ReturnCode NNCompiler::SetPerformance(OH_NN_PerformanceMode performance)
187 {
188     if (m_device == nullptr) {
189         LOGE("[NNCompiler] SetPerformance failed, m_device is nullptr");
190         return OH_NN_OPERATION_FORBIDDEN;
191     }
192 
193     bool isSupportedPerformance {false};
194     OH_NN_ReturnCode ret = m_device->IsPerformanceModeSupported(isSupportedPerformance);
195     if (ret != OH_NN_SUCCESS) {
196         LOGE("[NNCompiler] SetPerformance failed, fail to call device.");
197         return OH_NN_FAILED;
198     }
199 
200     if (!isSupportedPerformance && (performance != OH_NN_PERFORMANCE_NONE)) {
201         LOGE("[NNCompiler] SetPerformance failed, this device is not support performance setting.");
202         return OH_NN_OPERATION_FORBIDDEN;
203     }
204 
205     if (!Validation::ValidatePerformanceMode(performance)) {
206         LOGE("[NNCompiler] SetPerformance failed, performance=%{public}d is invalid", performance);
207         return OH_NN_INVALID_PARAMETER;
208     }
209 
210     m_performance = performance;
211     return OH_NN_SUCCESS;
212 }
213 
SetPriority(OH_NN_Priority priority)214 OH_NN_ReturnCode NNCompiler::SetPriority(OH_NN_Priority priority)
215 {
216     if (m_device == nullptr) {
217         LOGE("[NNCompiler] SetPriority failed, m_device is nullptr");
218         return OH_NN_OPERATION_FORBIDDEN;
219     }
220 
221     bool isSupportedPriority {false};
222     OH_NN_ReturnCode ret = m_device->IsPrioritySupported(isSupportedPriority);
223     if (ret != OH_NN_SUCCESS) {
224         LOGE("[NNCompiler] SetPriority failed, fail to call device.");
225         return ret;
226     }
227 
228     if (!isSupportedPriority && (priority != OH_NN_PRIORITY_NONE)) {
229         LOGE("[NNCompiler] SetPriority failed, this device is not support priority setting.");
230         return OH_NN_OPERATION_FORBIDDEN;
231     }
232 
233     if (!Validation::ValidatePriority(priority)) {
234         LOGE("[NNCompiler] SetPriority failed, priority=%{public}d is invalid.", priority);
235         return OH_NN_INVALID_PARAMETER;
236     }
237 
238     m_priority = priority;
239     return OH_NN_SUCCESS;
240 }
241 
SetEnableFp16(bool isFp16)242 OH_NN_ReturnCode NNCompiler::SetEnableFp16(bool isFp16)
243 {
244     if (m_device == nullptr) {
245         LOGE("[NNCompiler] SetEnableFp16 failed, m_device is nullptr");
246         return OH_NN_OPERATION_FORBIDDEN;
247     }
248 
249     bool isSupportedFp16 {false};
250     OH_NN_ReturnCode ret = m_device->IsFloat16PrecisionSupported(isSupportedFp16);
251     if (ret != OH_NN_SUCCESS) {
252         LOGE("[NNCompiler] SetEnableFp16 failed, fail to call device.");
253         return ret;
254     }
255 
256     if (!isSupportedFp16 && isFp16) {
257         LOGE("[NNCompiler] SetEnableFp16 failed, this device is not support float16 precision setting.");
258         return OH_NN_OPERATION_FORBIDDEN;
259     }
260 
261     m_enableFp16 = isFp16;
262     return OH_NN_SUCCESS;
263 }
264 
IsBuild() const265 bool NNCompiler::IsBuild() const
266 {
267     return m_isBuild;
268 }
269 
IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph> & liteGraph,bool & isSupportedModel) const270 OH_NN_ReturnCode NNCompiler::IsSupportedModel(const std::shared_ptr<mindspore::lite::LiteGraph>& liteGraph,
271                                               bool& isSupportedModel) const
272 {
273     std::vector<bool> supportedList;
274     OH_NN_ReturnCode ret = m_device->GetSupportedOperation(liteGraph, supportedList);
275     if (ret != OH_NN_SUCCESS) {
276         LOGE("[NNCompiler] Build failed, error happened when getting supported operation.");
277         return ret;
278     }
279 
280     bool isNotSupport = std::any_of(supportedList.begin(), supportedList.end(), [](bool isSupport) {
281         return !isSupport;
282     });
283     if (isNotSupport) {
284         LOGE("[NNCompiler] Build failed, current device not support the model, device id: %{public}zu.", m_backendID);
285         isSupportedModel = false;
286         return OH_NN_FAILED;
287     }
288 
289     isSupportedModel = true;
290     return OH_NN_SUCCESS;
291 }
292 
CheckModelParameter() const293 OH_NN_ReturnCode NNCompiler::CheckModelParameter() const
294 {
295     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
296     if (m_innerModel == nullptr) {
297         return OH_NN_SUCCESS;
298     }
299 
300     // m_innerModel is not constructed completely.
301     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
302         LOGE("[NNCompiler] LiteGraph and metaGraph are empty, m_innerModel is not constructed completely.");
303         return OH_NN_INVALID_PARAMETER;
304     }
305 
306     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
307         LOGE("[NNCompiler] Both LiteGraph and metaGraph are not empty.");
308         return OH_NN_INVALID_PARAMETER;
309     }
310 
311     return OH_NN_SUCCESS;
312 }
313 
IsOfflineModel(bool & isOfflineModel) const314 OH_NN_ReturnCode NNCompiler::IsOfflineModel(bool& isOfflineModel) const
315 {
316     // If m_innerModel is not passed, the compiler must be construct from cache, jump check m_innerModel.
317     if (m_innerModel == nullptr) {
318         return OH_NN_SUCCESS;
319     }
320 
321     isOfflineModel = false; // Initialize the returned value
322     if (m_metaGraph != nullptr) {
323         isOfflineModel = false;
324         return OH_NN_SUCCESS;
325     }
326 
327     if (m_liteGraph->all_nodes_.size() == 0) {
328         LOGE("[NNCompiler] Find empty node in the model.");
329         return OH_NN_INVALID_PARAMETER;
330     }
331 
332     // If the model consists of more than 1 node, it will not be considered as offline model.
333     if (m_liteGraph->all_nodes_.size() > 1) {
334         isOfflineModel = false;
335         return OH_NN_SUCCESS;
336     }
337 
338     const mindspore::lite::LiteGraph::Node* pNode = m_liteGraph->all_nodes_[0];
339     if (pNode == nullptr) {
340         LOGE("[NNCompiler] Find invalid node in the model.");
341         return OH_NN_NULL_PTR;
342     }
343 
344     const mindspore::lite::NodeType& nodeType = mindspore::lite::MindIR_Primitive_GetType(pNode->primitive_);
345     if (nodeType == mindspore::lite::NodeType::NODE_TYPE_CUSTOM) {
346         isOfflineModel = true;
347     }
348 
349     return OH_NN_SUCCESS;
350 }
351 
BuildOfflineModel()352 OH_NN_ReturnCode NNCompiler::BuildOfflineModel()
353 {
354     ModelConfig config {m_enableFp16, m_performance, m_priority};
355     OH_NN_ReturnCode ret = m_device->PrepareOfflineModel(m_liteGraph, config, m_preparedModel);
356     if (ret != OH_NN_SUCCESS) {
357         LOGE("[NNCompiler] Preparing model failed when building from offline model.");
358         return ret;
359     }
360 
361     return OH_NN_SUCCESS;
362 }
363 
NormalBuild()364 OH_NN_ReturnCode NNCompiler::NormalBuild()
365 {
366     if ((m_liteGraph == nullptr) && (m_metaGraph == nullptr)) {
367         LOGE("[NNCompiler] Build failed, both liteGraph and metaGraph are nullptr.");
368         return OH_NN_INVALID_PARAMETER;
369     }
370 
371     if ((m_liteGraph != nullptr) && (m_metaGraph != nullptr)) {
372         LOGE("[NNCompiler] Build failed, neither liteGraph nor metaGraph are nullptr.");
373         return OH_NN_INVALID_PARAMETER;
374     }
375 
376     // 判断是否支持模型
377     bool isSupportedModel = true;
378     OH_NN_ReturnCode ret = IsSupportedModel(m_liteGraph, isSupportedModel);
379     if (ret != OH_NN_SUCCESS) {
380         LOGE("[NNCompiler] Build failed, error happened when judge if support the model.");
381         return ret;
382     } else if (!isSupportedModel) {
383         LOGE("[NNCompiler] Build failed, current device not support the model.");
384         return OH_NN_FAILED;
385     }
386 
387     ModelConfig config {m_enableFp16, static_cast<OH_NN_PerformanceMode>(m_performance),
388         static_cast<OH_NN_Priority>(m_priority), m_cachePath, m_extensionConfig};
389     if (m_liteGraph != nullptr) {
390         ret = m_device->PrepareModel(m_liteGraph, config, m_preparedModel);
391     }
392     if (m_metaGraph != nullptr) {
393         ret = m_device->PrepareModel(m_metaGraph, config, m_preparedModel);
394     }
395     if (ret != OH_NN_SUCCESS) {
396         LOGE("[NNCompiler] Build failed, fail to prepare model when normally building.");
397         return ret;
398     }
399     m_isBuild = true;
400 
401     // 保存cache
402     if (!m_cachePath.empty()) {
403         ret = SaveToCacheFile();
404         if (ret != OH_NN_SUCCESS) {
405             LOGE("[NNCompiler] Build success, but fail to save cache to file.");
406             return ret;
407         }
408     }
409 
410     return OH_NN_SUCCESS;
411 }
412 
Build()413 OH_NN_ReturnCode NNCompiler::Build()
414 {
415     if (m_isBuild) {
416         LOGE("[NNCompiler] Build failed, cannot build again.");
417         return OH_NN_OPERATION_FORBIDDEN;
418     }
419 
420     if (m_device == nullptr) {
421         LOGE("[NNCompiler] Build failed, the m_device is nullptr.");
422         return OH_NN_OPERATION_FORBIDDEN;
423     }
424 
425     OH_NN_ReturnCode ret = CheckModelParameter();
426     if (ret != OH_NN_SUCCESS) {
427         LOGE("[NNCompiler] CheckModelParameter failed, some error happened when checking model parameter.");
428         return ret;
429     }
430 
431     // Prepare from offline model.
432     bool isOfflineModel {false};
433     ret = IsOfflineModel(isOfflineModel);
434     if (ret != OH_NN_SUCCESS) {
435         LOGE("[NNCompiler] Build failed, fail to identify the offline model.");
436         return ret;
437     }
438 
439     if (isOfflineModel) {
440         ret = BuildOfflineModel();
441         if (ret != OH_NN_SUCCESS) {
442             LOGE("[NNCompiler] Build failed, Failed to build offline model.");
443             return ret;
444         }
445 
446         m_isBuild = true;
447         return OH_NN_SUCCESS;
448     }
449 
450     ret = OnlineBuild();
451     if (ret != OH_NN_SUCCESS) {
452         LOGE("[NNCompiler] OnlineBuild failed, Failed to build model online.");
453         return ret;
454     }
455 
456     return OH_NN_SUCCESS;
457 }
458 
OnlineBuild()459 OH_NN_ReturnCode NNCompiler::OnlineBuild()
460 {
461     // cache存在,从cache直接复原prepareModel、input/output TensorDesc
462     OH_NN_ReturnCode ret = RestoreFromCacheFile();
463     if (ret == OH_NN_INVALID_FILE) {
464         char path[PATH_MAX];
465         if (realpath(m_cachePath.c_str(), path) == nullptr) {
466             LOGE("[NNCompiler] Build failed, fail to get the real path of cacheDir.");
467             return OH_NN_INVALID_PARAMETER;
468         }
469 
470         std::string cachePath = path;
471         std::string cacheInfo = cachePath + "/" + m_extensionConfig.modelName + "cache_info.nncache";
472         if (std::filesystem::exists(cacheInfo)) {
473             LOGW("[NNCompiler] cache file is failed, fail to delete cache file.");
474             std::filesystem::remove_all(cacheInfo);
475         }
476     }
477 
478     if (ret == OH_NN_OPERATION_FORBIDDEN) {
479         LOGE("[NNCompiler] Build failed, operation is forbidden.");
480         return ret;
481     }
482     if (ret == OH_NN_SUCCESS) {
483         LOGD("[NNCompiler] Build success, restore from cache file.");
484         m_isBuild = true;
485     }
486 
487     // cache不存在或cache restore失败,走在线构图
488     if (!m_isBuild) {
489         ret = NormalBuild();
490         if (ret != OH_NN_SUCCESS) {
491             LOGE("[NNCompiler] Build failed, fail to build model online.");
492             return ret;
493         }
494     }
495 
496     return OH_NN_SUCCESS;
497 }
498 
ReleaseBuffer(std::vector<Buffer> & buffers) const499 void NNCompiler::ReleaseBuffer(std::vector<Buffer>& buffers) const
500 {
501     for (size_t i = 0; i < buffers.size(); ++i) {
502         // release tensor buffer which is allocated by new method.
503         delete[] reinterpret_cast<char*>(buffers[i].data);
504     }
505     buffers.clear();
506 }
507 
SaveToCacheFile() const508 OH_NN_ReturnCode NNCompiler::SaveToCacheFile() const
509 {
510     if (m_cachePath.empty()) {
511         LOGE("[NNCompiler] SaveToCacheFile failed, m_cachePath is empty.");
512         return OH_NN_INVALID_PARAMETER;
513     }
514 
515     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
516         LOGE("[NNCompiler] SaveToCacheFile failed, cache version is invalid. Please set a valid cache version.");
517         return OH_NN_INVALID_PARAMETER;
518     }
519 
520     if (m_preparedModel == nullptr) {
521         LOGE("[NNCompiler] SaveToCacheFile failed, m_preparedModel is nullptr. Please construct prepareModel first.");
522         return OH_NN_FAILED;
523     }
524 
525     std::vector<Buffer> caches;
526     std::vector<Buffer> tensorBuffers;
527     OH_NN_ReturnCode ret = m_preparedModel->ExportModelCache(caches);
528     if (ret != OH_NN_SUCCESS) {
529         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when exporting model cache.");
530         return ret;
531     }
532 
533     size_t cacheNumber = caches.size();
534     if (cacheNumber == 0 || cacheNumber > NN_CACHE_FILE_NUMBER_MAX) {
535         LOGE("[NNCompiler] Caches size is equal 0 or greater than 100.");
536         return OH_NN_FAILED;
537     }
538 
539     NNCompiledCache compiledCache;
540     ret = compiledCache.SetBackend(m_backendID);
541     if (ret != OH_NN_SUCCESS) {
542         LOGE("[NNCompiler] SaveToCacheFile failed, fail to set backend.");
543         return ret;
544     }
545 
546     if ((m_inputTensorDescs.size() > INPUT_OUTPUT_MAX_NUM) || (m_outputTensorDescs.size() > INPUT_OUTPUT_MAX_NUM)) {
547         LOGE("[NNCompiler] SaveToCacheFile failed, m_inputTensorDescs or m_outputTensorDescs is more than 200.");
548         return OH_NN_INVALID_PARAMETER;
549     }
550 
551     Buffer inputTensorDescBuffer;
552     ret = SerializeTensorsToBuffer(m_inputTensorDescs, inputTensorDescBuffer);
553     if (ret != OH_NN_SUCCESS) {
554         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing input tensor desc.");
555         return ret;
556     }
557     caches.emplace_back(inputTensorDescBuffer);
558     tensorBuffers.emplace_back(inputTensorDescBuffer);
559 
560     Buffer outputTensorDescBuffer;
561     ret = SerializeTensorsToBuffer(m_outputTensorDescs, outputTensorDescBuffer);
562     if (ret != OH_NN_SUCCESS) {
563         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when serializing output tensor desc.");
564         ReleaseBuffer(tensorBuffers);
565         return ret;
566     }
567     caches.emplace_back(outputTensorDescBuffer);
568     tensorBuffers.emplace_back(outputTensorDescBuffer);
569 
570     compiledCache.SetModelName(m_extensionConfig.modelName);
571     compiledCache.SetIsExceedRamLimit(m_extensionConfig.isExceedRamLimit);
572     ret = compiledCache.Save(caches, m_cachePath, m_cacheVersion);
573     if (ret != OH_NN_SUCCESS) {
574         LOGE("[NNCompiler] SaveToCacheFile failed, error happened when saving model cache.");
575         ReleaseBuffer(tensorBuffers);
576         return ret;
577     }
578 
579     ReleaseBuffer(tensorBuffers);
580     ret = m_preparedModel->ReleaseBuiltModel();
581     if (ret != OH_NN_SUCCESS) {
582         LOGE("[NNCompiler] ReleaseBuiltModel failed, error happened when release model cache.");
583         return ret;
584     }
585 
586     LOGI("[NNCompiler] Export model cache successfully.");
587     return OH_NN_SUCCESS;
588 }
589 
RestoreFromCacheFile()590 OH_NN_ReturnCode NNCompiler::RestoreFromCacheFile()
591 {
592     if (m_cachePath.empty()) {
593         LOGE("[NNCompiler] RestoreFromCacheFile failed, path is empty.");
594         return OH_NN_INVALID_PARAMETER;
595     }
596 
597     if (m_cacheVersion == INVALID_CAHCE_VERSION) {
598         LOGE("[NNCompiler] RestoreFromCacheFile failed, cache version is invalid. Please set a valid cache version.");
599         return OH_NN_INVALID_PARAMETER;
600     }
601 
602     if (m_preparedModel != nullptr) {
603         LOGE("[NNCompiler] RestoreFromCacheFile failed, m_preparedModel is not nullptr.");
604         return OH_NN_FAILED;
605     }
606 
607     NNCompiledCache compiledCache;
608     OH_NN_ReturnCode ret = compiledCache.SetBackend(m_backendID);
609     if (ret != OH_NN_SUCCESS) {
610         LOGE("[NNCompiler] RestoreFromCacheFile failed, fail to set backend.");
611         return ret;
612     }
613 
614     std::vector<Buffer> caches;
615     compiledCache.SetModelName(m_extensionConfig.modelName);
616     ret = compiledCache.Restore(m_cachePath, m_cacheVersion, caches);
617     if (ret != OH_NN_SUCCESS) {
618         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when restoring model cache.");
619         compiledCache.ReleaseCacheBuffer(caches);
620         return ret;
621     }
622 
623     size_t cacheNum = caches.size();
624     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> inputTensorDescs;
625     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_INPUT_TENSORDESC_OFFSET], inputTensorDescs);
626     if (ret != OH_NN_SUCCESS) {
627         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing input tensor desc.");
628         compiledCache.ReleaseCacheBuffer(caches);
629         return ret;
630     }
631 
632     std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>> outputTensorDescs;
633     ret = DeserializedTensorsFromBuffer(caches[cacheNum - CACHE_OUTPUT_TENSORDESC_OFFSET], outputTensorDescs);
634     if (ret != OH_NN_SUCCESS) {
635         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when deserializing output tensor desc.");
636         compiledCache.ReleaseCacheBuffer(caches);
637         return ret;
638     }
639 
640     ModelConfig config;
641     config.enableFloat16 = m_enableFp16;
642     config.mode = m_performance;
643     config.priority = m_priority;
644     config.extensionConfig.isNpuFmShared = m_extensionConfig.isNpuFmShared;
645     std::vector<Buffer> modelOnlyCaches(caches.begin(), caches.end() - CACHE_INPUT_TENSORDESC_OFFSET);
646     bool isUpdatable = false;
647     ret = m_device->PrepareModelFromModelCache(modelOnlyCaches, config, m_preparedModel, isUpdatable);
648     if (ret != OH_NN_SUCCESS) {
649         LOGE("[NNCompiler] RestoreFromCacheFile failed, error happened when preparing model from cache.");
650         compiledCache.ReleaseCacheBuffer(caches);
651         return ret;
652     }
653 
654     if (isUpdatable) {
655         LOGI("isUpdatable is true");
656 
657         int currentOpVersion = 0;
658         ret = m_device->ReadOpVersion(currentOpVersion);
659         if (ret != OH_NN_SUCCESS) {
660             LOGE("[NNCompiledCache] GenerateCacheModel failed, fail to read op version.");
661             return ret;
662         }
663 
664         NNCompiledCacheInfo modelCacheInfo;
665         std::string cacheInfoPath = m_cachePath + "/" + m_extensionConfig.modelName + "cache_info.nncache";
666         ret = compiledCache.CheckCacheInfo(modelCacheInfo, cacheInfoPath);
667         if (ret != OH_NN_SUCCESS) {
668             LOGE("[NNCompiledCache] isUpdatable is true to check cache info failed.");
669             return ret;
670         }
671 
672         LOGI("isUpdatable currentOpVersion is: %{public}d", currentOpVersion);
673         LOGI("isUpdatable modelCacheInfo opVersion is %{public}d", static_cast<int>(modelCacheInfo.opVersion));
674 
675         if (currentOpVersion > modelCacheInfo.opVersion) {
676             const size_t cacheNumber = caches.size();
677             uint32_t cacheSize = NUMBER_CACHE_INFO_MEMBERS + cacheNumber + NUMBER_CACHE_INFO_EXTENSION_MEMBERS;
678             uint32_t infoCharNumber = cacheSize * sizeof(int64_t);
679 
680             nlohmann::json cacheInfo;
681 
682             cacheInfo["data"]["fileNumber"] = modelCacheInfo.fileNumber;
683             cacheInfo["data"]["version"] = modelCacheInfo.version - 1;
684             cacheInfo["data"]["deviceId"] = modelCacheInfo.deviceId;
685 
686             for (size_t i = 0; i < modelCacheInfo.modelCheckSum.size(); ++i) {
687                 cacheInfo["data"]["modelCheckSum"][i] = modelCacheInfo.modelCheckSum[i];
688             }
689 
690             cacheInfo["data"]["opVersion"] = currentOpVersion;
691             cacheInfo["data"]["isExceedRamLimit"] = modelCacheInfo.isExceedRamLimit ? 1 : 0;
692 
693             const size_t dataLength = cacheInfo["data"].dump().length();
694             char cacheInfoData[dataLength + 1];
695             if (strncpy_s(cacheInfoData, dataLength+1, cacheInfo["data"].dump().c_str(), dataLength) != 0) {
696                 LOGE("ParseStr failed due to strncpy_s error");
697                 return OH_NN_INVALID_PARAMETER;
698             }
699 
700             cacheInfo["CheckSum"] = static_cast<int64_t>(CacheInfoGetCrc16(cacheInfoData, dataLength));
701 
702             ret = compiledCache.WriteCacheInfo(infoCharNumber, cacheInfo, m_cachePath);
703             if (ret != OH_NN_SUCCESS) {
704                 LOGE("[NNCompiledCache] isUpdatable is true to write cache info failed.");
705                 return ret;
706             }
707         }
708     }
709 
710     compiledCache.ReleaseCacheBuffer(caches);
711 
712     m_inputTensorDescs = inputTensorDescs;
713     m_outputTensorDescs = outputTensorDescs;
714     return OH_NN_SUCCESS;
715 }
716 
SaveToCacheBuffer(const void * buffer,size_t length,size_t * modelSize) const717 OH_NN_ReturnCode NNCompiler::SaveToCacheBuffer(const void* buffer, size_t length, size_t* modelSize) const
718 {
719     LOGE("[NNCompiler] SaveToCacheBuffer is not supported currently.");
720     return OH_NN_UNSUPPORTED;
721 }
722 
RestoreFromCacheBuffer(const void * buffer,size_t length)723 OH_NN_ReturnCode NNCompiler::RestoreFromCacheBuffer(const void* buffer, size_t length)
724 {
725     LOGE("[NNCompiler] RestoreFromCacheBuffer is not supported currently.");
726     return OH_NN_UNSUPPORTED;
727 }
728 
SetExtensionConfig(const std::unordered_map<std::string,std::vector<char>> & configs)729 OH_NN_ReturnCode NNCompiler::SetExtensionConfig(const std::unordered_map<std::string, std::vector<char>>& configs)
730 {
731     if (configs.find(EXTENSION_KEY_MODEL_NAME) != configs.end()) {
732         std::vector<char> value = configs.at(EXTENSION_KEY_MODEL_NAME);
733         if (value.empty()) {
734             LOGE("[NNCompiler] SetExtensionConfig get empty model name from configs");
735             return OH_NN_INVALID_PARAMETER;
736         }
737         m_extensionConfig.modelName.assign(value.data(), value.data() + value.size());
738     }
739     if (configs.find(EXTENSION_KEY_FM_SHARED) != configs.end()) {
740         m_extensionConfig.isNpuFmShared = true;
741         LOGI("[NNCompiler] SetExtensionConfig NpuFmShared enabled.");
742     }
743     if (configs.find(EXTENSION_KEY_IS_EXCEED_RAMLIMIT) != configs.end()) {
744         std::vector<char> value = configs.at(EXTENSION_KEY_IS_EXCEED_RAMLIMIT);
745         if (value.empty()) {
746             LOGE("[NNCompiler] SetExtensionConfig get empty model name from configs");
747             return OH_NN_INVALID_PARAMETER;
748         }
749 
750         if (value[0] == '1') {
751             m_extensionConfig.isExceedRamLimit = true;
752         } else {
753             m_extensionConfig.isExceedRamLimit = false;
754         }
755     }
756     return OH_NN_SUCCESS;
757 }
758 
SetOptions(const std::vector<std::shared_ptr<void>> & options)759 OH_NN_ReturnCode NNCompiler::SetOptions(const std::vector<std::shared_ptr<void>>& options)
760 {
761     return OH_NN_UNSUPPORTED;
762 }
763 
GetModelName(std::string & modelName)764 OH_NN_ReturnCode NNCompiler::GetModelName(std::string& modelName)
765 {
766     modelName = m_extensionConfig.modelName;
767     return OH_NN_SUCCESS;
768 }
769 
CreateExecutor()770 NNExecutor* NNCompiler::CreateExecutor()
771 {
772     if (m_device == nullptr) {
773         LOGE("[NNCompiler] CreateExecutor failed, m_device is nullptr");
774         return nullptr;
775     }
776 
777     if (m_preparedModel == nullptr) {
778         LOGE("[NNCompiler] CreateExecutor failed, m_preparedModel is nullptr");
779         return nullptr;
780     }
781 
782     if (m_inputTensorDescs.empty()) {
783         LOGE("[NNCompiler] CreateExecutor failed, m_inputTensorDescs is empty");
784         return nullptr;
785     }
786 
787     if (m_outputTensorDescs.empty()) {
788         LOGE("[NNCompiler] CreateExecutor failed, m_outputTensorDescs is empty");
789         return nullptr;
790     }
791 
792     NNExecutor* nnExecutor = new (std::nothrow) NNExecutor(
793         m_backendID, m_device, m_preparedModel, m_inputTensorDescs, m_outputTensorDescs,
794         m_cachePath, m_cacheVersion, m_extensionConfig, m_enableFp16, m_performance, m_priority);
795     if (nnExecutor == nullptr) {
796         LOGE("[NNCompiler] CreateExecutor failed, error happend when allocating NN Executor.");
797         return nullptr;
798     }
799 
800     return nnExecutor;
801 }
802 
SerializeTensorsToBuffer(const std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs,Buffer & buffer) const803 OH_NN_ReturnCode NNCompiler::SerializeTensorsToBuffer(
804     const std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs, Buffer& buffer) const
805 {
806     std::vector<SerializedTensorDesc> immediateTensorDescs;
807     OH_NN_ReturnCode ret = OH_NN_SUCCESS;
808     for (const auto& tensorDesc : tensorDescs) {
809         SerializedTensorDesc immediateTensorDesc;
810         ret = immediateTensorDesc.CopyFromTensorDesc(tensorDesc);
811         if (ret != OH_NN_SUCCESS) {
812             LOGE("[NNCompiler] SerializeInputsToBuffer failed, error happened when copying tensorDesc to "
813                  "SerializedTensorDesc.");
814             immediateTensorDescs.clear();
815             return ret;
816         }
817         immediateTensorDescs.emplace_back(immediateTensorDesc);
818     }
819 
820     size_t totalSize = 0;
821     for (const auto& tensorDesc : immediateTensorDescs) {
822         totalSize += SIZE_OF_DATATYPE;
823         totalSize += SIZE_OF_FORMAT;
824         totalSize += SIZE_OF_TENSOR_TYPE;
825         totalSize += SIZE_OF_SHAPE_NUM;
826         totalSize += tensorDesc.m_shapeNum * sizeof(int32_t);
827         totalSize += strlen(tensorDesc.m_name) + 1;
828     }
829 
830     // Allocate memory for the serialized data
831     char* serializedData = new (std::nothrow) char[totalSize];
832     if (serializedData == nullptr) {
833         LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to create serialized data.");
834         return OH_NN_NULL_PTR;
835     }
836     char* currentPos = serializedData;
837 
838     // Serialize each tensor description
839     for (const auto& tensorDesc : immediateTensorDescs) {
840         auto memRet = memcpy_s(currentPos, SIZE_OF_DATATYPE, &tensorDesc.m_dataType, SIZE_OF_DATATYPE);
841         if (memRet != EOK) {
842             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s data type.");
843             delete[] serializedData;
844             return OH_NN_MEMORY_ERROR;
845         }
846         currentPos += SIZE_OF_DATATYPE;
847 
848         memRet = memcpy_s(currentPos, SIZE_OF_FORMAT, &tensorDesc.m_format, SIZE_OF_FORMAT);
849         if (memRet != EOK) {
850             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s format.");
851             delete[] serializedData;
852             return OH_NN_MEMORY_ERROR;
853         }
854         currentPos += SIZE_OF_FORMAT;
855 
856         memRet = memcpy_s(currentPos, SIZE_OF_TENSOR_TYPE, &tensorDesc.m_tensorType, SIZE_OF_TENSOR_TYPE);
857         if (memRet != EOK) {
858             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s tensor type.");
859             delete[] serializedData;
860             return OH_NN_MEMORY_ERROR;
861         }
862         currentPos += SIZE_OF_TENSOR_TYPE;
863 
864         memRet = memcpy_s(currentPos, SIZE_OF_SHAPE_NUM, &tensorDesc.m_shapeNum, SIZE_OF_SHAPE_NUM);
865         if (memRet != EOK) {
866             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape num.");
867             delete[] serializedData;
868             return OH_NN_MEMORY_ERROR;
869         }
870         currentPos += SIZE_OF_SHAPE_NUM;
871 
872         size_t sizeOfShape = tensorDesc.m_shapeNum * sizeof(int32_t);
873         memRet = memcpy_s(currentPos, sizeOfShape, tensorDesc.m_shape, sizeOfShape);
874         if (memRet != EOK) {
875             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s shape.");
876             delete[] serializedData;
877             return OH_NN_MEMORY_ERROR;
878         }
879         currentPos += sizeOfShape;
880 
881         memRet = strcpy_s(currentPos, strlen(tensorDesc.m_name) + 1, tensorDesc.m_name);
882         if (memRet != EOK) {
883             LOGE("[NNCompiler] SerializeInputsToBuffer failed, failed to memcpy_s name.");
884             delete[] serializedData;
885             return OH_NN_MEMORY_ERROR;
886         }
887         currentPos += strlen(tensorDesc.m_name) + 1;
888     }
889 
890     buffer.data = serializedData;
891     buffer.length = totalSize;
892 
893     return OH_NN_SUCCESS;
894 }
895 
ReleaseDescShape(std::vector<SerializedTensorDesc> & immediateTensorDescs)896 void ReleaseDescShape(std::vector<SerializedTensorDesc>& immediateTensorDescs)
897 {
898     for (auto desc : immediateTensorDescs) {
899         delete[] desc.m_shape;
900     }
901     immediateTensorDescs.clear();
902 }
903 
DeserializedTensorsFromBuffer(const Buffer & buffer,std::vector<std::pair<std::shared_ptr<TensorDesc>,OH_NN_TensorType>> & tensorDescs)904 OH_NN_ReturnCode NNCompiler::DeserializedTensorsFromBuffer(
905     const Buffer& buffer, std::vector<std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType>>& tensorDescs)
906 {
907     std::vector<SerializedTensorDesc> immediateTensorDescs;
908     const char* ptr = static_cast<const char*>(buffer.data);
909     const char* end = ptr + buffer.length;
910     while (ptr < end) {
911         SerializedTensorDesc desc;
912 
913         auto memRet = memcpy_s(&desc.m_dataType, SIZE_OF_DATATYPE, ptr, sizeof(desc.m_dataType));
914         if (memRet != EOK) {
915             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s data type.");
916             ReleaseDescShape(immediateTensorDescs);
917             return OH_NN_MEMORY_ERROR;
918         }
919         ptr += sizeof(desc.m_dataType);
920 
921         memRet = memcpy_s(&desc.m_format, SIZE_OF_FORMAT, ptr, sizeof(desc.m_format));
922         if (memRet != EOK) {
923             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s format.");
924             ReleaseDescShape(immediateTensorDescs);
925             return OH_NN_MEMORY_ERROR;
926         }
927         ptr += sizeof(desc.m_format);
928 
929         memRet = memcpy_s(&desc.m_tensorType, SIZE_OF_TENSOR_TYPE, ptr, sizeof(desc.m_tensorType));
930         if (memRet != EOK) {
931             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s tensor type.");
932             ReleaseDescShape(immediateTensorDescs);
933             return OH_NN_MEMORY_ERROR;
934         }
935         ptr += sizeof(desc.m_tensorType);
936 
937         memRet = memcpy_s(&desc.m_shapeNum, SIZE_OF_SHAPE_NUM, ptr, sizeof(desc.m_shapeNum));
938         if (memRet != EOK) {
939             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape num.");
940             ReleaseDescShape(immediateTensorDescs);
941             return OH_NN_MEMORY_ERROR;
942         }
943         ptr += sizeof(desc.m_shapeNum);
944 
945         desc.m_shape = new (std::nothrow) int32_t[desc.m_shapeNum];
946         if (desc.m_shape == nullptr) {
947             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create shape buffer.");
948             ReleaseDescShape(immediateTensorDescs);
949             return OH_NN_NULL_PTR;
950         }
951         memRet = memcpy_s(desc.m_shape, desc.m_shapeNum * sizeof(int32_t), ptr, desc.m_shapeNum * sizeof(int32_t));
952         if (memRet != EOK) {
953             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to memcpy_s shape.");
954             ReleaseDescShape(immediateTensorDescs);
955             return OH_NN_MEMORY_ERROR;
956         }
957         ptr += desc.m_shapeNum * sizeof(int32_t);
958 
959         desc.m_name = ptr;
960         ptr += std::strlen(desc.m_name) + 1; // +1 for null terminator
961 
962         immediateTensorDescs.push_back(desc);
963     }
964 
965     OH_NN_ReturnCode ret {OH_NN_SUCCESS};
966     for (const auto& immediateTensorDesc : immediateTensorDescs) {
967         std::pair<std::shared_ptr<TensorDesc>, OH_NN_TensorType> tensorDescPair;
968         tensorDescPair.first = CreateSharedPtr<TensorDesc>();
969         if (tensorDescPair.first == nullptr) {
970             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, failed to create tensor desc.");
971             tensorDescs.clear();
972             ReleaseDescShape(immediateTensorDescs);
973             return OH_NN_NULL_PTR;
974         }
975         ret = immediateTensorDesc.CopyToTensorDesc(*(tensorDescPair.first.get()));
976         if (ret != OH_NN_SUCCESS) {
977             LOGE("[NNCompiler] DeserializedTensorsFromBuffer failed, error happened when copying "
978                  "SerializedTensorDesc to TensorDesc.");
979             tensorDescs.clear();
980             ReleaseDescShape(immediateTensorDescs);
981             return ret;
982         }
983         tensorDescPair.second = immediateTensorDesc.m_tensorType;
984 
985         tensorDescs.emplace_back(tensorDescPair);
986     }
987 
988     ReleaseDescShape(immediateTensorDescs);
989     return ret;
990 }
991 
DataTypeSize(mindspore::lite::DataType dataType)992 size_t NNCompiler::DataTypeSize(mindspore::lite::DataType dataType)
993 {
994     switch (dataType) {
995         case mindspore::lite::DATA_TYPE_BOOL:
996             return sizeof(bool);
997         case mindspore::lite::DATA_TYPE_INT8:
998             return sizeof(int8_t);
999         case mindspore::lite::DATA_TYPE_UINT8:
1000             return sizeof(uint8_t);
1001         case mindspore::lite::DATA_TYPE_INT16:
1002             return sizeof(int16_t);
1003         case mindspore::lite::DATA_TYPE_UINT16:
1004         case mindspore::lite::DATA_TYPE_FLOAT16:
1005             return sizeof(uint16_t);
1006         case mindspore::lite::DATA_TYPE_INT32:
1007             return sizeof(int32_t);
1008         case mindspore::lite::DATA_TYPE_UINT32:
1009             return sizeof(uint32_t);
1010         case mindspore::lite::DATA_TYPE_INT64:
1011             return sizeof(int64_t);
1012         case mindspore::lite::DATA_TYPE_UINT64:
1013             return sizeof(uint64_t);
1014         case mindspore::lite::DATA_TYPE_FLOAT32:
1015             return sizeof(float);
1016         case mindspore::lite::DATA_TYPE_FLOAT64:
1017             return sizeof(double);
1018         case mindspore::lite::DATA_TYPE_UNKNOWN:
1019             return 0;
1020         default:
1021             LOGE("Not support the type: %{public}d", dataType);
1022             return 0;
1023     }
1024 }
1025 
GetFileSize(const char * fileName)1026 size_t NNCompiler::GetFileSize(const char* fileName)
1027 {
1028     if (fileName == nullptr) {
1029         return 0;
1030     }
1031 
1032     // 这是一个存储文件(夹)信息的结构体,其中有文件大小和创建时间、访问时间、修改时间等
1033     struct stat statbuf;
1034 
1035     // 提供文件名字符串, 获得文件属性结构体
1036     stat(fileName, &statbuf);
1037 
1038     // 获取文件大小
1039     size_t fileSize = static_cast<size_t>(statbuf.st_size);
1040 
1041     return fileSize;
1042 }
1043 
GetModelSizeFromModel(InnerModel * innerModel)1044 size_t NNCompiler::GetModelSizeFromModel(InnerModel* innerModel)
1045 {
1046     auto liteGraph = innerModel->GetLiteGraphs();
1047     if (liteGraph == nullptr) {
1048         LOGE("GetModelSizeFromModel failed, failed to get liteGraph");
1049         return 0;
1050     }
1051 
1052     size_t modelSize = 0;
1053     std::vector<int32_t> shape;
1054     mindspore::lite::DataType dtype = mindspore::lite::DATA_TYPE_UNKNOWN;
1055     size_t num = 1;
1056     LOGD("GetOnlineModelSize, all_tensors_size: %{public}zu.", liteGraph->all_tensors_.size());
1057     for (const auto& tensor : liteGraph->all_tensors_) {
1058         if (tensor == nullptr) {
1059             LOGE("GetmodelSizeFromModel failed, failed to nullptr in model tensor");
1060             return 0;
1061         }
1062 
1063         // non-const node type, skip
1064         if (mindspore::lite::MindIR_Tensor_GetNodeType(tensor) != MINDSPORE_CONST_NODE_TYPE) {
1065             continue;
1066         }
1067 
1068         shape = mindspore::lite::MindIR_Tensor_GetDims(tensor);
1069         dtype = mindspore::lite::MindIR_Tensor_GetDataType(tensor);
1070         size_t tensorSize = std::accumulate(shape.begin(), shape.end(), num, std::multiplies<size_t>());
1071         if ((std::numeric_limits<size_t>::max() - modelSize) <= tensorSize) {
1072             LOGE("model size exceed max limit size, please check.");
1073             return 0;
1074         }
1075         modelSize +=  (tensorSize * DataTypeSize(dtype));
1076     }
1077 
1078     LOGD("GetModelSizeFromModel, modelSize: %{public}zu.", modelSize);
1079     return modelSize;
1080 }
1081 
GetModelSizeFromFile(std::string & path)1082 size_t NNCompiler::GetModelSizeFromFile(std::string& path)
1083 {
1084     // 读取omc文件大小
1085     if (path.empty()) {
1086         LOGE("[GetModelSizeFromFile] failed, path is empty.");
1087         return 0;
1088     }
1089 
1090     // 获取模型文件大小
1091     size_t modelSize = GetFileSize(path.c_str());
1092 
1093     // 获取权重文件大小
1094     const std::string& weightPath = path;
1095     struct stat buffer;
1096     if (stat(weightPath.c_str(), &buffer) == 0) {
1097         modelSize += static_cast<size_t>(buffer.st_size);
1098     } else {
1099         LOGD("[GetModelSizeFromFile] weight file not exists: %{public}s.", weightPath.c_str());
1100     }
1101 
1102     LOGD("GetModelSizeFromFile, modelSize: %{public}zu.", modelSize);
1103     return modelSize;
1104 }
1105 
GetModelSizeFromCache(std::string & path,const std::string & modelName)1106 size_t NNCompiler::GetModelSizeFromCache(std::string& path, const std::string& modelName)
1107 {
1108     size_t modelSize = 0;
1109     if (std::filesystem::is_directory(path)) {
1110         if (path.empty()) {
1111             LOGE("GetModelSizeFromCache failed, path is nullptr");
1112             return 0;
1113         }
1114 
1115         std::string modelPath = path + "/" + modelName + "cache_info.nncache";
1116         char modelCachePath[PATH_MAX];
1117         if (realpath(modelPath.c_str(), modelCachePath) == nullptr) {
1118             LOGE("GetModelSizeFromCache failed to get the real path of cacheDir.");
1119             return 0;
1120         }
1121 
1122         std::string cacheInfoPath(modelCachePath);
1123 
1124         // cacheInfoPath is validated outside.
1125         std::ifstream infoCacheFile(cacheInfoPath.c_str(), std::ios::in | std::ios::binary);
1126         if (!infoCacheFile) {
1127             LOGE("[GetModelSizeFromCache] checkCacheInfo failed, error happened when opening cache info file.");
1128             return 0;
1129         }
1130 
1131         std::string content((std::istreambuf_iterator<char>(infoCacheFile)), std::istreambuf_iterator<char>());
1132         infoCacheFile.close();
1133 
1134         if (!nlohmann::json::accept(content)) {
1135             LOGE("[GetModelSizeFromCache] checkCacheInfo JSON parse error.");
1136             return 0;
1137         }
1138 
1139         // parse the JSON string
1140         nlohmann::json j = nlohmann::json::parse(content);
1141 
1142         int64_t isExceedRamLimit = -1;
1143         if (j["data"].find("isExceedRamLimit") == j["data"].end()) {
1144             LOGW("[GetModelSizeFromCache] checkCacheInfo read cache isExceedRamLimit failed.");
1145         }
1146 
1147         isExceedRamLimit = j["data"]["isExceedRamLimit"].get<int64_t>();
1148         modelSize = isExceedRamLimit == 1 ? MORE_MODEL_MAX_LIMIT : MODEL_MAX_LIMIT;
1149     } else {
1150         modelSize = GetModelSizeFromFile(path);
1151     }
1152     return modelSize;
1153 }
1154 
GetModelSize()1155 size_t NNCompiler::GetModelSize()
1156 {
1157     size_t modelSize = 0;
1158     if (m_innerModel != nullptr) {
1159         modelSize = GetModelSizeFromModel(m_innerModel);
1160     } else {
1161         modelSize = GetModelSizeFromCache(m_cachePath, m_extensionConfig.modelName);
1162     }
1163 
1164     return modelSize;
1165 }
1166 
GetNodeIndices(const std::shared_ptr<mindspore::lite::LiteGraph> & liteGraph,size_t layer)1167 std::vector<mindspore::lite::LiteGraph::Node*> NNCompiler::GetNodeIndices(
1168     const std::shared_ptr<mindspore::lite::LiteGraph>& liteGraph, size_t layer)
1169 {
1170     std::vector<mindspore::lite::LiteGraph::Node*> nodes;
1171     size_t inputTensorSize = liteGraph->input_indices_.size();
1172     size_t outputTensorSize = liteGraph->output_indices_.size();
1173 
1174     size_t allnodeSize = liteGraph->all_nodes_.size();
1175     if (((inputTensorSize + outputTensorSize) * layer) >= allnodeSize) {
1176         LOGI("The all node size in model is too small, return all nodes.");
1177         return liteGraph->all_nodes_;
1178     }
1179 
1180     for (size_t i = 0; i < inputTensorSize * layer; ++i) {
1181         nodes.emplace_back(liteGraph->all_nodes_[i]);
1182     }
1183 
1184     for (size_t j = allnodeSize - 1; j >= (allnodeSize - (outputTensorSize * layer)); --j) {
1185         nodes.emplace_back(liteGraph->all_nodes_[j]);
1186     }
1187 
1188     LOGD("nodes size : %{public}zu.", nodes.size());
1189     return nodes;
1190 }
1191 
GetOnlineModelID(const std::shared_ptr<mindspore::lite::LiteGraph> & liteGraph)1192 size_t NNCompiler::GetOnlineModelID(const std::shared_ptr<mindspore::lite::LiteGraph>& liteGraph)
1193 {
1194     size_t inputSize = liteGraph->input_indices_.size();
1195     size_t outputSize = liteGraph->output_indices_.size();
1196     size_t allTensorSize = liteGraph->all_tensors_.size();
1197     size_t allNodesSize = liteGraph->all_nodes_.size();
1198 
1199     std::string onlineModelId = "";
1200     onlineModelId.append(std::to_string(inputSize));
1201     onlineModelId.append(std::to_string(outputSize));
1202     onlineModelId.append(std::to_string(allTensorSize));
1203     onlineModelId.append(std::to_string(allNodesSize));
1204 
1205     std::vector<mindspore::lite::LiteGraph::Node*> nodes = GetNodeIndices(liteGraph, EXTRACT_NODE_LAYER);
1206 
1207     for (auto node : nodes) {
1208         onlineModelId.append(node->name_);
1209     }
1210 
1211     return std::hash<std::string>{}(onlineModelId);
1212 }
1213 
GetNNRtModelIDFromModel(InnerModel * innerModel,size_t & nnrtModelID)1214 OH_NN_ReturnCode NNCompiler::GetNNRtModelIDFromModel(InnerModel* innerModel, size_t& nnrtModelID)
1215 {
1216     if (innerModel == nullptr) {
1217         LOGE("GetNNRtModelIDFromModel failed, model is nullptr.");
1218         return OH_NN_INVALID_PARAMETER;
1219     }
1220 
1221     auto liteGraph = innerModel->GetLiteGraphs();
1222     if (liteGraph == nullptr) {
1223         LOGE("GetNNRtModelIDFromModel failed, failed to get liteGraph.");
1224         return OH_NN_INVALID_PARAMETER;
1225     }
1226 
1227     nnrtModelID = GetOnlineModelID(liteGraph);
1228     return OH_NN_SUCCESS;
1229 }
1230 
GetNNRtModelIDFromCache(const std::string & path,const std::string & modelName,size_t & nnrtModelID)1231 OH_NN_ReturnCode NNCompiler::GetNNRtModelIDFromCache(const std::string& path, const std::string& modelName,
1232     size_t& nnrtModelID)
1233 {
1234     if (path.empty()) {
1235         LOGE("GetNNRtModelIDFromCache failed, path is empty");
1236         return OH_NN_INVALID_PARAMETER;
1237     }
1238 
1239     if (modelName.empty()) {
1240         LOGE("GetNNRtModelIDFromCache failed, modelName is empty");
1241         return OH_NN_INVALID_PARAMETER;
1242     }
1243 
1244     if (!std::filesystem::is_directory(path)) {
1245         LOGW("GetNNRtModelIDFromCache cvache path is not directory.");
1246         nnrtModelID = std::hash<std::string>{}(path);
1247         return OH_NN_SUCCESS;
1248     }
1249 
1250     std::string modelPath = path + "/" + modelName + "cache_info.nncache";
1251     char modelCachePath[PATH_MAX];
1252     if (realpath(modelPath.c_str(), modelCachePath) == nullptr) {
1253         LOGE("GetNNRtModelIDFromCache fail to get real path of cacheDir.");
1254         return OH_NN_INVALID_PARAMETER;
1255     }
1256 
1257     NNCompiledCache compiledCache;
1258     NNCompiledCacheInfo cacheInfo;
1259     OH_NN_ReturnCode retCode = compiledCache.SetBackend(m_backendID);
1260     if (retCode != OH_NN_SUCCESS) {
1261         LOGE("GetNNRtmodelIDFromCache failed, fail to set backend.");
1262         return retCode;
1263     }
1264 
1265     retCode = compiledCache.CheckCacheInfo(cacheInfo, modelCachePath);
1266     if (retCode != OH_NN_SUCCESS) {
1267         LOGE("GetNNRtmodelIDFromCache failed, fail to CheckCacheInfo.");
1268         return retCode;
1269     }
1270 
1271     if (cacheInfo.modelCheckSum.size() != NUMBER_CACHE_INFO_MEMBERS) {
1272         LOGE("GetNNRtmodelIDFromCache failed, fail to modelCheckSum.");
1273         return OH_NN_INVALID_PARAMETER;
1274     }
1275 
1276     std::string cacheStr = std::to_string(cacheInfo.modelCheckSum[CHECK_SUM_ZERO]) +
1277         std::to_string(cacheInfo.modelCheckSum[CHECK_SUM_ONE]) +
1278         std::to_string(cacheInfo.modelCheckSum[CHECK_SUM_TWO]);
1279     nnrtModelID = std::hash<std::string>{}(cacheStr);
1280 
1281     return OH_NN_SUCCESS;
1282 }
1283 
GetOnlineModelID()1284 size_t NNCompiler::GetOnlineModelID()
1285 {
1286     size_t nnrtModeId = 0;
1287     OH_NN_ReturnCode ret = GetNNRtModelIDFromCache(m_cachePath, m_extensionConfig.modelName, nnrtModeId);
1288     if (ret != OH_NN_SUCCESS && m_innerModel != nullptr) {
1289         ret = GetNNRtModelIDFromModel(m_innerModel, nnrtModeId);
1290     }
1291 
1292     if (ret != OH_NN_SUCCESS) {
1293         LOGE("[NNCompiler] GetOnlineModelID failed.");
1294         return 0;
1295     }
1296 
1297     return nnrtModeId;
1298 }
1299 } // NeuralNetworkRuntime
1300 } // OHOS
1301