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