1. add validation for directory and filename 2. refactor the file operations about path 3. add in CMakeLists 4. add logger in nn_opstags/v1.2.0-rc1
| @@ -381,9 +381,9 @@ bool Somas::InitSomasTensors(const session::KernelGraph *graph) { | |||
| #ifdef ENABLE_DUMP_IR | |||
| SubModuleId module = SubModuleId::SM_OPTIMIZER; | |||
| std::string tag = "somas"; | |||
| std::string filename = "somas_pre_processed_info_" + std::to_string(graph->graph_id()) + ".ir"; | |||
| std::string filename = "somas_pre_processed_info_" + std::to_string(graph->graph_id()); | |||
| mindspore::RDR::RecordString(module, tag, SomasInfo(), filename); | |||
| filename = "somas_offline_log_" + std::to_string(graph->graph_id()) + ".ir"; | |||
| filename = "somas_offline_log_" + std::to_string(graph->graph_id()); | |||
| mindspore::RDR::RecordString(module, tag, Offline(), filename); | |||
| #endif | |||
| @@ -673,7 +673,7 @@ void Somas::InitBasicInfo(const session::KernelGraph *graph) { | |||
| #ifdef ENABLE_DUMP_IR | |||
| SubModuleId module = SubModuleId::SM_OPTIMIZER; | |||
| std::string tag = "somas"; | |||
| std::string filename = "somas_initial_info_" + std::to_string(graph->graph_id()) + ".ir"; | |||
| std::string filename = "somas_initial_info_" + std::to_string(graph->graph_id()); | |||
| mindspore::RDR::RecordString(module, tag, SomasInfo(), filename); | |||
| #endif | |||
| @@ -10,6 +10,7 @@ set(_DEBUG_SRC_LIST | |||
| if(ENABLE_DUMP_IR) | |||
| list(APPEND _DEBUG_SRC_LIST | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/rdr/base_recorder.cc" | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/rdr/graph_exec_order_recorder.cc" | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/rdr/graph_recorder.cc" | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/rdr/string_recorder.cc" | |||
| @@ -170,4 +170,105 @@ std::optional<std::string> Common::GetEnvConfigFile() { | |||
| } | |||
| return config_file; | |||
| } | |||
| bool Common::IsStrLengthValid(const std::string &str, const int &length_limit, const std::string &error_message, | |||
| const bool &print_str) { | |||
| const int len_str = str.length(); | |||
| if (len_str > length_limit) { | |||
| std::ostringstream msg; | |||
| if (print_str) { | |||
| msg << error_message << "The string is " << str << ", its length is " << str.length(); | |||
| } else { | |||
| msg << error_message << "The length is " << str.length(); | |||
| } | |||
| msg << ", exceeding the limit of " << length_limit << "."; | |||
| MS_LOG(WARNING) << msg.str(); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool Common::IsEveryFilenameValid(const std::string &path, const int &length_limit, const std::string &error_message) { | |||
| int left_pos = 0; | |||
| int len_path = path.length(); | |||
| for (int i = 0; i < len_path; i++) { | |||
| if (i != 0) { | |||
| if (path[i] == '\\' || path[i] == '/') { | |||
| int cur_len = i - left_pos; | |||
| if (cur_len > length_limit) { | |||
| MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is " | |||
| << cur_len << ". It is out of the limit which is " << length_limit << "."; | |||
| return false; | |||
| } | |||
| left_pos = i + 1; | |||
| } | |||
| } | |||
| } | |||
| if (!(path[len_path - 1] == '\\' || path[len_path - 1] == '/')) { | |||
| int cur_len = len_path - left_pos; | |||
| if (cur_len > length_limit) { | |||
| MS_LOG(WARNING) << error_message << "The name length of '" << path.substr(left_pos, cur_len) << "' is " << cur_len | |||
| << ". It is out of the limit which is " << length_limit << "."; | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| bool Common::IsPathValid(const std::string &path, const int &length_limit, const std::string &error_message, | |||
| const bool &print_str) { | |||
| std::string err_msg = "Detail: "; | |||
| if (!error_message.empty()) { | |||
| err_msg = error_message + " " + err_msg; | |||
| } | |||
| if (path.empty()) { | |||
| MS_LOG(WARNING) << err_msg << "The path is empty."; | |||
| return false; | |||
| } | |||
| if (!IsStrLengthValid(path, length_limit, err_msg, print_str)) { | |||
| return false; | |||
| } | |||
| if (!std::all_of(path.begin(), path.end(), | |||
| [](char c) { return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '/'; })) { | |||
| MS_LOG(WARNING) << err_msg << "The path only support alphabets, digit or {'-', '_', '/'}, but got:" << path << "."; | |||
| return false; | |||
| } | |||
| if (path[0] != '/') { | |||
| MS_LOG(WARNING) << err_msg << "The path only support absolute path and should start with '/'."; | |||
| return false; | |||
| } | |||
| if (!IsEveryFilenameValid(path, maxOSFilenameLength, err_msg)) { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool Common::IsFilenameValid(const std::string &filename, const int &length_limit, const std::string &error_message) { | |||
| std::string err_msg = "Detail: "; | |||
| if (!error_message.empty()) { | |||
| err_msg = error_message + " " + err_msg; | |||
| } | |||
| if (filename.empty()) { | |||
| MS_LOG(WARNING) << err_msg << "The filename is empty."; | |||
| return false; | |||
| } | |||
| if (!IsStrLengthValid(filename, length_limit, err_msg)) { | |||
| return false; | |||
| } | |||
| if (!std::all_of(filename.begin(), filename.end(), | |||
| [](char c) { return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '.'; })) { | |||
| MS_LOG(WARNING) << err_msg << "The filename only support alphabets, digit or {'-', '_', '.'}, but got:" << filename | |||
| << "."; | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| } // namespace mindspore | |||
| @@ -22,6 +22,9 @@ | |||
| #include "utils/contract.h" | |||
| namespace mindspore { | |||
| static const int maxDirectoryLength = 1024; | |||
| static const int maxFilenameLength = 128; | |||
| static const int maxOSFilenameLength = 255; | |||
| class Common { | |||
| public: | |||
| Common() = default; | |||
| @@ -29,9 +32,16 @@ class Common { | |||
| static std::optional<std::string> GetRealPath(const std::string &input_path); | |||
| static std::optional<std::string> GetConfigFile(const std::string &env); | |||
| static std::optional<std::string> GetEnvConfigFile(); | |||
| static bool IsStrLengthValid(const std::string &str, const int &length_limit, const std::string &error_message = "", | |||
| const bool &print_str = true); | |||
| static bool IsPathValid(const std::string &path, const int &length_limit, const std::string &error_message = "", | |||
| const bool &print_str = true); | |||
| static bool IsFilenameValid(const std::string &filename, const int &length_limit, | |||
| const std::string &error_message = ""); | |||
| private: | |||
| static bool CreateNotExistDirs(const std::string &path); | |||
| static bool IsEveryFilenameValid(const std::string &path, const int &length_limit, const std::string &error_message); | |||
| }; | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_CCSRC_DEBUG_COMMON_H_ | |||
| @@ -116,28 +116,20 @@ void EnvConfigParser::ParseRdrSetting(const nlohmann::json &content) { | |||
| } | |||
| void EnvConfigParser::ParseRdrPath(const nlohmann::json &content) { | |||
| std::string err_msg = "RDR path parse failed. The RDR path will be a default value: '" + rdr_path_ + | |||
| "'. Please check the settings about '" + kRdrSettings + "' in config file '" + config_file_ + | |||
| "' set by 'env_config_path' in context."; | |||
| if (!CheckJsonStringType(content, kRdrSettings, kPath)) { | |||
| MS_LOG(WARNING) << "The RDR path will be a default value: '" << rdr_path_ << "'."; | |||
| MS_LOG(WARNING) << err_msg; | |||
| return; | |||
| } | |||
| std::string path = content; | |||
| if (!std::all_of(path.begin(), path.end(), | |||
| [](char c) { return ::isalpha(c) || ::isdigit(c) || c == '-' || c == '_' || c == '/'; })) { | |||
| MS_LOG(WARNING) << "The path in " << kRdrSettings | |||
| << " only support alphabets, digit or {'-', '_', '/'}, but got:" << path << "." | |||
| << " Please check the config file '" << config_file_ << "' set by 'env_config_path' in context."; | |||
| return; | |||
| } | |||
| if (path.empty()) { | |||
| MS_LOG(WARNING) << "The path in " << kRdrSettings << " is empty." | |||
| << " Please check the config file '" << config_file_ << "' set by 'env_config_path' in context."; | |||
| return; | |||
| } | |||
| if (path[0] != '/') { | |||
| MS_LOG(WARNING) << "The path in " << kRdrSettings << " only support absolute path and should start with '/'." | |||
| << " Please check the config file '" << config_file_ << "' set by 'env_config_path' in context."; | |||
| if (!Common::IsPathValid(path, maxDirectoryLength, err_msg, false)) { | |||
| return; | |||
| } | |||
| if (path.back() != '/') { | |||
| path += '/'; | |||
| } | |||
| @@ -146,7 +138,7 @@ void EnvConfigParser::ParseRdrPath(const nlohmann::json &content) { | |||
| void EnvConfigParser::ParseRdrEnable(const nlohmann::json &content) { | |||
| if (!content.is_boolean()) { | |||
| MS_LOG(WARNING) << "Json Parse Failed. 'enable' in " << kRdrSettings << " should be boolean." | |||
| MS_LOG(WARNING) << "Json parse failed. 'enable' in " << kRdrSettings << " should be boolean." | |||
| << " Please check the config file '" << config_file_ << "' set by 'env_config_path' in context."; | |||
| rdr_enabled_ = false; | |||
| return; | |||
| @@ -0,0 +1,54 @@ | |||
| /** | |||
| * Copyright 2021 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "debug/rdr/base_recorder.h" | |||
| #include <sys/stat.h> | |||
| #include <fstream> | |||
| #include "debug/common.h" | |||
| #include "utils/utils.h" | |||
| namespace mindspore { | |||
| void BaseRecorder::SetDirectory(const std::string &directory) { | |||
| std::string error_message = module_ + ":" + tag_ + " set directory failed."; | |||
| if (Common::IsPathValid(directory, maxDirectoryLength, error_message)) { | |||
| directory_ = directory; | |||
| if (directory_.back() != '/') { | |||
| directory_ += "/"; | |||
| } | |||
| } | |||
| } | |||
| void BaseRecorder::SetFilename(const std::string &filename) { | |||
| std::string error_message = module_ + ":" + tag_ + " set filename failed."; | |||
| if (Common::IsFilenameValid(filename, maxDirectoryLength, error_message)) { | |||
| filename_ = filename; | |||
| } | |||
| } | |||
| std::optional<std::string> BaseRecorder::GetFileRealPath() { | |||
| if (filename_.empty()) { | |||
| filename_ = module_ + "_" + tag_ + "_" + timestamp_; | |||
| } | |||
| std::string file_path = directory_ + filename_; | |||
| auto realpath = Common::GetRealPath(file_path); | |||
| if (!realpath.has_value()) { | |||
| MS_LOG(ERROR) << "Get real path failed. " | |||
| << "Info: module=" << module_ << ", tag=" << tag_ << ", " | |||
| << "path=" << file_path << "."; | |||
| } | |||
| return realpath; | |||
| } | |||
| } // namespace mindspore | |||
| @@ -21,7 +21,11 @@ | |||
| #include <sstream> | |||
| #include <chrono> | |||
| #include <iomanip> | |||
| #include "debug/common.h" | |||
| #include "debug/env_config_parser.h" | |||
| #include "mindspore/core/utils/log_adapter.h" | |||
| const int maxTagLength = 32; | |||
| namespace mindspore { | |||
| class BaseRecorder { | |||
| public: | |||
| @@ -31,6 +35,17 @@ class BaseRecorder { | |||
| config_parser_ptr.Parse(); | |||
| directory_ = config_parser_ptr.rdr_path(); | |||
| if (tag.length() > maxTagLength) { | |||
| tag_ = tag.substr(0, maxTagLength); | |||
| MS_LOG(WARNING) << "The tag length is " << tag.length() << ", exceeding the limit " << maxTagLength | |||
| << ". It will be intercepted as '" << tag_ << "'."; | |||
| } | |||
| std::string err_msg = module_ + ":" + tag_ + " set filename failed."; | |||
| if (!filename_.empty() && !Common::IsFilenameValid(filename_, maxFilenameLength, err_msg)) { | |||
| filename_ = ""; | |||
| } | |||
| auto sys_time = std::chrono::system_clock::now(); | |||
| auto t_time = std::chrono::system_clock::to_time_t(sys_time); | |||
| std::tm *l_time = std::localtime(&t_time); | |||
| @@ -47,9 +62,10 @@ class BaseRecorder { | |||
| std::string GetModule() const { return module_; } | |||
| std::string GetTag() const { return tag_; } | |||
| std::string GetTimeStamp() const { return timestamp_; } | |||
| std::optional<std::string> GetFileRealPath(); | |||
| void SetDirectory(const std::string &directory) { directory_ = directory; } | |||
| std::string GetDirectory() const { return directory_; } | |||
| void SetDirectory(const std::string &directory); | |||
| void SetFilename(const std::string &filename); | |||
| virtual void Export() {} | |||
| protected: | |||
| @@ -46,10 +46,11 @@ bool DumpGraphExeOrder(const std::string &filename, const std::vector<CNodePtr> | |||
| } // namespace | |||
| void GraphExecOrderRecorder::Export() { | |||
| if (filename_.empty()) { | |||
| filename_ = module_ + "_" + tag_ + "_" + timestamp_; | |||
| auto realpath = GetFileRealPath(); | |||
| if (!realpath.has_value()) { | |||
| return; | |||
| } | |||
| std::string filename = directory_ + filename_ + ".txt"; | |||
| DumpGraphExeOrder(filename, exec_order_); | |||
| std::string real_file_path = realpath.value() + ".txt"; | |||
| DumpGraphExeOrder(real_file_path, exec_order_); | |||
| } | |||
| } // namespace mindspore | |||
| @@ -25,33 +25,22 @@ | |||
| namespace mindspore { | |||
| namespace protobuf { | |||
| #ifdef ENABLE_DUMP_IR | |||
| void DumpIRProto(const std::string &filename, const FuncGraphPtr &func_graph) { | |||
| void DumpIRProto(const std::string &real_path, const FuncGraphPtr &func_graph) { | |||
| if (func_graph == nullptr) { | |||
| MS_LOG(ERROR) << "Func graph is nullptr"; | |||
| MS_LOG(ERROR) << "Func graph is nullptr."; | |||
| return; | |||
| } | |||
| if (filename.size() > PATH_MAX) { | |||
| MS_LOG(ERROR) << "File path " << filename << " is too long."; | |||
| return; | |||
| } | |||
| auto real_path = Common::GetRealPath(filename); | |||
| if (!real_path.has_value()) { | |||
| MS_LOG(ERROR) << "Get real path failed. path=" << filename; | |||
| return; | |||
| } | |||
| ChangeFileMode(real_path.value(), S_IRWXU); | |||
| // write to pb file | |||
| std::ofstream ofs(real_path.value()); | |||
| std::ofstream ofs(real_path); | |||
| if (!ofs.is_open()) { | |||
| MS_LOG(ERROR) << "Open file '" << real_path.value() << "' failed!"; | |||
| MS_LOG(ERROR) << "Open file '" << real_path << "' failed!"; | |||
| return; | |||
| } | |||
| ofs << GetFuncGraphProtoString(func_graph); | |||
| ofs.close(); | |||
| // set file mode to read only by user | |||
| ChangeFileMode(real_path.value(), S_IRUSR); | |||
| ChangeFileMode(real_path, S_IRUSR); | |||
| } | |||
| #else | |||
| void DumpIRProto(const std::string &, const FuncGraphPtr &) { | |||
| @@ -68,31 +57,35 @@ void DumpIRProto(const std::string &, const FuncGraphPtr &) { | |||
| void GraphRecorder::Export() { | |||
| bool save_flag = false; | |||
| if (filename_.empty()) { | |||
| filename_ = module_ + "_" + tag_ + "_" + timestamp_; | |||
| auto tmp_realpath = GetFileRealPath(); | |||
| if (!tmp_realpath.has_value()) { | |||
| return; | |||
| } | |||
| std::string file_path = directory_ + filename_ + std::to_string(id_); | |||
| std::string realpath = tmp_realpath.value() + std::to_string(id_); | |||
| if (graph_type_.find(".dat") != std::string::npos) { | |||
| save_flag = true; | |||
| AnfExporter exporter(""); | |||
| std::string real_path = file_path + ".dat"; | |||
| ChangeFileMode(real_path, S_IRWXU); | |||
| exporter.ExportFuncGraph(real_path, func_graph_); | |||
| ChangeFileMode(real_path, S_IRUSR); | |||
| AnfExporter exporter(std::to_string(id_)); | |||
| std::string realpath_dat = realpath + ".dat"; | |||
| ChangeFileMode(realpath_dat, S_IRWXU); | |||
| exporter.ExportFuncGraph(realpath_dat, func_graph_); | |||
| ChangeFileMode(realpath_dat, S_IRUSR); | |||
| } | |||
| if (graph_type_.find(".ir") != std::string::npos) { | |||
| save_flag = true; | |||
| std::string real_path = file_path + ".ir"; | |||
| std::string realpath_ir = realpath + ".ir"; | |||
| if (full_name_) { | |||
| DumpIRForRDR(real_path, func_graph_, true, kTopStack); | |||
| DumpIRForRDR(realpath_ir, func_graph_, true, kTopStack); | |||
| } else { | |||
| DumpIRForRDR(real_path, func_graph_, false, kOff); | |||
| DumpIRForRDR(realpath_ir, func_graph_, false, kOff); | |||
| } | |||
| } | |||
| if (graph_type_.find(".pb") != std::string::npos) { | |||
| save_flag = true; | |||
| std::string real_path = file_path + ".pb"; | |||
| protobuf::DumpIRProto(real_path, func_graph_); // save *.pb file | |||
| protobuf::DumpIRProto(realpath + ".pb", func_graph_); // save *.pb file | |||
| } | |||
| if (!save_flag) { | |||
| MS_LOG(WARNING) << "Unknown save graph type: " << graph_type_; | |||
| @@ -22,23 +22,13 @@ | |||
| namespace mindspore { | |||
| void StringRecorder::Export() { | |||
| if (directory_.back() != '/') { | |||
| directory_ += "/"; | |||
| } | |||
| if (filename_.empty()) { | |||
| filename_ = module_ + "_" + tag_ + "_" + timestamp_ + ".txt"; | |||
| } | |||
| std::string file_path = directory_ + filename_; | |||
| auto realpath = Common::GetRealPath(file_path); | |||
| auto realpath = GetFileRealPath(); | |||
| if (!realpath.has_value()) { | |||
| MS_LOG(ERROR) << "Get real path failed. path=" << file_path; | |||
| return; | |||
| } | |||
| ChangeFileMode(realpath.value(), S_IRWXU); | |||
| std::ofstream fout(realpath.value(), std::ofstream::app); | |||
| std::string file_path = realpath.value() + ".txt"; | |||
| ChangeFileMode(file_path, S_IRWXU); | |||
| std::ofstream fout(file_path, std::ofstream::app); | |||
| if (!fout.is_open()) { | |||
| MS_LOG(WARNING) << "Open file for saving string failed."; | |||
| return; | |||
| @@ -46,6 +36,6 @@ void StringRecorder::Export() { | |||
| fout << data_; | |||
| fout.close(); | |||
| // set file mode to read only by user | |||
| ChangeFileMode(realpath.value(), S_IRUSR); | |||
| ChangeFileMode(file_path, S_IRUSR); | |||
| } | |||
| } // namespace mindspore | |||
| @@ -25,15 +25,15 @@ class StringRecorder : public BaseRecorder { | |||
| public: | |||
| StringRecorder() : BaseRecorder() {} | |||
| StringRecorder(const std::string &module, const std::string &tag, const std::string &data, | |||
| const std::string &file_type) | |||
| : BaseRecorder(module, tag), data_(data) {} | |||
| const std::string &filename) | |||
| : BaseRecorder(module, tag), data_(data), filename_(filename) {} | |||
| ~StringRecorder() {} | |||
| void SetModule(const std::string &module) { module_ = module; } | |||
| void SetFilename(const std::string &filename) { filename_ = filename; } | |||
| virtual void Export(); | |||
| private: | |||
| std::string data_; | |||
| std::string filename_; | |||
| }; | |||
| using StringRecorderPtr = std::shared_ptr<StringRecorder>; | |||
| } // namespace mindspore | |||
| @@ -76,10 +76,10 @@ void MemoryManager::MallocSomasDynamicMem(const session::KernelGraph *graph) { | |||
| SubModuleId module = SubModuleId::SM_OPTIMIZER; | |||
| std::string tag = "somas"; | |||
| std::string filename = "somas_allocate_info_" + std::to_string(graph->graph_id()) + ".ir"; | |||
| std::string filename = "somas_allocate_info_" + std::to_string(graph->graph_id()); | |||
| mindspore::RDR::RecordString(module, tag, somas_reuse_util_ptr_->SomasInfo(), filename); | |||
| filename = "somas_mem_info_" + std::to_string(graph->graph_id()) + ".ir"; | |||
| filename = "somas_mem_info_" + std::to_string(graph->graph_id()); | |||
| mindspore::RDR::RecordString(module, tag, somas_reuse_util_ptr_->SomasMemory(), filename); | |||
| #endif | |||
| bool save_graphs = context_ptr->get_param<bool>(MS_CTX_SAVE_GRAPHS_FLAG); | |||
| @@ -18,6 +18,7 @@ | |||
| import math | |||
| import operator | |||
| from functools import reduce, partial | |||
| from mindspore import log as logger | |||
| from mindspore._checkparam import _check_3d_int_or_tuple | |||
| import numpy as np | |||
| from ... import context | |||