• 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 "debug/common.h"
18 
19 #include <memory>
20 #include <iomanip>
21 #include <optional>
22 #include <fstream>
23 #include "utils/system/env.h"
24 #include "utils/system/file_system.h"
25 #include "utils/log_adapter.h"
26 #include "utils/file_utils.h"
27 #include "utils/utils.h"
28 
29 namespace mindspore {
CreatePrefixPath(const std::string & input_path,const bool support_relative_path)30 std::optional<std::string> Common::CreatePrefixPath(const std::string &input_path, const bool support_relative_path) {
31   std::optional<std::string> prefix_path;
32   std::optional<std::string> file_name;
33   FileUtils::SplitDirAndFileName(input_path, &prefix_path, &file_name);
34   if (!file_name.has_value()) {
35     MS_LOG(ERROR) << "Cannot get file_name from: " << input_path;
36     return std::nullopt;
37   }
38   auto file_name_str = file_name.value();
39 #if defined(SYSTEM_ENV_POSIX)
40   if (file_name_str.length() > NAME_MAX) {
41     MS_LOG(ERROR) << "The length of file name: " << file_name_str.length() << " exceeds limit: " << NAME_MAX;
42     return std::nullopt;
43   }
44 #endif
45 
46   std::string prefix_path_str;
47   if (prefix_path.has_value()) {
48     auto create_prefix_path = FileUtils::CreateNotExistDirs(prefix_path.value(), support_relative_path);
49     if (!create_prefix_path.has_value()) {
50       return std::nullopt;
51     }
52     prefix_path_str = create_prefix_path.value();
53   } else {
54     auto pwd_path = FileUtils::GetRealPath("./");
55     if (!pwd_path.has_value()) {
56       MS_LOG(ERROR) << "Cannot get pwd path";
57       return std::nullopt;
58     }
59     prefix_path_str = pwd_path.value();
60   }
61   return std::string(prefix_path_str + "/" + file_name_str);
62 }
63 
CommonFuncForConfigPath(const std::string & default_path,const std::string & env_path,std::string * value)64 bool Common::CommonFuncForConfigPath(const std::string &default_path, const std::string &env_path, std::string *value) {
65   MS_EXCEPTION_IF_NULL(value);
66   value->clear();
67   if (!env_path.empty()) {
68     char real_path[PATH_MAX] = {0};
69 #if defined(SYSTEM_ENV_WINDOWS)
70     if (_fullpath(real_path, common::SafeCStr(env_path), PATH_MAX) == nullptr) {
71       MS_LOG(ERROR) << "The dir " << env_path << " does not exist.";
72       return false;
73     }
74     *value = real_path;
75     return true;
76 #else
77 
78     if (realpath(env_path.c_str(), real_path)) {
79       *value = real_path;
80       return true;
81     }
82     MS_LOG(ERROR) << "Invalid env path, path : " << env_path;
83     return false;
84 #endif
85   }
86   *value = default_path;
87   return true;
88 }
89 
GetConfigFile(const std::string & env)90 std::optional<std::string> Common::GetConfigFile(const std::string &env) {
91   if (env.empty()) {
92     MS_LOG(EXCEPTION) << "Invalid env";
93   }
94   auto config_path_str = common::GetEnv(env);
95   if (config_path_str.empty()) {
96     MS_LOG(ERROR) << "Please export env:" << env;
97     return std::nullopt;
98   }
99   MS_LOG(INFO) << "Async Dump Getenv env:" << env << "=" << config_path_str;
100 
101   auto real_path = FileUtils::GetRealPath(common::SafeCStr(config_path_str));
102   if (!real_path.has_value()) {
103     MS_LOG(ERROR) << "Can't get real_path";
104     return std::nullopt;
105   }
106   std::string dump_config_file = real_path.value();
107   std::shared_ptr<system::FileSystem> fs = system::Env::GetFileSystem();
108   MS_EXCEPTION_IF_NULL(fs);
109   if (!fs->FileExist(dump_config_file)) {
110     MS_LOG(ERROR) << dump_config_file << " not exist.";
111     return std::nullopt;
112   }
113   auto point_pos = dump_config_file.find_last_of('.');
114   if (point_pos == std::string::npos) {
115     MS_LOG(EXCEPTION) << "Invalid json file name:" << dump_config_file;
116   }
117   auto suffix = dump_config_file.substr(point_pos + 1);
118   if (suffix != "json") {
119     MS_LOG(EXCEPTION) << "[DataDump] dump config file suffix only supports json! But got:." << suffix;
120   }
121   return dump_config_file;
122 }
123 
IsStrLengthValid(const std::string & str,size_t length_limit,const std::string & error_message)124 bool Common::IsStrLengthValid(const std::string &str, size_t length_limit, const std::string &error_message) {
125   auto len_str = str.length();
126   if (len_str > length_limit) {
127     MS_LOG(ERROR) << error_message << "The length is " << str.length() << ", exceeding the limit of " << length_limit
128                   << ".";
129     return false;
130   }
131   return true;
132 }
133 
IsEveryFilenameValid(const std::string & path,size_t length_limit,const std::string & error_message)134 bool Common::IsEveryFilenameValid(const std::string &path, size_t length_limit, const std::string &error_message) {
135   if (path.empty()) {
136     MS_LOG(WARNING) << error_message << "The path is empty.";
137     return false;
138   }
139   size_t len_path = path.length();
140   size_t left_pos = 0;
141   for (size_t i = 0; i < len_path; i++) {
142     if (i != 0) {
143       if (path[i] == '\\' || path[i] == '/') {
144         auto cur_len = i - left_pos;
145         if (cur_len > length_limit) {
146           MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is "
147                           << cur_len << ". It is out of the limit which is " << length_limit << ".";
148           return false;
149         }
150         left_pos = i + 1;
151       }
152     }
153   }
154   if (!(path[len_path - 1] == '\\' || path[len_path - 1] == '/')) {
155     auto cur_len = len_path - left_pos;
156     if (cur_len > length_limit) {
157       MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is " << cur_len
158                       << ". It is out of the limit which is " << length_limit << ".";
159       return false;
160     }
161   }
162   return true;
163 }
164 
IsPathValid(const std::string & path,size_t length_limit,const std::string & error_message)165 bool Common::IsPathValid(const std::string &path, size_t length_limit, const std::string &error_message) {
166   std::string err_msg = "Detail: ";
167   if (!error_message.empty()) {
168     err_msg = error_message + " " + err_msg;
169   }
170 
171   if (path.empty()) {
172     MS_LOG(WARNING) << err_msg << "The path is empty.";
173     return false;
174   }
175 
176   if (!IsStrLengthValid(path, length_limit, err_msg)) {
177     return false;
178   }
179 
180   if (!std::all_of(path.begin(), path.end(), [](char c) {
181         return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '.' || c == '/';
182       })) {
183     MS_LOG(ERROR) << err_msg << "The path only supports alphabets, digit or {'-', '_', '.', '/'}, but got:" << path
184                   << ".";
185     return false;
186   }
187 
188   if (path[0] != '/') {
189     MS_LOG(ERROR) << err_msg << "The path only supports absolute path and should start with '/'.";
190     return false;
191   }
192 
193   if (!IsEveryFilenameValid(path, MAX_OS_FILENAME_LENGTH, err_msg)) {
194     return false;
195   }
196   return true;
197 }
198 
IsFilenameValid(const std::string & filename,size_t length_limit,const std::string & error_message)199 bool Common::IsFilenameValid(const std::string &filename, size_t length_limit, const std::string &error_message) {
200   std::string err_msg = "Detail: ";
201   if (!error_message.empty()) {
202     err_msg = error_message + " " + err_msg;
203   }
204 
205   if (filename.empty()) {
206     MS_LOG(WARNING) << err_msg << "The filename is empty.";
207     return false;
208   }
209 
210   if (!IsStrLengthValid(filename, length_limit, err_msg)) {
211     return false;
212   }
213   auto func = [](char c) { return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '.'; };
214   if (!std::all_of(filename.begin(), filename.end(), func)) {
215     MS_LOG(ERROR) << err_msg << "The filename only supports alphabets, digit or {'-', '_', '.'}, but got:" << filename
216                   << ".";
217     return false;
218   }
219   return true;
220 }
221 
AddId(const std::string & filename,const std::string & suffix)222 std::string Common::AddId(const std::string &filename, const std::string &suffix) {
223   static size_t g_id = 0;
224   std::ostringstream s;
225   auto i = filename.rfind(suffix);
226   const int spaces = 4;
227   if (i >= filename.size()) {
228     s << filename;
229     s << "_" << std::setfill('0') << std::setw(spaces) << g_id;
230   } else {
231     s << filename.substr(0, i);
232     s << "_" << std::setfill('0') << std::setw(spaces) << g_id;
233     if (i + 1 < filename.size()) {
234       s << filename.substr(i);
235     }
236   }
237   g_id++;
238   return s.str();
239 }
240 
SaveStringToFile(const std::string filename,const std::string string_info)241 bool Common::SaveStringToFile(const std::string filename, const std::string string_info) {
242   if (filename.size() >= PATH_MAX) {
243     MS_LOG(ERROR) << "File path " << filename << " is too long.";
244     return false;
245   }
246   auto real_path = CreatePrefixPath(filename);
247   if (!real_path.has_value()) {
248     MS_LOG(ERROR) << "Get real path failed. path=" << filename;
249     return false;
250   }
251 
252   ChangeFileMode(real_path.value(), S_IRWXU);
253   std::ofstream ofs;
254   ofs.open(real_path.value());
255 
256   if (!ofs.is_open()) {
257     MS_LOG(ERROR) << "Open dump file '" << real_path.value() << "' failed!" << ErrnoToString(errno);
258     return false;
259   }
260   ofs << string_info << std::endl;
261   ofs.close();
262   // set file mode to read only by user
263   ChangeFileMode(real_path.value(), S_IRUSR);
264   return true;
265 }
266 
FileExists(const std::string & filepath)267 bool Common::FileExists(const std::string &filepath) {
268   std::ifstream f(filepath);
269   bool cache_file_existed = f.good();
270   f.close();
271   return cache_file_existed;
272 }
273 
274 struct GlogLogDirRegister {
GlogLogDirRegistermindspore::GlogLogDirRegister275   GlogLogDirRegister() {
276     const std::string logtostderr = common::GetEnv("GLOG_logtostderr");
277     const std::string log_dir = common::GetEnv("GLOG_log_dir");
278     if (!logtostderr.empty() && !log_dir.empty()) {
279       std::string logtostderr_str = std::string(logtostderr);
280       std::string log_dir_str = std::string(log_dir);
281       if (logtostderr_str != "0") {
282         return;
283       }
284       const std::string rank_id = common::GetEnv("RANK_ID");
285       const std::string gpu_rank_id = common::GetEnv("OMPI_COMM_WORLD_RANK");
286       std::string rank = "0";
287       bool both_exist = false;
288       if (!rank_id.empty() && gpu_rank_id.empty()) {
289         rank = std::string(rank_id);
290       } else if (rank_id.empty() && !gpu_rank_id.empty()) {
291         rank = std::string(gpu_rank_id);
292       } else if (!rank_id.empty() && !gpu_rank_id.empty()) {
293         rank = std::string(rank_id);
294         both_exist = true;
295       }
296       log_dir_str += "/rank_" + rank + "/logs/";
297       auto real_log_dir_str = Common::CreatePrefixPath(log_dir_str, true);
298       // While 'GLOG_logtostderr' = 0, logs output to files. 'GLOG_log_dir' must be specified as the path of log files.
299       // Here can not throw exception and use python to catch, because the PYBIND11_MODULE is not yet been initialed.
300       if (!real_log_dir_str.has_value()) {
301         MS_LOG(ERROR) << "The path of log files, which set by 'GLOG_log_dir', is invalid.";
302         exit(EXIT_FAILURE);
303       }
304       if (both_exist) {
305         MS_LOG(WARNING) << "Environment variables RANK_ID and OMPI_COMM_WORLD_RANK both exist, we will use RANK_ID to "
306                            "get rank id by default.";
307       }
308     }
309   }
310 } _glog_log_dir_register;
311 }  // namespace mindspore
312