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