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