diff --git a/mindspore/ccsrc/backend/kernel_compiler/cpu/reduce_cpu_kernel.h b/mindspore/ccsrc/backend/kernel_compiler/cpu/reduce_cpu_kernel.h index 24d29531039..c72cc5b93fc 100644 --- a/mindspore/ccsrc/backend/kernel_compiler/cpu/reduce_cpu_kernel.h +++ b/mindspore/ccsrc/backend/kernel_compiler/cpu/reduce_cpu_kernel.h @@ -37,7 +37,7 @@ class ReduceCPUKernel : public CPUKernel { enum ReduceType { kReduceAll, kReduceAny, kReduceMax, kReduceMin, kReduceSum, kReduceMean }; std::vector input_shape_; std::vector axis_; - ReduceType reduce_type_; + ReduceType reduce_type_{kReduceAll}; std::function reduce_func_; }; diff --git a/mindspore/ccsrc/debug/CMakeLists.txt b/mindspore/ccsrc/debug/CMakeLists.txt index 5a69bc701f9..86e4c31d2ed 100644 --- a/mindspore/ccsrc/debug/CMakeLists.txt +++ b/mindspore/ccsrc/debug/CMakeLists.txt @@ -12,6 +12,7 @@ set(_DEBUG_SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/data_dump/dump_json_parser.cc" "${CMAKE_CURRENT_SOURCE_DIR}/data_dump/cpu_e2e_dump.cc" "${CMAKE_CURRENT_SOURCE_DIR}/data_dump/dump_utils.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/data_dump/npy_header.cc" ) set(_OFFLINE_SRC_LIST diff --git a/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.cc b/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.cc index a4522223c07..cbdd272c3fd 100644 --- a/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.cc +++ b/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.cc @@ -19,7 +19,7 @@ #include "backend/session/anf_runtime_algorithm.h" namespace mindspore { -void CPUE2eDump::DumpCNodeData(const CNodePtr &node) { +void CPUE2eDump::DumpCNodeData(const CNodePtr &node, uint32_t graph_id) { MS_EXCEPTION_IF_NULL(node); auto &dump_json_parser = DumpJsonParser::GetInstance(); std::string kernel_name = node->fullname_with_scope(); @@ -29,7 +29,7 @@ void CPUE2eDump::DumpCNodeData(const CNodePtr &node) { MS_LOG(DEBUG) << "E2e dump CNode data start: " << kernel_name << ", current iteration is " << dump_json_parser.cur_dump_iter(); - std::string dump_path = GenerateDumpPath(); + std::string dump_path = GenerateDumpPath(graph_id); if (dump_json_parser.InputNeedDump()) { DumpCNodeInputs(node, dump_path); } @@ -129,12 +129,12 @@ void CPUE2eDump::DumpSingleAnfNode(const AnfNodePtr &anf_node, const size_t outp DumpMemToFile(file_path, NOT_NULL(addr), int_shapes, type); } -void CPUE2eDump::DumpParametersAndConst(const session::KernelGraph *graph) { +void CPUE2eDump::DumpParametersAndConst(const session::KernelGraph *graph, uint32_t graph_id) { MS_EXCEPTION_IF_NULL(graph); MS_LOG(INFO) << "Start e2e dump parameters and Const values"; std::map const_map; GetConstantId(graph, &const_map); - const std::string &dump_path = GenerateDumpPath(); + const std::string &dump_path = GenerateDumpPath(graph_id); // dump parameters const auto ¶meters = graph->inputs(); diff --git a/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.h b/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.h index 3ef6425f269..f1b2c0f3b95 100644 --- a/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.h +++ b/mindspore/ccsrc/debug/data_dump/cpu_e2e_dump.h @@ -29,9 +29,9 @@ class CPUE2eDump { CPUE2eDump() = default; ~CPUE2eDump() = default; // Dump data when task error. - static void DumpParametersAndConst(const session::KernelGraph *graph); + static void DumpParametersAndConst(const session::KernelGraph *graph, uint32_t graph_id); - static void DumpCNodeData(const CNodePtr &node); + static void DumpCNodeData(const CNodePtr &node, uint32_t graph_id); private: static void DumpCNodeInputs(const CNodePtr &node, const std::string &dump_path); diff --git a/mindspore/ccsrc/debug/data_dump/dump_json_parser.cc b/mindspore/ccsrc/debug/data_dump/dump_json_parser.cc index cbcb269fabe..96ca4e354ca 100644 --- a/mindspore/ccsrc/debug/data_dump/dump_json_parser.cc +++ b/mindspore/ccsrc/debug/data_dump/dump_json_parser.cc @@ -20,12 +20,14 @@ #include "utils/ms_context.h" #include "utils/convert_utils_base.h" #include "backend/session/anf_runtime_algorithm.h" +#include "debug/data_dump/npy_header.h" namespace { constexpr auto kCommonDumpSettings = "common_dump_settings"; constexpr auto kAsyncDumpSettings = "async_dump_settings"; constexpr auto kE2eDumpSettings = "e2e_dump_settings"; constexpr auto kDumpMode = "dump_mode"; +constexpr auto kDumpFormat = "dump_format"; constexpr auto kPath = "path"; constexpr auto kNetName = "net_name"; constexpr auto kIteration = "iteration"; @@ -42,6 +44,8 @@ constexpr auto kMindsporeDumpConfig = "MINDSPORE_DUMP_CONFIG"; } // namespace namespace mindspore { +uint32_t DumpJsonParser::dump_format_ = 0; + auto DumpJsonParser::CheckJsonKeyExist(const nlohmann::json &content, const std::string &key) { auto iter = content.find(key); if (iter == content.end()) { @@ -137,13 +141,15 @@ bool DumpJsonParser::GetIterDumpFlag() { return e2e_dump_enabled_ && (iteration_ == 0 || cur_dump_iter_ == iteration_); } -bool DumpJsonParser::DumpToFile(const std::string &filename, const void *data, size_t len) { +bool DumpJsonParser::DumpToFile(const std::string &filename, const void *data, size_t len, const ShapeVector &shape, + TypeId type) { if (filename.empty() || data == nullptr || len == 0) { MS_LOG(ERROR) << "Incorrect parameter."; return false; } - auto realpath = Common::GetRealPath(filename); + std::string file_format = dump_format_ == 1 ? ".npy" : ".bin"; + auto realpath = Common::GetRealPath(filename + file_format); if (!realpath.has_value()) { MS_LOG(ERROR) << "Get real path failed."; return false; @@ -154,6 +160,10 @@ bool DumpJsonParser::DumpToFile(const std::string &filename, const void *data, s MS_LOG(ERROR) << "Open file " << realpath.value() << " fail."; return false; } + if (dump_format_ == 1) { + std::string npy_header = GenerateNpyHeader(shape, type); + fd << npy_header; + } (void)fd.write(reinterpret_cast(data), SizeToLong(len)); fd.close(); return true; @@ -176,6 +186,7 @@ void DumpJsonParser::ParseCommonDumpSetting(const nlohmann::json &content) { ParseInputOutput(*input_output); ParseKernels(*kernels); ParseSupportDevice(*support_device); + ParseDumpFormat(*common_dump_settings); } void DumpJsonParser::ParseAsyncDumpSetting(const nlohmann::json &content) { @@ -209,19 +220,19 @@ void DumpJsonParser::ParseE2eDumpSetting(const nlohmann::json &content) { void CheckJsonUnsignedType(const nlohmann::json &content, const std::string &key) { if (!content.is_number_unsigned()) { - MS_LOG(EXCEPTION) << "Dump Json Parse Failed." << key << " should be unsigned int type"; + MS_LOG(EXCEPTION) << "Dump config parse failed, " << key << " should be unsigned int type"; } } void CheckJsonStringType(const nlohmann::json &content, const std::string &key) { if (!content.is_string()) { - MS_LOG(EXCEPTION) << "Dump Json Parse Failed." << key << " should be string type"; + MS_LOG(EXCEPTION) << "Dump config parse failed, " << key << " should be string type"; } } void CheckJsonArrayType(const nlohmann::json &content, const std::string &key) { if (!content.is_array()) { - MS_LOG(EXCEPTION) << "Dump Json Parse Failed." << key << " should be array type"; + MS_LOG(EXCEPTION) << "Dump config parse failed, " << key << " should be array type"; } } @@ -229,7 +240,18 @@ void DumpJsonParser::ParseDumpMode(const nlohmann::json &content) { CheckJsonUnsignedType(content, kDumpMode); dump_mode_ = content; if (dump_mode_ != 0 && dump_mode_ != 1) { - MS_LOG(EXCEPTION) << "Dump Json Parse Failed. dump_mode should be 0 or 1"; + MS_LOG(EXCEPTION) << "Dump config parse failed, dump_mode should be 0 or 1, but got " << dump_format_; + } +} + +void DumpJsonParser::ParseDumpFormat(const nlohmann::json &content) { + auto iter = content.find(kDumpFormat); + if (iter == content.end()) { + return; + } + dump_format_ = *iter; + if (dump_format_ != 0 && dump_format_ != 1) { + MS_LOG(EXCEPTION) << "Dump config parse failed, dump_format should be 0(.bin) or 1(.npy), but got " << dump_format_; } } diff --git a/mindspore/ccsrc/debug/data_dump/dump_json_parser.h b/mindspore/ccsrc/debug/data_dump/dump_json_parser.h index 7ce9b4a1c2b..001c7ea2d34 100644 --- a/mindspore/ccsrc/debug/data_dump/dump_json_parser.h +++ b/mindspore/ccsrc/debug/data_dump/dump_json_parser.h @@ -33,7 +33,8 @@ class DumpJsonParser { } void Parse(); - static bool DumpToFile(const std::string &filename, const void *data, size_t len); + static bool DumpToFile(const std::string &filename, const void *data, size_t len, const ShapeVector &shape, + TypeId type); void CopyJsonToDir(); bool NeedDump(const std::string &op_full_name) const; void MatchKernel(const std::string &kernel_name); @@ -62,6 +63,7 @@ class DumpJsonParser { DISABLE_COPY_AND_ASSIGN(DumpJsonParser) std::mutex lock_; + static uint32_t dump_format_; bool async_dump_enabled_{false}; bool e2e_dump_enabled_{false}; uint32_t dump_mode_{0}; @@ -84,6 +86,7 @@ class DumpJsonParser { auto CheckJsonKeyExist(const nlohmann::json &content, const std::string &key); void ParseDumpMode(const nlohmann::json &content); + void ParseDumpFormat(const nlohmann::json &content); void ParseDumpPath(const nlohmann::json &content); void ParseNetName(const nlohmann::json &content); void ParseIteration(const nlohmann::json &content); diff --git a/mindspore/ccsrc/debug/data_dump/dump_utils.cc b/mindspore/ccsrc/debug/data_dump/dump_utils.cc index c3dfabcbbf8..9bf4b848d64 100644 --- a/mindspore/ccsrc/debug/data_dump/dump_utils.cc +++ b/mindspore/ccsrc/debug/data_dump/dump_utils.cc @@ -34,7 +34,7 @@ uint32_t ConvertPhysicalDeviceId(uint32_t device_id) { return kernel_runtime->device_id(); } -std::string GenerateDumpPath(const uint32_t *device_id) { +std::string GenerateDumpPath(uint32_t graph_id, const uint32_t *device_id) { auto &dump_json_parser = DumpJsonParser::GetInstance(); std::string net_name = dump_json_parser.net_name(); std::string iterator = std::to_string(dump_json_parser.cur_dump_iter()); @@ -42,12 +42,9 @@ std::string GenerateDumpPath(const uint32_t *device_id) { if (dump_path.back() != '/') { dump_path += "/"; } - if (device_id == nullptr) { - dump_path += (net_name + "/iteration_" + iterator); - } else { - auto physical_device = ConvertPhysicalDeviceId(*device_id); - dump_path += (net_name + "/device_" + std::to_string(physical_device) + "/iteration_" + iterator); - } + uint32_t physical_device = device_id == nullptr ? 0 : ConvertPhysicalDeviceId(*device_id); + dump_path += ("rank_" + std::to_string(physical_device) + "/" + net_name + "/graph_" + std::to_string(graph_id) + + "/iteration_" + iterator); return dump_path; } diff --git a/mindspore/ccsrc/debug/data_dump/dump_utils.h b/mindspore/ccsrc/debug/data_dump/dump_utils.h index 47f04cb16b9..5daf41b9504 100644 --- a/mindspore/ccsrc/debug/data_dump/dump_utils.h +++ b/mindspore/ccsrc/debug/data_dump/dump_utils.h @@ -27,7 +27,7 @@ namespace mindspore { static const size_t PARAMETER_OUTPUT_INDEX = 0; static const size_t VALUE_NODE_OUTPUT_INDEX = 0; -std::string GenerateDumpPath(const uint32_t *device_id = nullptr); +std::string GenerateDumpPath(uint32_t graph_id, const uint32_t *device_id = nullptr); void GetFileKernelName(NotNull kernel_name); diff --git a/mindspore/ccsrc/debug/data_dump/e2e_dump.cc b/mindspore/ccsrc/debug/data_dump/e2e_dump.cc index 5b12d8ad1a3..b305a997418 100644 --- a/mindspore/ccsrc/debug/data_dump/e2e_dump.cc +++ b/mindspore/ccsrc/debug/data_dump/e2e_dump.cc @@ -223,18 +223,19 @@ void E2eDump::DumpParametersAndConst(const session::KernelGraph *graph, const st bool E2eDump::DumpData(const session::KernelGraph *graph, uint32_t device_id, const Debugger *debugger) { MS_EXCEPTION_IF_NULL(graph); auto &dump_json_parser = DumpJsonParser::GetInstance(); + uint32_t graph_id = graph->graph_id(); if (starting_graph_id == INT32_MAX) { - starting_graph_id = graph->graph_id(); + starting_graph_id = graph_id; } - if (starting_graph_id == graph->graph_id()) { + if (starting_graph_id == graph_id) { dump_json_parser.UpdateDumpIter(); } if (!dump_json_parser.GetIterDumpFlag()) { return true; } MS_LOG(INFO) << "Start e2e dump. Current iteration is " << dump_json_parser.cur_dump_iter(); - MS_LOG(INFO) << "Current graph id is " << graph->graph_id(); - std::string dump_path = GenerateDumpPath(&device_id); + MS_LOG(INFO) << "Current graph id is " << graph_id; + std::string dump_path = GenerateDumpPath(graph_id, &device_id); DumpInput(graph, dump_path, debugger); DumpOutput(graph, dump_path, debugger); diff --git a/mindspore/ccsrc/debug/data_dump/npy_header.cc b/mindspore/ccsrc/debug/data_dump/npy_header.cc new file mode 100644 index 00000000000..1746703e635 --- /dev/null +++ b/mindspore/ccsrc/debug/data_dump/npy_header.cc @@ -0,0 +1,145 @@ +/** + * 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/data_dump/npy_header.h" + +#include +#include +#include +#include + +#include "mindspore/core/utils/log_adapter.h" +#include "mindspore/core/ir/dtype.h" + +namespace mindspore { +namespace { +// npy file header start information +const char kMagicPrefix[] = "\x93NUMPY"; +// magical length include kMagicPrefix length and version length +const size_t kMagicLen = 8; +const size_t kArrayAlign = 64; + +// first: header_length_type, second: encoding_type +// header_length_type: 1 represents 2 bytes; 2 and 3 represents 4 bytes +// encoding_type: 1 and 2 represents 'latin1'; 3 represents 'utf8' +using version_type = std::pair; + +// data type description +// byteorder char: '<' is little endian; '>' is big endian; '|' is ignore(no change to byte order) +// type char: 'b' represents bool; 'u' represents uint; 'i' represents int; 'f' represents float +struct DtypeDescr { + char byteorder; + char type; + size_t length; + + std::string str() const; +}; + +// npy file header description, includes data type description, fortran_order and array shape +// fortran_order: true represents the array data Fortran-contiguous; false represents the array data C-contiguity +struct NpyHeader { + public: + DtypeDescr dtype_descr; + bool fortran_order; + ShapeVector shape; + + std::string str() const; + + private: + std::string fortran_order_to_str() const; + std::string shape_to_str() const; +}; + +std::string DtypeDescr::str() const { + std::ostringstream buffer; + buffer << "\'" << byteorder << type << length << "\'"; + return buffer.str(); +} + +std::string NpyHeader::str() const { + const std::string first_field = "'descr': "; + const std::string second_field = "'fortran_order': "; + const std::string third_field = "'shape': "; + std::ostringstream buffer; + buffer << "{" << first_field << dtype_descr.str() << ", " << second_field << fortran_order_to_str() << ", " + << third_field << shape_to_str() << ", }"; + return buffer.str(); +} + +std::string NpyHeader::fortran_order_to_str() const { return fortran_order ? "True" : "False"; } + +std::string NpyHeader::shape_to_str() const { + std::ostringstream buffer; + buffer << "("; + for (const auto i : shape) { + buffer << std::to_string(i) << ","; + } + buffer << ")"; + return buffer.str(); +} +} // namespace + +void int_to_byte(size_t number, char *byte, size_t length) { + for (size_t i = 0; i < length; i++) { + byte[i] = (number >> (i * 8)) & 0xff; + } +} + +std::string GenerateNpyHeader(const ShapeVector &shape, TypeId type_id, bool fortran_order) { + static std::unordered_map type_desc_map = { + {kNumberTypeBool, DtypeDescr{'|', 'b', 1}}, {kNumberTypeInt8, DtypeDescr{'|', 'i', 1}}, + {kNumberTypeInt16, DtypeDescr{'<', 'i', 2}}, {kNumberTypeInt32, DtypeDescr{'<', 'i', 4}}, + {kNumberTypeInt64, DtypeDescr{'<', 'i', 8}}, {kNumberTypeUInt8, DtypeDescr{'|', 'u', 1}}, + {kNumberTypeUInt16, DtypeDescr{'<', 'u', 2}}, {kNumberTypeUInt32, DtypeDescr{'<', 'u', 4}}, + {kNumberTypeUInt64, DtypeDescr{'<', 'u', 8}}, {kNumberTypeFloat16, DtypeDescr{'<', 'f', 2}}, + {kNumberTypeFloat32, DtypeDescr{'<', 'f', 4}}, {kNumberTypeFloat64, DtypeDescr{'<', 'f', 8}}, + }; + auto type_desc = type_desc_map.find(type_id); + if (type_desc == type_desc_map.end()) { + MS_LOG(EXCEPTION) << "Not support dump the " << TypeIdToType(type_id)->ToString() << " data to npy file."; + } + + NpyHeader npy_header{type_desc->second, fortran_order, shape}; + std::string header_str = npy_header.str(); + size_t header_len = header_str.length(); + version_type version{1, 0}; + size_t total_len = kMagicLen + 2 + header_len + 1; + if (total_len > std::pow(2, 16)) { + version = {2, 0}; + total_len = kMagicLen + 4 + header_len + 1; + } + std::ostringstream out; + out << kMagicPrefix; + out.put(version.first); + out.put(version.second); + + size_t pad_len = kArrayAlign - total_len % kArrayAlign; + size_t padding_header_len = header_len + pad_len + 1; + if (version == version_type{1, 0}) { + char length_byte[2]; + int_to_byte(padding_header_len, length_byte, 2); + out.write(length_byte, 2); + } else { + char length_byte[4]; + int_to_byte(padding_header_len, length_byte, 4); + out.write(length_byte, 4); + } + + std::string padding(pad_len, ' '); + out << header_str << padding << "\n"; + return out.str(); +} +} // namespace mindspore diff --git a/mindspore/ccsrc/debug/data_dump/npy_header.h b/mindspore/ccsrc/debug/data_dump/npy_header.h new file mode 100644 index 00000000000..f780d5f4c03 --- /dev/null +++ b/mindspore/ccsrc/debug/data_dump/npy_header.h @@ -0,0 +1,28 @@ +/** + * 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. + */ + +#ifndef MINDSPORE_MINDSPORE_CCSRC_DEBUG_DATA_DUMP_NPY_HEADER_H_ +#define MINDSPORE_MINDSPORE_CCSRC_DEBUG_DATA_DUMP_NPY_HEADER_H_ + +#include + +#include "mindspore/core/utils/shape_utils.h" +#include "mindspore/core/ir/dtype/type_id.h" + +namespace mindspore { +std::string GenerateNpyHeader(const ShapeVector &shape, TypeId type_id, bool fortran_order = false); +} // namespace mindspore +#endif // MINDSPORE_MINDSPORE_CCSRC_DEBUG_DATA_DUMP_NPY_HEADER_H_ diff --git a/mindspore/ccsrc/debug/tensor_load.h b/mindspore/ccsrc/debug/tensor_load.h index e7e831b0910..fe90b4d065d 100644 --- a/mindspore/ccsrc/debug/tensor_load.h +++ b/mindspore/ccsrc/debug/tensor_load.h @@ -172,12 +172,11 @@ class TensorLoader { } else { shape = shape + "_0"; } - std::string file_extension = ".bin"; std::string path = ""; if (trans_flag) { - path = filepath + '_' + shape + '_' + TypeIdToType(host_type)->ToString() + '_' + host_fmt + file_extension; + path = filepath + '_' + shape + '_' + TypeIdToType(host_type)->ToString() + '_' + host_fmt; } else { - path = filepath + '_' + shape + '_' + TypeIdToType(device_type)->ToString() + '_' + addr_format + file_extension; + path = filepath + '_' + shape + '_' + TypeIdToType(device_type)->ToString() + '_' + addr_format; } MS_LOG(INFO) << "Dump path is " << path; @@ -188,7 +187,7 @@ class TensorLoader { std::shared_ptr node = iter->second; size_t host_size = node->GetByteSize(); - return DumpJsonParser::DumpToFile(path, node->GetDataPtr(), host_size); + return DumpJsonParser::DumpToFile(path, node->GetDataPtr(), host_size, host_shape, host_type); } MS_LOG(INFO) << "Tensor name:" << tensor_name << " not found in tensor_list_map"; return true; diff --git a/mindspore/ccsrc/runtime/device/ascend/ascend_device_address.cc b/mindspore/ccsrc/runtime/device/ascend/ascend_device_address.cc index eac7ca90da5..cd5957a6ac3 100644 --- a/mindspore/ccsrc/runtime/device/ascend/ascend_device_address.cc +++ b/mindspore/ccsrc/runtime/device/ascend/ascend_device_address.cc @@ -664,10 +664,8 @@ bool AscendDeviceAddress::DumpMemToFile(const std::string &filepath, const std:: } else { shape = shape + "_0"; } - std::string file_extension = ".bin"; if (trans_flag) { - std::string path = - filepath + '_' + shape + '_' + TypeIdToType(host_type)->ToString() + '_' + host_fmt + file_extension; + std::string path = filepath + '_' + shape + '_' + TypeIdToType(host_type)->ToString() + '_' + host_fmt; MS_LOG(INFO) << "E2E Dump path is " << path; mindspore::tensor::TensorPtr out_tensor = std::make_shared(host_type, host_shape); size_t host_size = out_tensor->data().nbytes(); @@ -676,17 +674,16 @@ bool AscendDeviceAddress::DumpMemToFile(const std::string &filepath, const std:: MS_LOG(ERROR) << "Copy device mem to host failed"; return ret; } - ret = DumpJsonParser::DumpToFile(path, out_tensor->data_c(), host_size); + ret = DumpJsonParser::DumpToFile(path, out_tensor->data_c(), host_size, host_shape, host_type); } else { auto host_tmp = std::vector(size_); auto ret_rt_memcpy = rtMemcpy(host_tmp.data(), size_, ptr_, size_, RT_MEMCPY_DEVICE_TO_HOST); if (ret_rt_memcpy != RT_ERROR_NONE) { MS_LOG(ERROR) << "SyncDeviceToHost: rtMemcpy mem size[" << size_ << "] fail, ret[" << ret_rt_memcpy << "]"; } - std::string path = - filepath + '_' + shape + '_' + TypeIdToType(type_id_)->ToString() + '_' + format_ + file_extension; + std::string path = filepath + '_' + shape + '_' + TypeIdToType(type_id_)->ToString() + '_' + format_; MS_LOG(INFO) << "E2E Dump path is " << path; - ret = DumpJsonParser::DumpToFile(path, host_tmp.data(), size_); + ret = DumpJsonParser::DumpToFile(path, host_tmp.data(), size_, host_shape_, type_id_); } return ret; diff --git a/mindspore/ccsrc/runtime/device/cpu/cpu_device_address.cc b/mindspore/ccsrc/runtime/device/cpu/cpu_device_address.cc index 88e016072c4..92bd75f4db4 100644 --- a/mindspore/ccsrc/runtime/device/cpu/cpu_device_address.cc +++ b/mindspore/ccsrc/runtime/device/cpu/cpu_device_address.cc @@ -37,10 +37,9 @@ bool CPUDeviceAddress::DumpMemToFile(const std::string &filepath, const std::str shape += '_' + std::to_string(value); } } - std::string file_extension = ".bin"; - std::string path = filepath + '_' + shape + '_' + TypeIdToType(type_id_)->ToString() + '_' + format_ + file_extension; + std::string path = filepath + '_' + shape + '_' + TypeIdToType(type_id_)->ToString() + '_' + format_; MS_LOG(DEBUG) << "E2E Dump path is " << path; - ret = DumpJsonParser::DumpToFile(path, ptr_, size_); + ret = DumpJsonParser::DumpToFile(path, ptr_, size_, host_shape, host_type); return ret; } diff --git a/mindspore/ccsrc/runtime/device/cpu/cpu_kernel_runtime.cc b/mindspore/ccsrc/runtime/device/cpu/cpu_kernel_runtime.cc index 2c670ef90c3..b5d8d470dc2 100644 --- a/mindspore/ccsrc/runtime/device/cpu/cpu_kernel_runtime.cc +++ b/mindspore/ccsrc/runtime/device/cpu/cpu_kernel_runtime.cc @@ -380,6 +380,7 @@ bool CPUKernelRuntime::Run(session::KernelGraph *kernel_graph, bool is_task_sink auto &dump_json_parser = DumpJsonParser::GetInstance(); dump_json_parser.UpdateDumpIter(); bool iter_dump_flag = dump_json_parser.GetIterDumpFlag(); + uint32_t graph_id = kernel_graph->graph_id(); for (const auto &kernel : kernels) { #ifdef ENABLE_PROFILE @@ -421,7 +422,7 @@ bool CPUKernelRuntime::Run(session::KernelGraph *kernel_graph, bool is_task_sink MS_LOG(EXCEPTION) << e.what() << "\nTrace:" << trace::DumpSourceLines(kernel); } if (iter_dump_flag) { - CPUE2eDump::DumpCNodeData(kernel); + CPUE2eDump::DumpCNodeData(kernel, graph_id); } if (profiler_inst->GetEnableFlag()) { profiler_inst->OpDataProducerEnd(); @@ -439,7 +440,7 @@ bool CPUKernelRuntime::Run(session::KernelGraph *kernel_graph, bool is_task_sink #endif } if (iter_dump_flag) { - CPUE2eDump::DumpParametersAndConst(kernel_graph); + CPUE2eDump::DumpParametersAndConst(kernel_graph, graph_id); } return true; } diff --git a/tests/st/dump/e2e_dump.json b/tests/st/dump/e2e_dump_bin.json similarity index 100% rename from tests/st/dump/e2e_dump.json rename to tests/st/dump/e2e_dump_bin.json diff --git a/tests/st/dump/e2e_dump_npy.json b/tests/st/dump/e2e_dump_npy.json new file mode 100644 index 00000000000..709f29bbe49 --- /dev/null +++ b/tests/st/dump/e2e_dump_npy.json @@ -0,0 +1,16 @@ +{ + "common_dump_settings": { + "dump_mode": 0, + "path": "/test", + "net_name": "Net", + "iteration": 0, + "input_output": 0, + "kernels": ["Default/Conv-op12"], + "support_device": [0,1,2,3,4,5,6,7], + "dump_format": 1 + }, + "e2e_dump_settings": { + "enable": true, + "trans_flag": false + } +} \ No newline at end of file diff --git a/tests/st/dump/test_data_dump.py b/tests/st/dump/test_data_dump.py index bea56efe7cc..03f27c389ec 100644 --- a/tests/st/dump/test_data_dump.py +++ b/tests/st/dump/test_data_dump.py @@ -14,8 +14,10 @@ # ============================================================================ import os import json +import sys import time import shutil + import numpy as np import pytest import mindspore.context as context @@ -29,7 +31,6 @@ from mindspore.nn import Momentum from mindspore.nn import TrainOneStepCell from mindspore.nn import WithLossCell -context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") class Net(nn.Cell): def __init__(self): @@ -39,8 +40,10 @@ class Net(nn.Cell): def construct(self, x_, y_): return self.add(x_, y_) -x = np.random.randn(1, 3, 3, 4).astype(np.float32) -y = np.random.randn(1, 3, 3, 4).astype(np.float32) + +x = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) +y = np.array([[7, 8, 9], [10, 11, 12]]).astype(np.float32) + def change_current_dump_json(file_name, dump_path): with open(file_name, 'r+') as f: @@ -50,6 +53,7 @@ def change_current_dump_json(file_name, dump_path): with open(file_name, 'w') as f: json.dump(data, f) + @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_ascend_training @@ -61,7 +65,7 @@ def test_async_dump(): change_current_dump_json('async_dump.json', dump_path) os.environ['MINDSPORE_DUMP_CONFIG'] = pwd + "/async_dump.json" device_id = context.get_context("device_id") - dump_file_path = pwd + '/async_dump/device_{}/Net_graph_0/0/0/'.format(device_id) + dump_file_path = dump_path + '/device_{}/Net_graph_0/0/0/'.format(device_id) if os.path.isdir(dump_path): shutil.rmtree(dump_path) add = Net() @@ -69,24 +73,90 @@ def test_async_dump(): time.sleep(5) assert len(os.listdir(dump_file_path)) == 1 -@pytest.mark.level0 -@pytest.mark.platform_arm_ascend_training -@pytest.mark.platform_x86_ascend_training -@pytest.mark.env_onecard -def test_e2e_dump(): - context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") + +def run_e2e_dump_bin(): + if sys.platform != 'linux': + return pwd = os.getcwd() - dump_path = pwd + "/e2e_dump" - change_current_dump_json('e2e_dump.json', dump_path) - os.environ['MINDSPORE_DUMP_CONFIG'] = pwd + "/e2e_dump.json" + dump_path = pwd + '/e2e_dump' + change_current_dump_json('e2e_dump_bin.json', dump_path) + os.environ['MINDSPORE_DUMP_CONFIG'] = pwd + '/e2e_dump_bin.json' device_id = context.get_context("device_id") - dump_file_path = pwd + '/e2e_dump/Net/device_{}/iteration_1/'.format(device_id) + dump_file_path = dump_path + '/rank_{}/Net/graph_0/iteration_1/'.format(device_id) if os.path.isdir(dump_path): shutil.rmtree(dump_path) add = Net() add(Tensor(x), Tensor(y)) - time.sleep(5) - assert len(os.listdir(dump_file_path)) == 5 + if context.get_context("device_target") == "Ascend": + output_name = "Default--Add-op1_output_0_shape_2_3_Float32_DefaultFormat.bin" + else: + output_name = "Default--Add-op3_output_0_shape_2_3_Float32_DefaultFormat.bin" + output_path = dump_file_path + output_name + real_path = os.path.realpath(output_path) + output = np.fromfile(real_path, dtype=np.float32) + expect = np.array([8, 10, 12, 14, 16, 18], np.float32) + assert output.dtype == expect.dtype + assert np.array_equal(output, expect) + + +def run_e2e_dump_npy(): + if sys.platform != 'linux': + return + pwd = os.getcwd() + dump_path = pwd + '/e2e_dump' + change_current_dump_json('e2e_dump_npy.json', dump_path) + os.environ['MINDSPORE_DUMP_CONFIG'] = pwd + '/e2e_dump_npy.json' + device_id = context.get_context("device_id") + dump_file_path = dump_path + '/rank_{}/Net/graph_0/iteration_1/'.format(device_id) + if os.path.isdir(dump_path): + shutil.rmtree(dump_path) + add = Net() + add(Tensor(x), Tensor(y)) + if context.get_context("device_target") == "Ascend": + output_name = "Default--Add-op1_output_0_shape_2_3_Float32_DefaultFormat.npy" + else: + output_name = "Default--Add-op3_output_0_shape_2_3_Float32_DefaultFormat.npy" + output_path = dump_file_path + output_name + real_path = os.path.realpath(output_path) + output = np.load(real_path) + expect = np.array([[8, 10, 12], [14, 16, 18]], np.float32) + assert output.dtype == expect.dtype + assert np.array_equal(output, expect) + + +@pytest.mark.level0 +@pytest.mark.platform_arm_ascend_training +@pytest.mark.platform_x86_ascend_training +@pytest.mark.env_onecard +def test_e2e_dump_bin(): + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") + run_e2e_dump_bin() + + +@pytest.mark.level0 +@pytest.mark.platform_arm_ascend_training +@pytest.mark.platform_x86_ascend_training +@pytest.mark.env_onecard +def test_e2e_dump_npy(): + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") + run_e2e_dump_npy() + + +@pytest.mark.level0 +@pytest.mark.platform_x86_cpu +@pytest.mark.env_onecard +def test_cpu_e2e_dump_bin(): + context.set_context(mode=context.GRAPH_MODE, device_target="CPU") + run_e2e_dump_bin() + + +@pytest.mark.level0 +@pytest.mark.platform_x86_cpu +@pytest.mark.env_onecard +def test_cpu_e2e_dump_npy(): + context.set_context(mode=context.GRAPH_MODE, save_graphs=True, device_target="CPU") + run_e2e_dump_npy() + class ReluReduceMeanDenseRelu(Cell): def __init__(self, kernel, bias, in_channel, num_class): @@ -116,11 +186,13 @@ def search_path(path, keyword): search_path(each_path, keyword) return None + @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_ascend_training @pytest.mark.env_onecard def test_async_dump_net_multi_layer_mode1(): + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") test_name = "test_async_dump_net_multi_layer_mode1" json_file = os.path.join(os.getcwd(), "{}.json".format(test_name)) device_id = context.get_context("device_id") @@ -131,7 +203,8 @@ def test_async_dump_net_multi_layer_mode1(): bias = Tensor(np.ones((1000,)).astype(np.float32)) net = ReluReduceMeanDenseRelu(weight, bias, 2048, 1000) criterion = SoftmaxCrossEntropyWithLogits(sparse=False) - optimizer = Momentum(learning_rate=0.1, momentum=0.1, params=filter(lambda x: x.requires_grad, net.get_parameters())) + optimizer = Momentum(learning_rate=0.1, momentum=0.1, + params=filter(lambda x: x.requires_grad, net.get_parameters())) net_with_criterion = WithLossCell(net, criterion) train_network = TrainOneStepCell(net_with_criterion, optimizer) train_network.set_train() diff --git a/tests/ut/cpp/debug/memory_dumper_test.cc b/tests/ut/cpp/debug/memory_dumper_test.cc index 8753305f05d..8d24c6b7775 100644 --- a/tests/ut/cpp/debug/memory_dumper_test.cc +++ b/tests/ut/cpp/debug/memory_dumper_test.cc @@ -37,11 +37,11 @@ TEST_F(TestMemoryDumper, test_DumpToFileAbsPath) { } int ret; - char filename[] = "/tmp/dumpToFileTestFile"; - ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int)); + const std::string filename = "/tmp/dumpToFileTestFile"; + ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int), ShapeVector {10, 100}, kNumberTypeInt32); ASSERT_EQ(ret, true); - int fd = open(filename, O_RDONLY); + int fd = open((filename + ".bin").c_str(), O_RDONLY); int readBack[1000] = {0}; int readSize = read(fd, readBack, len * sizeof(int)); (void)close(fd); @@ -69,11 +69,11 @@ TEST_F(TestMemoryDumper, test_DumpToFileRelativePath) { } int ret; - char filename[] = "../../dumpToFileTestFile"; - ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int)); + const std::string filename = "../../dumpToFileTestFile"; + ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int), ShapeVector{100, 10}, kNumberTypeInt32); ASSERT_EQ(ret, true); - int fd = open(filename, O_RDONLY); + int fd = open((filename + ".bin").c_str(), O_RDONLY); int readBack[1000] = {0}; int readSize = read(fd, readBack, len * sizeof(int)); (void)close(fd); @@ -101,11 +101,11 @@ TEST_F(TestMemoryDumper, test_DumpToFileNotExistDir) { data[i] = i % 10; } - char filename[] = "./tmp/dumpToFileTestFile"; - int ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int)); + const std::string filename = "./tmp/dumpToFileTestFile"; + int ret = DumpJsonParser::DumpToFile(filename, data, len * sizeof(int), ShapeVector {1,}, kNumberTypeInt32); ASSERT_EQ(ret, true); - int fd = open(filename, O_RDONLY); + int fd = open((filename + ".bin").c_str(), O_RDONLY); int readBack[1000] = {0}; int readSize = read(fd, readBack, len * sizeof(int)); (void)close(fd);