[CPU] [DEBUG CAPS] Implicitly enable perf counters for verbose mode (#8754)

Also refactor debug capabilities configuration.
Now debug caps config parameters are the part of plugin configuration.
This commit is contained in:
Egor Duplensky 2022-01-18 12:32:53 +03:00 committed by GitHub
parent 71b7c7000a
commit 3a9dba7362
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 198 additions and 249 deletions

View File

@ -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<std::string, std::string> &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

View File

@ -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<std::string, std::string> &config);
void updateProperties();
std::map<std::string, std::string> _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<int> is necessary for Ubuntu-16.04 (gcc-5.4 and defect in C++11 standart)
std::unordered_map<FILTER, std::string, std::hash<int>> blobDumpFilters;
void readDebugCapsProperties();
#endif
};
} // namespace MKLDNNPlugin

View File

@ -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)

View File

@ -209,7 +209,7 @@ std::shared_ptr<ngraph::Function> 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;

View File

@ -579,6 +579,10 @@ public:
return outputShapes[port];
}
const std::vector<InferenceEngine::Blob::Ptr>& 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<impl_desc_type>& priority, bool ignoreConstInputs);
bool isConfigDefined(const NodeConfig &config) const;

View File

@ -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();

View File

@ -5,50 +5,11 @@
#ifdef CPU_DEBUG_CAPS
#include <map>
#include <string>
#include <vector>
#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

View File

@ -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 <array>
#include <regex>
#include <sstream>
#include <string>
@ -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<MKLDNNMemory>(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<MKLDNNMemory>(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<NodeDumper> nd;
void initNodeDumper(const DebugCaps::Config& config) {
nd.reset(new NodeDumper(config));
}
const std::unique_ptr<NodeDumper>& getNodeDumper() {
assert(nd.get() != nullptr);
return nd;
}
} // namespace MKLDNNPlugin
#endif // CPU_DEBUG_CAPS

View File

@ -5,71 +5,25 @@
#pragma once
#include "mkldnn_node.h"
#include "utils/blob_dump.h"
#include "utils/debug_capabilities.h"
#include <unordered_map>
#include <string>
#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<int> is necessary for Ubuntu-16.04 (gcc-5.4 and defect in C++11 standart)
std::unordered_map<FILTER, std::string, std::hash<int>> dumpFilters;
};
void initNodeDumper(const DebugCaps::Config& config);
const std::unique_ptr<NodeDumper>& 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);
}
};

View File

@ -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<Verbose>(new Verbose(__VA_ARGS__));
} // namespace MKLDNNPlugin
#else
#define VERBOSE(...)