Add a new CPU_DEBUG_CAPS: OV_CPU_SUMMARY_PERF
This commit is contained in:
@@ -255,6 +255,11 @@ void Config::readDebugCapsProperties() {
|
||||
if (envVarValue = readEnv("OV_CPU_BLOB_DUMP_NODE_NAME"))
|
||||
blobDumpFilters[BY_NAME] = envVarValue;
|
||||
|
||||
if (envVarValue = readEnv("OV_CPU_SUMMARY_PERF")) {
|
||||
collectPerfCounters = true;
|
||||
summaryPerf = envVarValue;
|
||||
}
|
||||
|
||||
// always enable perf counters for verbose mode
|
||||
if (!verbose.empty())
|
||||
collectPerfCounters = true;
|
||||
|
||||
@@ -65,6 +65,7 @@ struct Config {
|
||||
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;
|
||||
std::string summaryPerf = "";
|
||||
|
||||
void readDebugCapsProperties();
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,10 @@ typedef std::vector<edge_cluster_t> edge_clusters_t;
|
||||
|
||||
dnnl::engine Graph::eng(dnnl::engine::kind::cpu, 0);
|
||||
|
||||
Graph::~Graph() {
|
||||
CPU_DEBUG_CAP_ENABLE(summary_perf(*this));
|
||||
}
|
||||
|
||||
template<typename NET>
|
||||
void Graph::CreateGraph(NET &net, const ExtensionManager::Ptr& extMgr,
|
||||
WeightsSharing::Ptr &w_cache) {
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
};
|
||||
|
||||
Graph() = default;
|
||||
~Graph();
|
||||
|
||||
Status GetStatus() {
|
||||
return status;
|
||||
@@ -76,7 +77,7 @@ public:
|
||||
return graphNodes;
|
||||
}
|
||||
|
||||
std::string GetName() {
|
||||
std::string GetName() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,88 @@ void serializeToCout(const Graph &graph) {
|
||||
std::cout << " ]" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void summary_perf(const Graph &graph) {
|
||||
const std::string& summaryPerf = graph.getConfig().summaryPerf;
|
||||
|
||||
if (summaryPerf.empty())
|
||||
return;
|
||||
|
||||
std::map<std::string, double> perf_by_type;
|
||||
std::map<NodePtr, double> perf_by_node;
|
||||
double total_avg = 0;
|
||||
uint64_t total = 0;
|
||||
for (auto &node : graph.GetNodes()) { // important: graph.graphNodes are in topological order
|
||||
double avg = node->PerfCounter().avg();
|
||||
auto type = node->getTypeStr() + "_" + node->getPrimitiveDescriptorType();
|
||||
auto name = node->getName();
|
||||
|
||||
total += node->PerfCounter().count() * avg;
|
||||
total_avg += avg;
|
||||
|
||||
if (perf_by_type.count(type))
|
||||
perf_by_type[type] += avg;
|
||||
else
|
||||
perf_by_type[type] = avg;
|
||||
|
||||
if (perf_by_node.count(node))
|
||||
perf_by_node[node] += avg;
|
||||
else
|
||||
perf_by_node[node] = avg;
|
||||
}
|
||||
|
||||
if (total_avg < 1) return;
|
||||
|
||||
std::cout << "======= ENABLE_DEBUG_CAPS:OV_CPU_SUMMARY_PERF ======" << std::endl;
|
||||
std::cout << "Summary of " << graph.GetName() << " @" << std::hash<uint64_t>{}(reinterpret_cast<uint64_t>(&graph)) << std::endl;
|
||||
std::cout << " Total(us): " << (uint64_t)(total) << std::endl;
|
||||
std::cout << " Total_avg(us): " << (uint64_t)(total_avg) << std::endl;
|
||||
{
|
||||
std::cout << " perf_by_type:" << std::endl;
|
||||
std::vector<std::pair<std::string, double> > A;
|
||||
for (auto& it : perf_by_type)
|
||||
A.push_back(it);
|
||||
sort(A.begin(), A.end(),
|
||||
[](std::pair<std::string, double>& a,
|
||||
std::pair<std::string, double>& b){
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
for (auto& it : A) {
|
||||
std::stringstream ss;
|
||||
int percentage = (int)(it.second*100/total_avg);
|
||||
if (percentage == 0) break;
|
||||
ss << std::setw(10) << std::right << percentage << " % :" << it.first << std::endl;
|
||||
std::cout << ss.str();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::cout << " perf_by_node:" << std::endl;
|
||||
std::vector<std::pair<NodePtr, double> > A;
|
||||
for (auto& it : perf_by_node)
|
||||
A.push_back(it);
|
||||
sort(A.begin(), A.end(),
|
||||
[](std::pair<NodePtr, double>& a,
|
||||
std::pair<NodePtr, double>& b){
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
for (auto& it : A) {
|
||||
std::stringstream ss;
|
||||
auto percentage = it.second*100/total_avg;
|
||||
auto node = it.first;
|
||||
if (node->PerfCounter().count() == 0) continue;
|
||||
if (node->PerfCounter().avg() < 1) continue;
|
||||
ss << std::setw(10) << std::right << std::fixed << std::setprecision(2) << percentage << " % "
|
||||
<< std::setw(8) << std::right << node->PerfCounter().avg() << "(us)x" << node->PerfCounter().count()
|
||||
<< " #" << node->getExecIndex()
|
||||
<< " " << node->getName()
|
||||
<< " " << node->getTypeStr() + "_" + node->getPrimitiveDescriptorType() << std::endl;
|
||||
std::cout << ss.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace intel_cpu
|
||||
} // namespace ov
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace intel_cpu {
|
||||
std::shared_ptr<ngraph::Function> dump_graph_as_ie_ngraph_net(const Graph &graph);
|
||||
#ifdef CPU_DEBUG_CAPS
|
||||
void serialize(const Graph &graph);
|
||||
void summary_perf(const Graph &graph);
|
||||
#endif // CPU_DEBUG_CAPS
|
||||
|
||||
} // namespace intel_cpu
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
}
|
||||
|
||||
uint64_t avg() const { return (num == 0) ? 0 : total_duration / num; }
|
||||
uint32_t count() const { return num; }
|
||||
|
||||
private:
|
||||
void start_itr() {
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
do { \
|
||||
::std::stringstream ss___; \
|
||||
::ov::write_all_to_stream(ss___, __VA_ARGS__); \
|
||||
std::cout << __func__ << ":" << __LINE__ << " " << ss___.str() << std::endl; \
|
||||
std::cout << "[ VERBOSE ] " << __func__ << ":" << __LINE__ << " " << ss___.str() << std::endl; \
|
||||
} while (0)
|
||||
} // namespace intel_cpu
|
||||
} // namespace ov
|
||||
|
||||
Reference in New Issue
Block a user