1 /**
2 * Copyright 2020-2023 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 "include/common/debug/common.h"
18
19 #include <memory>
20 #include <iomanip>
21 #include <optional>
22 #include <fstream>
23 #include <string>
24 #include <random>
25 #include "ops/ascend_op_name.h"
26 #include "utils/system/env.h"
27 #include "utils/system/file_system.h"
28 #include "utils/log_adapter.h"
29 #include "utils/file_utils.h"
30 #include "include/common/utils/utils.h"
31 #include "utils/convert_utils_base.h"
32
33 namespace mindspore {
NeedMapping(const std::string & origin_name)34 bool Common::NeedMapping(const std::string &origin_name) {
35 #if defined(SYSTEM_ENV_POSIX)
36 if (origin_name.length() > NAME_MAX) {
37 return true;
38 } else {
39 return false;
40 }
41 #endif
42 return false;
43 }
44
GetRandomStr(size_t str_len)45 std::string Common::GetRandomStr(size_t str_len) {
46 std::random_device rd;
47 std::mt19937 generator(rd());
48 std::uniform_int_distribution<int> distribution{'a', 'z'};
49
50 std::string rand_str(str_len, '\0');
51 std::generate(rand_str.begin(), rand_str.end(), [&distribution, &generator]() { return distribution(generator); });
52
53 return rand_str;
54 }
55
GetRandomStr()56 std::string Common::GetRandomStr() {
57 std::string npy_suffix = ".npy";
58 #if defined(SYSTEM_ENV_POSIX)
59 std::lock_guard<std::mutex> guard(random_data_lock_);
60 #endif
61 #ifndef _MSC_VER
62 unsigned int seed = static_cast<unsigned int>(GetTimeStamp());
63 std::string random_name = std::to_string(rand_r(&seed)) + npy_suffix;
64 #else
65 std::random_device rd;
66 std::mt19937 gen(rd());
67 constexpr int min_value = 0;
68 std::uniform_int_distribution<> distrib(min_value);
69 std::string random_name = std::to_string(distrib(gen)) + npy_suffix;
70 #endif
71 return random_name;
72 }
73
MappingName(const std::string & input_path,std::optional<std::string> * prefix_path,std::optional<std::string> * origin_name,std::optional<std::string> * mapped_name)74 bool Common::MappingName(const std::string &input_path, std::optional<std::string> *prefix_path,
75 std::optional<std::string> *origin_name, std::optional<std::string> *mapped_name) {
76 FileUtils::SplitDirAndFileName(input_path, prefix_path, origin_name);
77 if (!prefix_path->has_value() || !origin_name->has_value()) {
78 MS_LOG(ERROR) << "Cannot get prefix_path or file_name from: " << input_path;
79 return false;
80 }
81 auto origin_name_str = origin_name->value();
82 if (!NeedMapping(origin_name_str)) {
83 MS_EXCEPTION_IF_NULL(mapped_name);
84 *mapped_name = origin_name_str;
85 return false;
86 }
87 MS_LOG(INFO) << "The file name: " << input_path << " is too long, change it to a random string.";
88 // name, max_loop is used to avoid the foreverloop.
89 size_t loop_count = 0;
90 size_t max_loop = 2;
91 std::string file_path;
92 while (loop_count < max_loop) {
93 loop_count += 1;
94 *mapped_name = GetRandomStr();
95 file_path = prefix_path->value() + "/" + mapped_name->value();
96 if (FileExists(file_path)) {
97 continue;
98 }
99 return true;
100 }
101 MS_LOG(WARNING) << "Random strings are repeated, which may lead to coverring the old data! File path is: "
102 << file_path;
103 return true;
104 }
105
CreatePrefixPath(const std::string & input_path,const bool support_relative_path)106 std::optional<std::string> Common::CreatePrefixPath(const std::string &input_path, const bool support_relative_path) {
107 std::optional<std::string> prefix_path;
108 std::optional<std::string> file_name;
109 FileUtils::SplitDirAndFileName(input_path, &prefix_path, &file_name);
110 if (!file_name.has_value()) {
111 MS_LOG(ERROR) << "Cannot get file_name from: " << input_path;
112 return std::nullopt;
113 }
114 auto file_name_str = file_name.value();
115 #if defined(SYSTEM_ENV_POSIX)
116 if (file_name_str.length() > NAME_MAX) {
117 MS_LOG(ERROR) << "The length of file name: " << file_name_str.length() << " exceeds limit: " << NAME_MAX;
118 return std::nullopt;
119 }
120 #endif
121
122 std::string prefix_path_str;
123 if (prefix_path.has_value()) {
124 auto create_prefix_path = FileUtils::CreateNotExistDirs(prefix_path.value(), support_relative_path);
125 if (!create_prefix_path.has_value()) {
126 return std::nullopt;
127 }
128 prefix_path_str = create_prefix_path.value();
129 } else {
130 auto pwd_path = FileUtils::GetRealPath("./");
131 if (!pwd_path.has_value()) {
132 MS_LOG(ERROR) << "Cannot get pwd path";
133 return std::nullopt;
134 }
135 prefix_path_str = pwd_path.value();
136 }
137 return std::string(prefix_path_str + "/" + file_name_str);
138 }
139
CommonFuncForConfigPath(const std::string & default_path,const std::string & env_path,std::string * const value)140 bool Common::CommonFuncForConfigPath(const std::string &default_path, const std::string &env_path,
141 std::string *const value) {
142 MS_EXCEPTION_IF_NULL(value);
143 value->clear();
144 if (!env_path.empty()) {
145 char real_path[PATH_MAX] = {0};
146 #if defined(SYSTEM_ENV_WINDOWS)
147 if (_fullpath(real_path, common::SafeCStr(env_path), PATH_MAX) == nullptr) {
148 MS_LOG(ERROR) << "The dir " << env_path << " does not exist.";
149 return false;
150 }
151 *value = real_path;
152 return true;
153 #else
154
155 if (realpath(env_path.c_str(), real_path)) {
156 *value = real_path;
157 return true;
158 }
159 MS_LOG(ERROR) << "Invalid env path, path : " << env_path;
160 return false;
161 #endif
162 }
163 *value = default_path;
164 return true;
165 }
166
GetConfigFile(const std::string & env)167 std::optional<std::string> Common::GetConfigFile(const std::string &env) {
168 if (env.empty()) {
169 MS_LOG(EXCEPTION) << "Invalid env";
170 }
171 auto config_path_str = common::GetEnv(env);
172 if (config_path_str.empty()) {
173 MS_LOG(ERROR) << "Please export env:" << env;
174 return std::nullopt;
175 }
176 MS_LOG(INFO) << "Async Dump Getenv env:" << env << "=" << config_path_str;
177
178 auto real_path = FileUtils::GetRealPath(common::SafeCStr(config_path_str));
179 if (!real_path.has_value()) {
180 MS_LOG(ERROR) << "Can't get real_path";
181 return std::nullopt;
182 }
183 std::string dump_config_file = real_path.value();
184 std::shared_ptr<system::FileSystem> fs = system::Env::GetFileSystem();
185 MS_EXCEPTION_IF_NULL(fs);
186 if (!fs->FileExist(dump_config_file)) {
187 MS_LOG(ERROR) << dump_config_file << " not exist.";
188 return std::nullopt;
189 }
190 auto point_pos = dump_config_file.find_last_of('.');
191 if (point_pos == std::string::npos) {
192 MS_LOG(EXCEPTION) << "Invalid json file name:" << dump_config_file;
193 }
194 auto suffix = dump_config_file.substr(point_pos + 1);
195 if (suffix != "json") {
196 MS_LOG(EXCEPTION) << "[DataDump] dump config file suffix only supports json! But got:." << suffix;
197 }
198 return dump_config_file;
199 }
200
IsStrLengthValid(const std::string & str,size_t length_limit,const std::string & error_message)201 bool Common::IsStrLengthValid(const std::string &str, size_t length_limit, const std::string &error_message) {
202 auto len_str = str.length();
203 if (len_str > length_limit) {
204 MS_LOG(ERROR) << error_message << "The length is " << str.length() << ", exceeding the limit of " << length_limit
205 << ".";
206 return false;
207 }
208 return true;
209 }
210
IsEveryFilenameValid(const std::string & path,size_t length_limit,const std::string & error_message)211 bool Common::IsEveryFilenameValid(const std::string &path, size_t length_limit, const std::string &error_message) {
212 if (path.empty()) {
213 MS_LOG(WARNING) << error_message << "The path is empty.";
214 return false;
215 }
216 size_t len_path = path.length();
217 size_t left_pos = 0;
218 for (size_t i = 0; i < len_path; i++) {
219 if (i != 0) {
220 if (path[i] == '\\' || path[i] == '/') {
221 auto cur_len = i - left_pos;
222 if (cur_len > length_limit) {
223 MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is "
224 << cur_len << ". It is out of the limit which is " << length_limit << ".";
225 return false;
226 }
227 left_pos = i + 1;
228 }
229 }
230 }
231 if (!(path[len_path - 1] == '\\' || path[len_path - 1] == '/')) {
232 auto cur_len = len_path - left_pos;
233 if (cur_len > length_limit) {
234 MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is " << cur_len
235 << ". It is out of the limit which is " << length_limit << ".";
236 return false;
237 }
238 }
239 return true;
240 }
241
IsPathValid(const std::string & path,size_t length_limit,const std::string & error_message)242 bool Common::IsPathValid(const std::string &path, size_t length_limit, const std::string &error_message) {
243 std::string err_msg = "Detail: ";
244 if (!error_message.empty()) {
245 err_msg = error_message + " " + err_msg;
246 }
247
248 if (path.empty()) {
249 MS_LOG(WARNING) << err_msg << "The path is empty.";
250 return false;
251 }
252
253 if (!IsStrLengthValid(path, length_limit, err_msg)) {
254 return false;
255 }
256
257 if (!std::all_of(path.begin(), path.end(), [](char c) {
258 return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '.' || c == '/';
259 })) {
260 MS_LOG(ERROR) << err_msg << "The path only supports alphabets, digit or {'-', '_', '.', '/'}, but got:" << path
261 << ".";
262 return false;
263 }
264
265 if (path[0] != '/') {
266 MS_LOG(ERROR) << err_msg << "The path only supports absolute path and should start with '/'.";
267 return false;
268 }
269
270 if (!IsEveryFilenameValid(path, MAX_OS_FILENAME_LENGTH, err_msg)) {
271 return false;
272 }
273 return true;
274 }
275
IsFilenameValid(const std::string & filename,size_t length_limit,const std::string & error_message)276 bool Common::IsFilenameValid(const std::string &filename, size_t length_limit, const std::string &error_message) {
277 std::string err_msg = "Detail: ";
278 if (!error_message.empty()) {
279 err_msg = error_message + " " + err_msg;
280 }
281
282 if (filename.empty()) {
283 MS_LOG(WARNING) << err_msg << "The filename is empty.";
284 return false;
285 }
286
287 if (!IsStrLengthValid(filename, length_limit, err_msg)) {
288 return false;
289 }
290 auto func = [](char c) { return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '.'; };
291 if (!std::all_of(filename.begin(), filename.end(), func)) {
292 MS_LOG(ERROR) << err_msg << "The filename only supports alphabets, digit or {'-', '_', '.'}, but got:" << filename
293 << ".";
294 return false;
295 }
296 return true;
297 }
298
AddId(const std::string & filename,const std::string & suffix)299 std::string Common::AddId(const std::string &filename, const std::string &suffix) {
300 std::ostringstream s;
301 auto i = filename.rfind(suffix);
302 const int spaces = 4;
303 if (i >= filename.size()) {
304 s << filename;
305 s << "_" << std::setfill('0') << std::setw(spaces) << (g_id_);
306 } else {
307 s << filename.substr(0, i);
308 s << "_" << std::setfill('0') << std::setw(spaces) << (g_id_);
309 if (i + 1 < filename.size()) {
310 s << filename.substr(i);
311 }
312 }
313 ++g_id_;
314 return s.str();
315 }
316
SaveStringToFile(const std::string filename,const std::string string_info)317 bool Common::SaveStringToFile(const std::string filename, const std::string string_info) {
318 if (filename.size() >= PATH_MAX) {
319 MS_LOG(ERROR) << "File path " << filename << " is too long.";
320 return false;
321 }
322 auto real_path = CreatePrefixPath(filename, true);
323 if (!real_path.has_value()) {
324 MS_LOG(ERROR) << "Get real path failed. path=" << filename;
325 return false;
326 }
327
328 ChangeFileMode(real_path.value(), S_IRWXU);
329 std::ofstream ofs;
330 ofs.open(real_path.value());
331
332 if (!ofs.is_open()) {
333 MS_LOG(ERROR) << "Open dump file '" << real_path.value() << "' failed!" << ErrnoToString(errno);
334 return false;
335 }
336 ofs << string_info << std::endl;
337 ofs.close();
338 // set file mode to read only by user
339 ChangeFileMode(real_path.value(), S_IRUSR);
340 return true;
341 }
342
FileExists(const std::string & filepath)343 bool Common::FileExists(const std::string &filepath) {
344 std::ifstream f(filepath);
345 bool cache_file_existed = f.good();
346 f.close();
347 return cache_file_existed;
348 }
349
GetUserDefineCachePath()350 std::string Common::GetUserDefineCachePath() {
351 static std::string config_path = "";
352 if (config_path != "") {
353 return config_path;
354 }
355 config_path = MsContext::GetInstance()->get_param<std::string>(MS_CTX_COMPILE_CACHE_PATH);
356 if (config_path.empty()) {
357 config_path = common::GetEnv(kCompilerCachePath);
358 }
359 if (config_path.empty()) {
360 config_path = "./";
361 } else {
362 (void)FileUtils::CreateNotExistDirs(config_path, true);
363 }
364 if (config_path[config_path.length() - 1] != '/') {
365 config_path += "/";
366 }
367 return config_path;
368 }
369
GetCompilerCachePath()370 std::string Common::GetCompilerCachePath() {
371 static const std::string user_defined_path = GetUserDefineCachePath();
372 std::string rank_id_str = common::GetEnv(kRankID);
373 if (rank_id_str.empty()) {
374 MS_LOG(DEBUG) << "Environment variable 'RANK_ID' is empty, using the default value: 0";
375 rank_id_str = "0";
376 }
377 const std::string compile_cache_dir = user_defined_path + "rank_" + rank_id_str + "/";
378 return compile_cache_dir;
379 }
380
GetKernelMetaTempDir()381 std::string Common::GetKernelMetaTempDir() {
382 auto cache_path = GetUserDefineCachePath();
383 std::string rank_id_str = common::GetEnv(kRankID);
384 if (rank_id_str.empty()) {
385 MS_LOG(DEBUG) << "Environment variable 'RANK_ID' is empty, using the default value: 0";
386 rank_id_str = "0";
387 }
388 auto kernel_meta_temp_dir = cache_path + +"rank_" + rank_id_str + "/kernel_meta_temp_dir/";
389 (void)FileUtils::CreateNotExistDirs(kernel_meta_temp_dir, true);
390 return kernel_meta_temp_dir;
391 }
392
GetDebugTerminate()393 bool Common::GetDebugTerminate() { return debugger_terminate_; }
394
GetDebugExitSuccess()395 bool Common::GetDebugExitSuccess() { return exit_success_; }
396
DebugTerminate(bool val,bool exit_success)397 void Common::DebugTerminate(bool val, bool exit_success) {
398 debugger_terminate_ = val;
399 exit_success_ = exit_success;
400 }
401
GetTimeStamp()402 uint64_t Common::GetTimeStamp() {
403 auto cur_sys_time = std::chrono::system_clock::now();
404 auto timestamp = std::chrono::duration_cast<std::chrono::microseconds>(cur_sys_time.time_since_epoch()).count();
405 return static_cast<uint64_t>(timestamp);
406 }
407
CheckInterval()408 bool Common::CheckInterval() {
409 int interval = 1;
410 static std::string interval_str = common::GetEnv("MS_DEV_DUMP_IR_INTERVAL");
411 if (interval_str.size() >= 1) {
412 try {
413 interval = std::stoi(interval_str);
414 } catch (const std::invalid_argument &ia) {
415 MS_LOG(EXCEPTION) << "Invalid argument: " << ia.what() << " when parse " << interval_str
416 << ". Please set this env variable to int value.";
417 }
418 } else {
419 return true;
420 }
421 if (interval < 1) {
422 MS_LOG(EXCEPTION) << "Dump IR interval should be greater than 0.";
423 }
424 const int check = SizeToInt(g_id_ % interval);
425 if (check == 0) {
426 return true;
427 }
428 return false;
429 }
430
CheckIfPrintIrPass(const std::string & pass_name)431 bool Common::CheckIfPrintIrPass(const std::string &pass_name) {
432 static const auto input_name = common::GetEnv("MS_DEV_DUMP_IR_PASSES");
433 static std::set<std::string> tokens;
434 if (input_name.size() == 0) {
435 return CheckInterval();
436 }
437 if (tokens.empty()) {
438 const char split = ',';
439 std::istringstream iss(input_name);
440 std::string token;
441 while (std::getline(iss, token, split)) {
442 (void)tokens.emplace(token);
443 }
444 }
445 for (const auto &element : tokens) {
446 auto sub_len = pass_name.find(element);
447 if (sub_len != std::string::npos) {
448 return true;
449 }
450 }
451 return false;
452 }
453
454 struct GlogLogDirRegister {
GlogLogDirRegistermindspore::GlogLogDirRegister455 GlogLogDirRegister() {
456 const char *logtostderr = std::getenv("GLOG_logtostderr");
457 const char *log_dir = std::getenv("GLOG_log_dir");
458 if (logtostderr != nullptr && log_dir != nullptr) {
459 std::string logtostderr_str = std::string(logtostderr);
460 std::string log_dir_str = std::string(log_dir);
461 if (logtostderr_str != "0") {
462 return;
463 }
464 const char *rank_id = std::getenv("RANK_ID");
465 const char *gpu_rank_id = std::getenv("OMPI_COMM_WORLD_RANK");
466 const char *ms_node_id = std::getenv("MS_NODE_ID");
467 std::string rank = "0";
468 if (rank_id != nullptr) {
469 rank = std::string(rank_id);
470 } else if (gpu_rank_id != nullptr) {
471 rank = std::string(gpu_rank_id);
472 } else if (ms_node_id != nullptr) {
473 rank = std::string(ms_node_id);
474 }
475 log_dir_str += "/rank_" + rank + "/logs/";
476 auto real_log_dir_str = Common::CreatePrefixPath(log_dir_str, true);
477 // While 'GLOG_logtostderr' = 0, logs output to files. 'GLOG_log_dir' must be specified as the path of log files.
478 // Here can not throw exception and use python to catch, because the PYBIND11_MODULE is not yet been initialed.
479 if (!real_log_dir_str.has_value()) {
480 MS_LOG(ERROR) << "The path of log files, which set by 'GLOG_log_dir', is invalid.";
481 exit(EXIT_FAILURE);
482 }
483 if (rank_id != nullptr && gpu_rank_id != nullptr && std::string(rank_id) != std::string(gpu_rank_id)) {
484 MS_LOG(WARNING) << "Environment variables RANK_ID and OMPI_COMM_WORLD_RANK set by different values: RANK_ID="
485 << std::string(rank_id) << ", OMPI_COMM_WORLD_RANK=" << std::string(gpu_rank_id)
486 << ". We will use RANK_ID to get rank id by default.";
487 }
488 }
489 }
490 } _glog_log_dir_register;
491 } // namespace mindspore
492