1 /**
2 * Copyright 2019 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 <unistd.h>
18 #include <fstream>
19 #include <thread>
20 #include "nlohmann/json.hpp"
21 #include "securec/include/securec.h"
22 #include "utils/log_adapter.h"
23 #include "utils/convert_utils.h"
24 #include "utils/system/sha256.h"
25 #include "backend/kernel_compiler/common_utils.h"
26 namespace mindspore {
27 namespace kernel {
28 namespace {
CheckHash(const std::string & json_file,const std::string & bin_file,const nlohmann::json & js)29 bool CheckHash(const std::string &json_file, const std::string &bin_file, const nlohmann::json &js) {
30 if (js.find("sha256") == js.end()) {
31 MS_LOG(ERROR) << "No sha256 found in " << json_file;
32 return false;
33 }
34 std::string sha256_cal = system::sha256::GetHashFromFile(bin_file);
35 std::string sha256_str = js["sha256"];
36 if (sha256_cal.empty() || sha256_cal != sha256_str) {
37 MS_LOG(ERROR) << "Cal sha256 of " << bin_file << " failed.";
38 return false;
39 }
40 return true;
41 }
42 } // namespace
43
ReadFromJsonFileHelper(std::ifstream & kernel_bin)44 bool KernelPack::ReadFromJsonFileHelper(std::ifstream &kernel_bin) {
45 size_t bin_size = LongToSize(kernel_bin.seekg(0, std::ios::end).tellg());
46 // free old data
47 if (kernel_ != nullptr) {
48 delete[] kernel_;
49 kernel_ = nullptr;
50 }
51
52 void *ptr = static_cast<void *>(new (std::nothrow) uint8_t[sizeof(KernelPack) + bin_size]);
53 if (ptr != nullptr) {
54 kernel_ = static_cast<FlexArray *>(ptr);
55 }
56 if (kernel_ == nullptr) {
57 MS_LOG(ERROR) << "Memory malloc failed.";
58 kernel_bin.close();
59 return false;
60 }
61 if (memset_s(kernel_, sizeof(KernelPack) + bin_size, 0, sizeof(KernelPack) + bin_size) != EOK) {
62 MS_LOG(ERROR) << "Memset kernel_ failed.";
63 delete[] kernel_;
64 kernel_ = nullptr;
65 kernel_bin.close();
66 return false;
67 }
68 kernel_->len = bin_size;
69 (void)kernel_bin.seekg(0, std::ios::beg);
70 (void)kernel_bin.read(kernel_->contents, SizeToLong(kernel_->len));
71 return true;
72 }
73
ReadFromJsonFile(const std::string & json_f,const std::string & processor)74 bool KernelPack::ReadFromJsonFile(const std::string &json_f, const std::string &processor) {
75 if (json_f.length() <= strlen(kJsonSuffix)) {
76 MS_LOG(ERROR) << "Please check json path, file name: " << json_f;
77 return false;
78 }
79
80 std::ifstream kernel_json(json_f);
81 if (!kernel_json.is_open()) {
82 MS_LOG(DEBUG) << "Read json file(" << json_f << ") error, please check kernel_meta.";
83 return false;
84 }
85 nlohmann::json js;
86 kernel_json >> js;
87
88 size_t bin_size = LongToSize(kernel_json.seekg(0, std::ios::end).tellg());
89 void *ptr = static_cast<void *>(new (std::nothrow) uint8_t[sizeof(KernelPack) + bin_size]);
90 if (ptr != nullptr) {
91 json_ = static_cast<FlexArray *>(ptr);
92 }
93 if (json_ == nullptr) {
94 MS_LOG(ERROR) << "memory malloc failed.";
95 kernel_json.close();
96 return false;
97 }
98 json_->len = bin_size;
99 (void)kernel_json.seekg(0, std::ios::beg);
100 (void)kernel_json.read(json_->contents, SizeToLong(json_->len));
101
102 if (processor == kProcessorCuda) {
103 std::string bin_f = json_f.substr(0, json_f.length() - 5) + ".ptx";
104 std::ifstream kernelbin(bin_f);
105 if (!kernelbin.is_open()) {
106 MS_LOG(ERROR) << "read kernel ptx file error, please check kernelmeta.";
107 kernel_json.close();
108 return false;
109 }
110
111 if (!ReadFromJsonFileHelper(kernelbin)) {
112 delete[] json_;
113 json_ = nullptr;
114 kernel_json.close();
115 return false;
116 }
117 kernel_json.close();
118 if (!CheckHash(json_f, bin_f, js)) {
119 return false;
120 }
121
122 // cuda json file may have workspace information
123 if (js.find("workspace") != js.end()) {
124 auto workspace = js.at("workspace");
125 std::vector<size_t> sizes = workspace.at("size");
126 for (auto size : sizes) {
127 kernel_json_info_.workspaces.push_back(size);
128 }
129 }
130
131 return true;
132 }
133
134 std::string binfile_suffix = js["binFileSuffix"];
135 std::string bin_f = json_f.substr(0, json_f.length() - 5) + binfile_suffix;
136 if (binfile_suffix == ".so") {
137 // change "xx/xx.so" -> "xx/libxx.so"
138 auto sp = bin_f.rfind('/');
139 if (sp == std::string::npos) {
140 MS_LOG(ERROR) << "illegal bin file path " << bin_f;
141 kernel_json.close();
142 return false;
143 }
144 bin_f = bin_f.substr(0, sp + 1) + "lib" + bin_f.substr(sp + 1, bin_f.length() - sp - 1);
145 }
146
147 std::ifstream kernelbin(bin_f, std::ios::binary);
148 if (!kernelbin.is_open()) {
149 MS_LOG(ERROR) << "read kernel binary file error, please check kernelmeta.";
150 kernel_json.close();
151 delete[] json_;
152 json_ = nullptr;
153 return false;
154 }
155
156 MS_LOG(INFO) << "kernelbin_name:" << bin_f;
157 if (!ReadFromJsonFileHelper(kernelbin)) {
158 delete[] json_;
159 json_ = nullptr;
160 kernel_json.close();
161 return false;
162 }
163 kernel_json.close();
164
165 if (!CheckHash(json_f, bin_f, js)) {
166 return false;
167 }
168
169 return true;
170 }
171
ParseKernelJson(const nlohmann::json & js)172 void KernelPack::ParseKernelJson(const nlohmann::json &js) {
173 kernel_json_info_.bin_file_name = js["binFileName"];
174 kernel_json_info_.bin_file_suffix = js["binFileSuffix"];
175 kernel_json_info_.block_dim = js["blockDim"];
176 kernel_json_info_.kernel_name = js["kernelName"];
177 kernel_json_info_.magic = js["magic"];
178 if (js.contains("opParaSize")) {
179 kernel_json_info_.op_para_size = js["opParaSize"];
180 }
181 if (js.find("parameters") != js.end()) {
182 if (!js.at("parameters").is_array()) {
183 MS_LOG(DEBUG) << "Format error!,parameters should be array.";
184 }
185 std::vector<size_t> sizes = js.at("parameters");
186 for (auto size : sizes) {
187 kernel_json_info_.parameters.push_back(size);
188 }
189 }
190 if (js.find("workspace") != js.end()) {
191 auto workspace = js.at("workspace");
192 std::vector<size_t> sizes = workspace.at("size");
193 for (auto size : sizes) {
194 kernel_json_info_.workspaces.push_back(size);
195 }
196 }
197 kernel_json_info_.sha256 = js["sha256"];
198 }
199
LoadKernelMeta(const std::string & json_f)200 bool KernelPack::LoadKernelMeta(const std::string &json_f) {
201 if (json_f.length() <= strlen(kJsonSuffix)) {
202 MS_LOG(ERROR) << "please check json path.";
203 return false;
204 }
205 std::ifstream kernel_json(json_f);
206 if (!kernel_json.is_open()) {
207 MS_LOG(INFO) << "Open json file: " << json_f << " error, please check kernel_meta.";
208 return false;
209 }
210 nlohmann::json js;
211 try {
212 kernel_json >> js;
213 kernel_json.close();
214 } catch (std::exception &e) {
215 MS_LOG(WARNING) << "Parse json file error: " << json_f << ", sleep 500ms and retry again. error ms: " << e.what();
216 kernel_json.close();
217 std::this_thread::sleep_for(std::chrono::microseconds(500000));
218 std::ifstream retry_tmp(json_f);
219 if (!retry_tmp.is_open()) {
220 MS_LOG(INFO) << "Open json file: " << json_f << " error, please check kernel_meta.";
221 return false;
222 }
223 retry_tmp >> js;
224 retry_tmp.close();
225 }
226 ParseKernelJson(js);
227
228 std::string bin_f = json_f.substr(0, json_f.length() - 5) + kernel_json_info_.bin_file_suffix;
229 if (kernel_json_info_.bin_file_suffix == ".so") {
230 // change "xx/xx.so" -> "xx/libxx.so"
231 auto sp = bin_f.rfind('/');
232 if (sp == std::string::npos) {
233 MS_LOG(ERROR) << "illegal bin file path " << bin_f;
234 return false;
235 }
236 bin_f = bin_f.substr(0, sp + 1) + "lib" + bin_f.substr(sp + 1, bin_f.length() - sp - 1);
237 }
238
239 std::ifstream kernelbin(bin_f, std::ios::binary);
240 if (!kernelbin.is_open()) {
241 MS_LOG(ERROR) << "read kernel binary file error, please check kernelmeta.";
242 return false;
243 }
244
245 if (!ReadFromJsonFileHelper(kernelbin)) {
246 return false;
247 }
248
249 return CheckHash(json_f, bin_f, js);
250 }
251
kernel_json_info() const252 KernelJsonInfo KernelPack::kernel_json_info() const { return kernel_json_info_; }
253 } // namespace kernel
254 } // namespace mindspore
255