Path: blob/master/modules/gapi/src/compiler/passes/dump_dot.cpp
16354 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.3//4// Copyright (C) 2018 Intel Corporation567#include "precomp.hpp"89#include <iostream> // cout10#include <sstream> // stringstream11#include <fstream> // ofstream1213#include <ade/passes/check_cycles.hpp>1415#include "opencv2/gapi/gproto.hpp"16#include "compiler/gmodel.hpp"17#include "compiler/gislandmodel.hpp"18#include "compiler/passes/passes.hpp"1920namespace cv { namespace gimpl { namespace passes {2122// TODO: FIXME: Ideally all this low-level stuff with accessing ADE APIs directly23// should be incapsulated somewhere into GModel, so here we'd operate not24// with raw nodes and edges, but with Operations and Data it produce/consume.25void dumpDot(const ade::Graph &g, std::ostream& os)26{27GModel::ConstGraph gr(g);2829const std::unordered_map<cv::GShape, std::string> data_labels = {30{cv::GShape::GMAT, "GMat"},31{cv::GShape::GSCALAR, "GScalar"},32{cv::GShape::GARRAY, "GArray"},33};3435auto format_op_label = [&gr](ade::NodeHandle nh) -> std::string {36std::stringstream ss;37const cv::GKernel k = gr.metadata(nh).get<Op>().k;38ss << k.name << "_" << nh;39return ss.str();40};4142auto format_op = [&format_op_label](ade::NodeHandle nh) -> std::string {43return "\"" + format_op_label(nh) + "\"";44};4546auto format_obj = [&gr, &data_labels](ade::NodeHandle nh) -> std::string {47std::stringstream ss;48const auto &data = gr.metadata(nh).get<Data>();49ss << data_labels.at(data.shape) << "_" << data.rc;50return ss.str();51};5253auto format_log = [&gr](ade::NodeHandle nh, const std::string &obj_name) {54std::stringstream ss;55const auto &msgs = gr.metadata(nh).get<Journal>().messages;56ss << "xlabel=\"";57if (!obj_name.empty()) { ss << "*** " << obj_name << " ***:\n"; };58for (const auto &msg : msgs) { ss << msg << "\n"; }59ss << "\"";60return ss.str();61};6263// FIXME:64// Unify with format_log65auto format_log_e = [&gr](ade::EdgeHandle nh) {66std::stringstream ss;67const auto &msgs = gr.metadata(nh).get<Journal>().messages;68for (const auto &msg : msgs) { ss << "\n" << msg; }69return ss.str();70};7172auto sorted = gr.metadata().get<ade::passes::TopologicalSortData>();7374os << "digraph GAPI_Computation {\n";7576// Prior to dumping the graph itself, list Data and Op nodes individually77// and put type information in labels.78// Also prepare list of nodes in islands, if any79std::map<std::string, std::vector<std::string> > islands;80for (auto &nh : sorted.nodes())81{82const auto node_type = gr.metadata(nh).get<NodeType>().t;83if (NodeType::DATA == node_type)84{85const auto obj_data = gr.metadata(nh).get<Data>();86const auto obj_name = format_obj(nh);8788os << obj_name << " [label=\"" << obj_name << "\n" << obj_data.meta << "\"";89if (gr.metadata(nh).contains<Journal>()) { os << ", " << format_log(nh, obj_name); }90os << " ]\n";9192if (gr.metadata(nh).contains<Island>())93islands[gr.metadata(nh).get<Island>().island].push_back(obj_name);94}95else if (NodeType::OP == gr.metadata(nh).get<NodeType>().t)96{97const auto obj_name = format_op(nh);98const auto obj_name_label = format_op_label(nh);99100os << obj_name << " [label=\"" << obj_name_label << "\"";101if (gr.metadata(nh).contains<Journal>()) { os << ", " << format_log(nh, obj_name_label); }102os << " ]\n";103104if (gr.metadata(nh).contains<Island>())105islands[gr.metadata(nh).get<Island>().island].push_back(obj_name);106}107}108109// Then, dump Islands (only nodes, operations and data, without links)110for (const auto &isl : islands)111{112os << "subgraph \"cluster " + isl.first << "\" {\n";113for(auto isl_node : isl.second) os << isl_node << ";\n";114os << "label=\"" << isl.first << "\";";115os << "}\n";116}117118// Now dump the graph119for (auto &nh : sorted.nodes())120{121// FIXME: Alan Kay probably hates me.122switch (gr.metadata(nh).get<NodeType>().t)123{124case NodeType::DATA:125{126const auto obj_name = format_obj(nh);127for (const auto &eh : nh->outEdges())128{129os << obj_name << " -> " << format_op(eh->dstNode())130<< " [ label = \"in_port: "131<< gr.metadata(eh).get<Input>().port;132if (gr.metadata(eh).contains<Journal>()) { os << format_log_e(eh); }133os << "\" ] \n";134}135}136break;137case NodeType::OP:138{139for (const auto &eh : nh->outEdges())140{141os << format_op(nh) << " -> " << format_obj(eh->dstNode())142<< " [ label = \"out_port: "143<< gr.metadata(eh).get<Output>().port144<< " \" ]; \n";145}146}147break;148default: GAPI_Assert(false);149}150}151152// And finally dump a GIslandModel (not connected with GModel directly,153// but projected in the same .dot file side-by-side)154auto pIG = gr.metadata().get<IslandModel>().model;155GIslandModel::Graph gim(*pIG);156for (auto nh : gim.nodes())157{158switch (gim.metadata(nh).get<NodeKind>().k)159{160case NodeKind::ISLAND:161{162const auto island = gim.metadata(nh).get<FusedIsland>().object;163const auto isl_name = "\"" + island->name() + "\"";164for (auto out_nh : nh->outNodes())165{166os << isl_name << " -> \"slot:"167<< format_obj(gim.metadata(out_nh).get<DataSlot>()168.original_data_node)169<< "\"\n";170}171}172break;173174case NodeKind::SLOT:175{176const auto obj_name = format_obj(gim.metadata(nh).get<DataSlot>()177.original_data_node);178for (auto cons_nh : nh->outNodes())179{180os << "\"slot:" << obj_name << "\" -> \""181<< gim.metadata(cons_nh).get<FusedIsland>().object->name()182<< "\"\n";183}184}185break;186187default:188GAPI_Assert(false);189break;190}191}192193os << "}" << std::endl;194}195196void dumpDot(ade::passes::PassContext &ctx, std::ostream& os)197{198dumpDot(ctx.graph, os);199}200201void dumpDotStdout(ade::passes::PassContext &ctx)202{203dumpDot(ctx, std::cout);204}205206void dumpDotToFile(ade::passes::PassContext &ctx, const std::string& dump_path)207{208std::ofstream dump_file(dump_path);209210if (dump_file.is_open())211{212dumpDot(ctx, dump_file);213dump_file << std::endl;214}215}216217void dumpGraph(ade::passes::PassContext &ctx, const std::string& dump_path)218{219dump_path.empty() ? dumpDotStdout(ctx) : dumpDotToFile(ctx, dump_path);220}221222}}} // cv::gimpl::passes223224225