diff --git a/src/plugins/intel_cpu/src/config.cpp b/src/plugins/intel_cpu/src/config.cpp index f820a2a97da..348b1cb02f1 100644 --- a/src/plugins/intel_cpu/src/config.cpp +++ b/src/plugins/intel_cpu/src/config.cpp @@ -43,6 +43,7 @@ Config::Config() { if (!with_cpu_x86_bfloat16()) enforceBF16 = false; + CPU_DEBUG_CAP_ENABLE(readDebugCapsProperties()); updateProperties(); } @@ -136,6 +137,7 @@ void Config::readProperties(const std::map &prop) { if (exclusiveAsyncRequests) // Exclusive request feature disables the streams streamExecutorConfig._streams = 1; + CPU_DEBUG_CAP_ENABLE(readDebugCapsProperties()); updateProperties(); } void Config::updateProperties() { @@ -184,4 +186,51 @@ void Config::updateProperties() { } } +#ifdef CPU_DEBUG_CAPS +void Config::readDebugCapsProperties() { + auto readEnv = [](const char* envVar) { + return std::getenv(envVar); + }; + + auto parseDumpFormat = [](const std::string& format) { + if (format == "BIN") + return FORMAT::BIN; + else if (format == "TEXT") + return FORMAT::TEXT; + else + IE_THROW() << "readDebugCapsProperties: Unknown dump format"; + }; + + const char* envVarValue = nullptr; + + if (envVarValue = readEnv("OV_CPU_EXEC_GRAPH_PATH")) + execGraphPath = envVarValue; + + if (envVarValue = readEnv("OV_CPU_VERBOSE")) + verbose = envVarValue; + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_DIR")) + blobDumpDir = envVarValue; + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_FORMAT")) + blobDumpFormat = parseDumpFormat(envVarValue); + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_NODE_EXEC_ID")) + blobDumpFilters[BY_EXEC_ID] = envVarValue; + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_NODE_PORTS")) + blobDumpFilters[BY_PORTS] = envVarValue; + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_NODE_TYPE")) + blobDumpFilters[BY_TYPE] = envVarValue; + + if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_NODE_NAME")) + blobDumpFilters[BY_NAME] = envVarValue; + + // always enable perf counters for verbose mode + if (!verbose.empty()) + collectPerfCounters = true; +} +#endif // CPU_DEBUG_CAPS + } // namespace MKLDNNPlugin diff --git a/src/plugins/intel_cpu/src/config.h b/src/plugins/intel_cpu/src/config.h index 8ee5cfa0cc0..295b385101b 100644 --- a/src/plugins/intel_cpu/src/config.h +++ b/src/plugins/intel_cpu/src/config.h @@ -39,14 +39,34 @@ struct Config { bool manualEnforceBF16 = false; #endif -#ifdef CPU_DEBUG_CAPS - DebugCaps::Config debugCaps; -#endif std::string cache_dir{}; void readProperties(const std::map &config); void updateProperties(); std::map _config; + +#ifdef CPU_DEBUG_CAPS + enum FILTER { + BY_PORTS, + BY_EXEC_ID, + BY_TYPE, + BY_NAME, + }; + + enum class FORMAT { + BIN, + TEXT, + }; + + std::string execGraphPath; + std::string verbose; + std::string blobDumpDir = "mkldnn_dump"; + FORMAT blobDumpFormat = FORMAT::TEXT; + // std::hash is necessary for Ubuntu-16.04 (gcc-5.4 and defect in C++11 standart) + std::unordered_map> blobDumpFilters; + + void readDebugCapsProperties(); +#endif }; } // namespace MKLDNNPlugin diff --git a/src/plugins/intel_cpu/src/mkldnn_graph.cpp b/src/plugins/intel_cpu/src/mkldnn_graph.cpp index 56ebf892143..8ab2de5f356 100644 --- a/src/plugins/intel_cpu/src/mkldnn_graph.cpp +++ b/src/plugins/intel_cpu/src/mkldnn_graph.cpp @@ -311,7 +311,6 @@ void MKLDNNGraph::Replicate(const CNNNetwork &network, const MKLDNNExtensionMana void MKLDNNGraph::InitGraph() { MKLDNNGraphOptimizer optimizer; - CPU_DEBUG_CAP_ENABLE(initNodeDumper(config.debugCaps)); SortTopologically(); InitNodes(); @@ -838,7 +837,7 @@ void MKLDNNGraph::PullOutputData(BlobMap &out) { } inline void MKLDNNGraph::ExecuteNode(const MKLDNNNodePtr& node, const mkldnn::stream& stream) const { - DUMP(node, infer_count); + DUMP(node, config, infer_count); OV_ITT_SCOPED_TASK(itt::domains::MKLDNNPlugin, node->profiling.execute); if (node->isDynamicNode()) { @@ -856,7 +855,7 @@ void MKLDNNGraph::Infer(MKLDNNInferRequest* request, int batch) { mkldnn::stream stream(eng); for (const auto& node : executableGraphNodes) { - VERBOSE(node, config.debugCaps.verbose); + VERBOSE(node, config.verbose); PERF(node, config.collectPerfCounters); if (request) diff --git a/src/plugins/intel_cpu/src/mkldnn_graph_dumper.cpp b/src/plugins/intel_cpu/src/mkldnn_graph_dumper.cpp index 974dea727da..c24c47b9b1f 100644 --- a/src/plugins/intel_cpu/src/mkldnn_graph_dumper.cpp +++ b/src/plugins/intel_cpu/src/mkldnn_graph_dumper.cpp @@ -209,7 +209,7 @@ std::shared_ptr dump_graph_as_ie_ngraph_net(const MKLDNNGraph #ifdef CPU_DEBUG_CAPS void serialize(const MKLDNNGraph &graph) { - const std::string& path = graph.getConfig().debugCaps.execGraphPath; + const std::string& path = graph.getConfig().execGraphPath; if (path.empty()) return; diff --git a/src/plugins/intel_cpu/src/mkldnn_node.h b/src/plugins/intel_cpu/src/mkldnn_node.h index 15c427d273e..b3857c8e8ba 100644 --- a/src/plugins/intel_cpu/src/mkldnn_node.h +++ b/src/plugins/intel_cpu/src/mkldnn_node.h @@ -579,6 +579,10 @@ public: return outputShapes[port]; } + const std::vector& getInternalBlobs() const { + return internalBlobs; + } + /** * @brief Return scales and shift if nodes can be executed as ScaleShift, else raise exception * If node has only scale or shift value, fill missing value with default values @@ -671,7 +675,6 @@ protected: friend class MKLDNNEdge; friend class MKLDNNGraph; friend class MKLDNNGraphOptimizer; - friend class NodeDumper; void selectPreferPrimitiveDescriptor(const std::vector& priority, bool ignoreConstInputs); bool isConfigDefined(const NodeConfig &config) const; diff --git a/src/plugins/intel_cpu/src/utils/blob_dump.cpp b/src/plugins/intel_cpu/src/utils/blob_dump.cpp index b5a00d7ce44..b6e21653e7a 100644 --- a/src/plugins/intel_cpu/src/utils/blob_dump.cpp +++ b/src/plugins/intel_cpu/src/utils/blob_dump.cpp @@ -231,7 +231,7 @@ void BlobDumper::dump(const std::string &dump_path) const { std::ofstream dump_file; dump_file.open(dump_path); if (!dump_file.is_open()) - IE_THROW() << "Dumper cannot create dump file"; + IE_THROW() << "Dumper cannot create dump file " << dump_path; dump(dump_file); dump_file.close(); @@ -241,7 +241,7 @@ void BlobDumper::dumpAsTxt(const std::string& dump_path) const { std::ofstream dump_file; dump_file.open(dump_path); if (!dump_file.is_open()) - IE_THROW() << "Dumper cannot create dump file"; + IE_THROW() << "Dumper cannot create dump file " << dump_path; dumpAsTxt(dump_file); dump_file.close(); diff --git a/src/plugins/intel_cpu/src/utils/debug_capabilities.h b/src/plugins/intel_cpu/src/utils/debug_capabilities.h index fce261b19be..b8598c967df 100644 --- a/src/plugins/intel_cpu/src/utils/debug_capabilities.h +++ b/src/plugins/intel_cpu/src/utils/debug_capabilities.h @@ -5,50 +5,11 @@ #ifdef CPU_DEBUG_CAPS -#include -#include -#include - - #define CPU_DEBUG_CAP_ENABLE(_x) _x; #define CPU_DEBUG_CAPS_ALWAYS_TRUE(x) true -namespace MKLDNNPlugin { -namespace DebugCaps { - -class Config { -public: - Config() { - readParam(blobDumpDir, "OV_CPU_BLOB_DUMP_DIR"); - readParam(blobDumpFormat, "OV_CPU_BLOB_DUMP_FORMAT"); - readParam(blobDumpNodeExecId, "OV_CPU_BLOB_DUMP_NODE_EXEC_ID"); - readParam(blobDumpNodePorts, "OV_CPU_BLOB_DUMP_NODE_PORTS"); - readParam(blobDumpNodeType, "OV_CPU_BLOB_DUMP_NODE_TYPE"); - readParam(blobDumpNodeName, "OV_CPU_BLOB_DUMP_NODE_NAME"); - readParam(execGraphPath, "OV_CPU_EXEC_GRAPH_PATH"); - readParam(verbose, "OV_CPU_VERBOSE"); - } - - std::string blobDumpDir; - std::string blobDumpFormat; - std::string blobDumpNodeExecId; - std::string blobDumpNodePorts; - std::string blobDumpNodeType; - std::string blobDumpNodeName; - std::string execGraphPath; - std::string verbose; - -private: - static void readParam(std::string& param, const char* envVar) { - if (const char* envValue = std::getenv(envVar)) - param = envValue; - } -}; - -} // namespace DebugCaps -} // namespace MKLDNNPlugin - #else // !CPU_DEBUG_CAPS + #define CPU_DEBUG_CAP_ENABLE(_x) #define CPU_DEBUG_CAPS_ALWAYS_TRUE(x) x diff --git a/src/plugins/intel_cpu/src/utils/node_dumper.cpp b/src/plugins/intel_cpu/src/utils/node_dumper.cpp index 02a36f166c9..df293b96d30 100644 --- a/src/plugins/intel_cpu/src/utils/node_dumper.cpp +++ b/src/plugins/intel_cpu/src/utils/node_dumper.cpp @@ -8,10 +8,8 @@ #include "mkldnn_node.h" #include "ie_common.h" #include "utils/blob_dump.h" -#include "utils/debug_capabilities.h" #include "memory_desc/cpu_memory_desc_utils.h" -#include #include #include #include @@ -20,30 +18,105 @@ using namespace InferenceEngine; namespace MKLDNNPlugin { -NodeDumper::NodeDumper(const DebugCaps::Config& config) - : dumpFormat(FORMAT::BIN) - , dumpDirName("mkldnn_dump") { - if (!config.blobDumpDir.empty()) - dumpDirName = config.blobDumpDir; - - if (!config.blobDumpFormat.empty()) - dumpFormat = parseDumpFormat(config.blobDumpFormat); - - if (!config.blobDumpNodeExecId.empty()) - dumpFilters[FILTER::BY_EXEC_ID] = config.blobDumpNodeExecId; - - if (!config.blobDumpNodePorts.empty()) - dumpFilters[FILTER::BY_PORTS] = config.blobDumpNodePorts; - - if (!config.blobDumpNodeType.empty()) - dumpFilters[FILTER::BY_TYPE] = config.blobDumpNodeType; - - if (!config.blobDumpNodeName.empty()) - dumpFilters[FILTER::BY_NAME] = config.blobDumpNodeName; +static void formatNodeName(std::string& name) { + std::replace(name.begin(), name.end(), '\\', '_'); + std::replace(name.begin(), name.end(), '/', '_'); + std::replace(name.begin(), name.end(), ' ', '_'); + std::replace(name.begin(), name.end(), ':', '-'); } -void NodeDumper::dumpInputBlobs(const MKLDNNNodePtr& node, int count) const { - if (!shouldBeDumped(node, "IN")) +static bool shouldBeDumped(const MKLDNNNodePtr& node, const Config& config, const std::string& portsKind) { + const auto& dumpFilters = config.blobDumpFilters; + + if (dumpFilters.empty()) + return false; + + if (dumpFilters.count(Config::FILTER::BY_PORTS)) { // filter by ports configured + if (dumpFilters.at(Config::FILTER::BY_PORTS) != "ALL" && + portsKind != dumpFilters.at(Config::FILTER::BY_PORTS)) + return false; + } + + if (dumpFilters.count(Config::FILTER::BY_EXEC_ID)) { // filter by exec id configured + std::stringstream ss(dumpFilters.at(Config::FILTER::BY_EXEC_ID)); + int id; + bool matched = false; + + while (ss >> id) { + if (node->getExecIndex() == id) {// exec id matches + matched = true; + break; + } + } + + if (!matched) + return false; + } + + if (dumpFilters.count(Config::FILTER::BY_TYPE)) { // filter by type configured + std::stringstream ss(dumpFilters.at(Config::FILTER::BY_TYPE)); + std::string type; + bool matched = false; + + while (ss >> type) { + if (NameFromType(node->getType()) == type) {// type does not match + matched = true; + break; + } + } + + if (!matched) + return false; + } + + if (dumpFilters.count(Config::FILTER::BY_NAME)) { // filter by name configured + if (dumpFilters.at(Config::FILTER::BY_NAME) != "*" && // to have 'single char' option for matching all the names + !std::regex_match(node->getName(), std::regex(dumpFilters.at(Config::FILTER::BY_NAME)))) // name does not match + return false; + } + + return true; +} + +static void dump(const BlobDumper& bd, const std::string& file, const Config& config) { + switch (config.blobDumpFormat) { + case Config::FORMAT::BIN: { + bd.dump(file); + break; + } + case Config::FORMAT::TEXT: { + bd.dumpAsTxt(file); + break; + } + default: + IE_THROW() << "NodeDumper: Unknown dump format"; + } +} + +static void dumpInternalBlobs(const MKLDNNNodePtr& node, const Config& config) { + std::string nodeName = node->getName(); + formatNodeName(nodeName); + + const auto& internalBlobs = node->getInternalBlobs(); + + for (size_t i = 0; i < internalBlobs.size(); i++) { + const auto& blb = internalBlobs[i]; + std::string file_name = NameFromType(node->getType()) + "_" + nodeName + "_blb" + std::to_string(i) + ".ieb"; + auto dump_file = config.blobDumpDir + "/#" + std::to_string(node->getExecIndex()) + "_" + file_name; + + TensorDesc desc = blb->getTensorDesc(); + if (desc.getPrecision() == Precision::BIN) + continue; + + MKLDNNMemoryPtr memory = std::make_shared(node->getEngine()); + memory->Create(MemoryDescUtils::convertToDnnlBlockedMemoryDesc(desc), blb->buffer()); + BlobDumper dumper(memory); + dump(dumper, dump_file, config); + } +} + +void dumpInputBlobs(const MKLDNNNodePtr& node, const Config& config, int count) { + if (!shouldBeDumped(node, config, "IN")) return; auto exec_order = std::to_string(node->getExecIndex()); @@ -62,7 +135,7 @@ void NodeDumper::dumpInputBlobs(const MKLDNNNodePtr& node, int count) const { if (file_name.size() > 240) file_name = file_name.substr(file_name.size() - 240); - auto dump_file = dumpDirName + "/#" + exec_order + "_" + file_name; + auto dump_file = config.blobDumpDir + "/#" + exec_order + "_" + file_name; std::cout << "Dump inputs: " << dump_file << std::endl; auto& desc = prEdge->getMemory().getDesc(); @@ -70,14 +143,14 @@ void NodeDumper::dumpInputBlobs(const MKLDNNNodePtr& node, int count) const { continue; BlobDumper dumper(prEdge->getMemoryPtr()); - dump(dumper, dump_file); + dump(dumper, dump_file, config); } - dumpInternalBlobs(node); + dumpInternalBlobs(node, config); } -void NodeDumper::dumpOutputBlobs(const MKLDNNNodePtr& node, int count) const { - if (!shouldBeDumped(node, "OUT")) +void dumpOutputBlobs(const MKLDNNNodePtr& node, const Config& config, int count) { + if (!shouldBeDumped(node, config, "OUT")) return; auto exec_order = std::to_string(node->getExecIndex()); @@ -95,7 +168,7 @@ void NodeDumper::dumpOutputBlobs(const MKLDNNNodePtr& node, int count) const { if (file_name.size() > 240) file_name = file_name.substr(file_name.size() - 240); - auto dump_file = dumpDirName + "/#" + exec_order + "_" + file_name; + auto dump_file = config.blobDumpDir + "/#" + exec_order + "_" + file_name; std::cout << "Dump outputs: " << dump_file << std::endl; auto& desc = childEdge->getMemory().getDesc(); @@ -103,122 +176,9 @@ void NodeDumper::dumpOutputBlobs(const MKLDNNNodePtr& node, int count) const { continue; BlobDumper dumper(childEdge->getMemoryPtr()); - dump(dumper, dump_file); + dump(dumper, dump_file, config); } } -void NodeDumper::dumpInternalBlobs(const MKLDNNNodePtr& node) const { - std::string nodeName = node->getName(); - formatNodeName(nodeName); - - for (size_t i = 0; i < node->internalBlobs.size(); i++) { - const auto& blb = node->internalBlobs[i]; - std::string file_name = NameFromType(node->getType()) + "_" + nodeName + "_blb" + std::to_string(i) + ".ieb"; - auto dump_file = dumpDirName + "/#" + std::to_string(node->getExecIndex()) + "_" + file_name; - - TensorDesc desc = blb->getTensorDesc(); - if (desc.getPrecision() == Precision::BIN) - continue; - - MKLDNNMemoryPtr memory = std::make_shared(node->getEngine()); - memory->Create(MemoryDescUtils::convertToDnnlBlockedMemoryDesc(desc), blb->buffer()); - BlobDumper dumper(memory); - dump(dumper, dump_file); - } -} - -void NodeDumper::dump(const BlobDumper& bd, const std::string& file) const { - switch (dumpFormat) { - case FORMAT::BIN: { - bd.dump(file); - break; - } - case FORMAT::TEXT: { - bd.dumpAsTxt(file); - break; - } - default: - IE_THROW() << "NodeDumper: Unknown dump format"; - } -} - -bool NodeDumper::shouldBeDumped(const MKLDNNNodePtr& node, const std::string& portsKind) const { - if (dumpFilters.empty()) - return false; - - if (dumpFilters.count(FILTER::BY_PORTS)) { // filter by ports configured - if (dumpFilters.at(FILTER::BY_PORTS) != "ALL" && - portsKind != dumpFilters.at(FILTER::BY_PORTS)) - return false; - } - - if (dumpFilters.count(FILTER::BY_EXEC_ID)) { // filter by exec id configured - std::stringstream ss(dumpFilters.at(FILTER::BY_EXEC_ID)); - int id; - bool matched = false; - - while (ss >> id) { - if (node->getExecIndex() == id) {// exec id matches - matched = true; - break; - } - } - - if (!matched) - return false; - } - - if (dumpFilters.count(FILTER::BY_TYPE)) { // filter by type configured - std::stringstream ss(dumpFilters.at(FILTER::BY_TYPE)); - std::string type; - bool matched = false; - - while (ss >> type) { - if (NameFromType(node->getType()) == type) {// type does not match - matched = true; - break; - } - } - - if (!matched) - return false; - } - - if (dumpFilters.count(FILTER::BY_NAME)) { // filter by name configured - if (dumpFilters.at(FILTER::BY_NAME) != "*" && // to have 'single char' option for matching all the names - !std::regex_match(node->getName(), std::regex(dumpFilters.at(FILTER::BY_NAME)))) // name does not match - return false; - } - - return true; -} - -NodeDumper::FORMAT NodeDumper::parseDumpFormat(const std::string& format) const { - if (format == "BIN") - return FORMAT::BIN; - else if (format == "TEXT") - return FORMAT::TEXT; - else - IE_THROW() << "NodeDumper: Unknown dump format"; -} - -void NodeDumper::formatNodeName(std::string& name) const { - std::replace(name.begin(), name.end(), '\\', '_'); - std::replace(name.begin(), name.end(), '/', '_'); - std::replace(name.begin(), name.end(), ' ', '_'); - std::replace(name.begin(), name.end(), ':', '-'); -} - -std::unique_ptr nd; - -void initNodeDumper(const DebugCaps::Config& config) { - nd.reset(new NodeDumper(config)); -} - -const std::unique_ptr& getNodeDumper() { - assert(nd.get() != nullptr); - return nd; -} - } // namespace MKLDNNPlugin #endif // CPU_DEBUG_CAPS diff --git a/src/plugins/intel_cpu/src/utils/node_dumper.h b/src/plugins/intel_cpu/src/utils/node_dumper.h index 7f349a07cfe..c693fbd917b 100644 --- a/src/plugins/intel_cpu/src/utils/node_dumper.h +++ b/src/plugins/intel_cpu/src/utils/node_dumper.h @@ -5,71 +5,25 @@ #pragma once #include "mkldnn_node.h" -#include "utils/blob_dump.h" -#include "utils/debug_capabilities.h" - -#include -#include +#include "config.h" namespace MKLDNNPlugin { -/** - * Blobs are not dumped by default - * Blobs are dumped if node matches all specified env filters - * - * To dump blobs from all the nodes use the following filter: - * - * OV_CPU_BLOB_DUMP_NODE_NAME=.+ - */ -class NodeDumper { -public: - NodeDumper(const DebugCaps::Config& config); - - void dumpInputBlobs(const MKLDNNNodePtr &node, int count = -1) const; - void dumpOutputBlobs(const MKLDNNNodePtr &node, int count = -1) const; - -private: - void dumpInternalBlobs(const MKLDNNNodePtr& node) const; - void dump(const BlobDumper& bd, const std::string& file) const; - bool shouldBeDumped(const MKLDNNNodePtr &node, const std::string& portsKind) const; - - enum class FORMAT { - BIN, - TEXT, - }; - - FORMAT parseDumpFormat(const std::string& format) const; - void formatNodeName(std::string& name) const; - - FORMAT dumpFormat; - std::string dumpDirName; - int count; - - enum FILTER { - BY_PORTS, - BY_EXEC_ID, - BY_TYPE, - BY_NAME, - }; - - // std::hash is necessary for Ubuntu-16.04 (gcc-5.4 and defect in C++11 standart) - std::unordered_map> dumpFilters; -}; - -void initNodeDumper(const DebugCaps::Config& config); -const std::unique_ptr& getNodeDumper(); +void dumpInputBlobs(const MKLDNNNodePtr &node, const Config& config, int count = -1); +void dumpOutputBlobs(const MKLDNNNodePtr &node, const Config& config, int count = -1); class DumpHelper { const MKLDNNNodePtr& node; const int count; + const Config& config; public: - explicit DumpHelper(const MKLDNNNodePtr& _node, int _count = -1): node(_node), count(_count) { - getNodeDumper()->dumpInputBlobs(node, count); + explicit DumpHelper(const MKLDNNNodePtr& _node, const Config& _config, int _count = -1): node(_node), config(_config), count(_count) { + dumpInputBlobs(node, config, count); } ~DumpHelper() { - getNodeDumper()->dumpOutputBlobs(node, count); + dumpOutputBlobs(node, config, count); } }; diff --git a/src/plugins/intel_cpu/src/utils/verbose.h b/src/plugins/intel_cpu/src/utils/verbose.h index 3fdb8ab4937..042774202bf 100644 --- a/src/plugins/intel_cpu/src/utils/verbose.h +++ b/src/plugins/intel_cpu/src/utils/verbose.h @@ -21,13 +21,15 @@ public: return; printInfo(); } - virtual ~Verbose() { + + ~Verbose() { if (!shouldBePrinted()) return; printDuration(); flush(); } + private: const MKLDNNNodePtr& node; const int lvl; @@ -39,7 +41,8 @@ private: void flush() const; }; -#define VERBOSE(...) Verbose(__VA_ARGS__) +// use heap allocation instead of stack to align with PERF macro (to have proper destruction order) +#define VERBOSE(...) const auto verbose = std::unique_ptr(new Verbose(__VA_ARGS__)); } // namespace MKLDNNPlugin #else #define VERBOSE(...)