• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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