• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2021 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/litert/delegate/npu/npu_manager.h"
18 #include <sys/system_properties.h>
19 #include <regex>
20 #include "include/hiai_ir_build.h"
21 #include "include/HiAiModelManagerService.h"
22 #include "src/common/file_utils.h"
23 #include "src/common/mmap_utils.h"
24 
25 namespace mindspore::lite {
26 constexpr int MAX_MODEL_NUM = 20;
27 constexpr int KIRIN_REGEX_MIN_SIZE = 2;
28 constexpr int KIRIN_VERSION_810 = 810;
29 constexpr int KIRIN_VERSION_820 = 820;
30 constexpr int KIRIN_VERSION_985 = 985;
CompareVersion(const std::string & version1,const std::string & version2)31 int NPUManager::CompareVersion(const std::string &version1, const std::string &version2) {
32   std::istringstream iss1(version1);
33   std::istringstream iss2(version2);
34   std::string string1;
35   std::string string2;
36   while (!iss1.eof() || !iss2.eof()) {
37     getline(iss1, string1, '.');
38     getline(iss2, string2, '.');
39     if (stoi(string1) > stoi(string2)) return 1;
40     if (stoi(string1) < stoi(string2)) return -1;
41     string1 = string2 = "0";
42   }
43   return 0;
44 }
45 
CheckEMUIVersion()46 bool NPUManager::CheckEMUIVersion() {
47   char emui[128] = {0x00};
48   __system_property_get("ro.build.version.emui", emui);
49   std::string emui_str = emui;
50   size_t pos = emui_str.find('_');
51   if (pos != std::string::npos) {
52     auto version = emui_str.substr(pos + 1);
53     int ret = CompareVersion(version, "10.0.0");
54     if (ret < 0) {
55       MS_LOG(WARNING) << "EMUI version " << version << " less than 10.0.0";
56       return false;
57     }
58   }
59   return true;
60 }
61 
Reset()62 void NPUManager::Reset() {
63   for (auto client : clients_) {
64     client->UnLoadModel();
65     client.reset();
66   }
67   clients_.clear();
68   subgraph_index_ = 0;
69   domi::HiaiIrBuild ir_build;
70   for (const auto &model_map : models_) {
71     auto model = model_map.second;
72     if (!model->is_freed_) {
73       UnmapMmapBuffer(const_cast<void *>(static_cast<const void *>(model->model_buffer_data_->data)),
74                       model->model_buffer_data_->length);
75       model->model_buffer_data_->data = nullptr;
76       model->model_buffer_data_->length = 0;
77       ir_build.ReleaseModelBuff(*model->model_buffer_data_);
78       model->is_freed_ = true;
79     }
80     model->model_buffer_data_.reset();
81     model->desc_.reset();
82     model->client_.reset();
83   }
84   models_.clear();
85 }
86 
CheckDDKVerGreatEqual(const std::string & spec_version)87 bool NPUManager::CheckDDKVerGreatEqual(const std::string &spec_version) {
88   auto client = std::make_shared<hiai::AiModelMngerClient>();
89   if (client->GetVersion() != nullptr) {
90     std::string version = client->GetVersion();
91     int ret = CompareVersion(version, spec_version);
92     if (ret < 0) {
93       MS_LOG(WARNING) << "DDK Version " << version << " less than " << spec_version;
94       return false;
95     }
96   } else {
97     MS_LOG(WARNING) << "Get DDK Version failed!";
98     return false;
99   }
100   return true;
101 }
102 
IsSupportNPU()103 bool NPUManager::IsSupportNPU() {
104   // Avoid multiple checks
105   if (!is_check_version_) {
106     is_check_version_ = true;
107     if (IsKirinChip() && CheckDDKVerGreatEqual("100.320.011.019")) {
108       is_support_npu_ = true;
109       MS_LOG(INFO) << "The current device support NPU.";
110     } else {
111       is_support_npu_ = false;
112       MS_LOG(WARNING) << "The current device NOT SUPPORT NPU.";
113     }
114     return is_support_npu_;
115   } else {
116     return is_support_npu_;
117   }
118 }
119 
IsKirinChip()120 bool NPUManager::IsKirinChip() {
121   char platform_info[PROP_VALUE_MAX] = {0};
122   if (__system_property_get("ro.hardware", platform_info) <= 0) {
123     MS_LOG(WARNING) << "Get board platform failed.";
124     return false;
125   }
126   std::string platform_info_str = std::string(platform_info);
127   std::cmatch match_result;
128   // to match kirin985/kirin990/kirin990 5g/kirin9000/kirin9000E
129   std::regex kirin_chip("kirin([0-9]+)[A-Z]*");
130   auto ret = std::regex_match(platform_info_str.c_str(), match_result, kirin_chip);
131   if (!ret || match_result.size() < KIRIN_REGEX_MIN_SIZE || match_result[1].length() == 0) {
132     MS_LOG(WARNING) << "The board platform is not a kirin chip.";
133     return false;
134   }
135   int kirin_number = std::stoi(match_result[1]);
136   return kirin_number >= KIRIN_VERSION_985 || kirin_number == KIRIN_VERSION_810 || kirin_number == KIRIN_VERSION_820;
137 }
138 
StoreCache(const std::string & cache_om_name,const std::shared_ptr<domi::ModelBufferData> & model_buffer_data)139 int NPUManager::StoreCache(const std::string &cache_om_name,
140                            const std::shared_ptr<domi::ModelBufferData> &model_buffer_data) {
141   // Store .om Cache
142   if (cache_dir_.empty()) {
143     return RET_OK;
144   }
145   if (CreateDir(cache_dir_) != RET_OK) {
146     MS_LOG(ERROR) << "Create cache_file folder failed.";
147     return RET_ERROR;
148   }
149   auto real_cache_dir = RealPath(cache_dir_.c_str());
150   if (real_cache_dir.empty()) {
151     MS_LOG(ERROR) << "Invalid cache directory";
152     return RET_ERROR;
153   }
154   if (WriteToBin(real_cache_dir + "/" + cache_om_name, model_buffer_data->data, model_buffer_data->length) != RET_OK) {
155     MS_LOG(ERROR) << "Store Cache failed for model: " << cache_om_name;
156     return RET_ERROR;
157   }
158   return RET_OK;
159 }
160 
LoadCache(const std::string & cache_om_name)161 std::shared_ptr<domi::ModelBufferData> NPUManager::LoadCache(const std::string &cache_om_name) {
162   // Load .om Cache
163   if (cache_dir_.empty()) {
164     return nullptr;
165   }
166   auto real_cache_dir = RealPath(cache_dir_.c_str());
167   if (real_cache_dir.empty()) {
168     MS_LOG(ERROR) << "Invalid cache directory.";
169     return nullptr;
170   }
171   auto cache_om_path = real_cache_dir + "/" + cache_om_name;
172   size_t len;
173   auto buf = ReadFileByMmap(cache_om_path, &len);
174   if (buf == nullptr) {
175     MS_LOG(WARNING) << "The Cache om model does not exist.";
176     return nullptr;
177   }
178   auto model_buffer_data = std::make_shared<domi::ModelBufferData>();
179   model_buffer_data->data = buf;
180   model_buffer_data->length = static_cast<uint32_t>(len);
181   return model_buffer_data;
182 }
183 
AddModel(std::shared_ptr<domi::ModelBufferData> model_buffer_data,const std::string & model_name,int frequency)184 int NPUManager::AddModel(std::shared_ptr<domi::ModelBufferData> model_buffer_data, const std::string &model_name,
185                          int frequency) {
186   auto model = std::make_shared<SubGraphModel>(subgraph_index_, model_name, model_buffer_data);
187   auto desc = std::make_shared<hiai::AiModelDescription>(model_name, frequency, 0, 0, 0);
188   model->desc_ = desc;
189   models_.insert({model_name, model});
190   subgraph_index_++;
191   return RET_OK;
192 }
193 
CreateAiModelMngerClient()194 std::shared_ptr<hiai::AiModelMngerClient> NPUManager::CreateAiModelMngerClient() {
195   auto client = std::make_shared<hiai::AiModelMngerClient>();
196   if (client == nullptr) {
197     MS_LOG(ERROR) << "NPU client is nullptr.";
198     return nullptr;
199   }
200   int ret = client->Init(nullptr);
201   if (ret != hiai::AI_SUCCESS) {
202     MS_LOG(ERROR) << "NPU client init failed. code is " << ret;
203     return nullptr;
204   }
205   return client;
206 }
207 
LoadOMModel()208 int NPUManager::LoadOMModel() {
209   std::vector<std::shared_ptr<hiai::AiModelDescription>> models_desc;
210   std::shared_ptr<hiai::AiModelMngerClient> client = nullptr;
211   std::shared_ptr<hiai::AiModelBuilder> mc_builder = nullptr;
212   std::unordered_map<std::shared_ptr<hiai::AiModelBuilder>, hiai::MemBuffer *> builder_buffer_map;
213   int total = 0;
214   for (const auto &model_map : models_) {
215     if (total % MAX_MODEL_NUM == 0) {
216       client = CreateAiModelMngerClient();
217       if (client == nullptr) {
218         MS_LOG(ERROR) << "Create Client failed.";
219         return RET_ERROR;
220       }
221       mc_builder = std::make_shared<hiai::AiModelBuilder>(client);
222       if (mc_builder == nullptr) {
223         MS_LOG(ERROR) << "Create AiModelBuilder failed.";
224         return RET_ERROR;
225       }
226     }
227     total++;
228     auto model = model_map.second;
229     if (model->is_loaded_ && model->is_freed_) {
230       continue;
231     }
232     models_desc.push_back(model->desc_);
233 
234     auto buffer = mc_builder->InputMemBufferCreate(model->model_buffer_data_->data, model->model_buffer_data_->length);
235     if (buffer == nullptr) {
236       MS_LOG(ERROR) << "NPU input memory buffer create failed.";
237       return RET_ERROR;
238     }
239     builder_buffer_map.insert({mc_builder, buffer});
240     model->desc_->SetModelBuffer(buffer->GetMemBufferData(), buffer->GetMemBufferSize());
241     if (models_desc.size() == MAX_MODEL_NUM) {
242       auto ret = LoadModel(client, models_desc);
243       if (ret != RET_ERROR) {
244         MS_LOG(ERROR) << "Client load model failed.";
245         return RET_ERROR;
246       }
247       models_desc.clear();
248     }
249   }
250 
251   if (!models_desc.empty()) {
252     auto ret = LoadModel(client, models_desc);
253     if (ret != RET_OK) {
254       MS_LOG(ERROR) << "Client load model failed.";
255       return RET_ERROR;
256     }
257     models_desc.clear();
258   }
259 
260   for (auto it : builder_buffer_map) {
261     it.first->MemBufferDestroy(it.second);
262   }
263   builder_buffer_map.clear();
264   return RET_OK;
265 }
266 
GetClient(const std::string & model_name)267 std::shared_ptr<hiai::AiModelMngerClient> NPUManager::GetClient(const std::string &model_name) {
268   if (models_.find(model_name) == models_.end() || models_[model_name] == nullptr) {
269     return nullptr;
270   }
271   return models_[model_name]->client_;
272 }
273 
LoadModel(const std::shared_ptr<hiai::AiModelMngerClient> & client,std::vector<std::shared_ptr<hiai::AiModelDescription>> desc_list)274 int NPUManager::LoadModel(const std::shared_ptr<hiai::AiModelMngerClient> &client,
275                           std::vector<std::shared_ptr<hiai::AiModelDescription>> desc_list) {
276   auto ret = client->Load(desc_list);
277   if (ret != hiai::AI_SUCCESS) {
278     MS_LOG(ERROR) << "Client load model failed." << ret;
279     return RET_ERROR;
280   }
281 
282   for (const auto &desc : desc_list) {
283     auto it = models_.find(desc->GetName());
284     it->second->is_loaded_ = true;
285     it->second->client_ = client;
286   }
287 
288   this->clients_.push_back(client);
289   return RET_OK;
290 }
291 }  // namespace mindspore::lite
292