Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/gapi/src/compiler/passes/dump_dot.cpp
16354 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
//
5
// Copyright (C) 2018 Intel Corporation
6
7
8
#include "precomp.hpp"
9
10
#include <iostream> // cout
11
#include <sstream> // stringstream
12
#include <fstream> // ofstream
13
14
#include <ade/passes/check_cycles.hpp>
15
16
#include "opencv2/gapi/gproto.hpp"
17
#include "compiler/gmodel.hpp"
18
#include "compiler/gislandmodel.hpp"
19
#include "compiler/passes/passes.hpp"
20
21
namespace cv { namespace gimpl { namespace passes {
22
23
// TODO: FIXME: Ideally all this low-level stuff with accessing ADE APIs directly
24
// should be incapsulated somewhere into GModel, so here we'd operate not
25
// with raw nodes and edges, but with Operations and Data it produce/consume.
26
void dumpDot(const ade::Graph &g, std::ostream& os)
27
{
28
GModel::ConstGraph gr(g);
29
30
const std::unordered_map<cv::GShape, std::string> data_labels = {
31
{cv::GShape::GMAT, "GMat"},
32
{cv::GShape::GSCALAR, "GScalar"},
33
{cv::GShape::GARRAY, "GArray"},
34
};
35
36
auto format_op_label = [&gr](ade::NodeHandle nh) -> std::string {
37
std::stringstream ss;
38
const cv::GKernel k = gr.metadata(nh).get<Op>().k;
39
ss << k.name << "_" << nh;
40
return ss.str();
41
};
42
43
auto format_op = [&format_op_label](ade::NodeHandle nh) -> std::string {
44
return "\"" + format_op_label(nh) + "\"";
45
};
46
47
auto format_obj = [&gr, &data_labels](ade::NodeHandle nh) -> std::string {
48
std::stringstream ss;
49
const auto &data = gr.metadata(nh).get<Data>();
50
ss << data_labels.at(data.shape) << "_" << data.rc;
51
return ss.str();
52
};
53
54
auto format_log = [&gr](ade::NodeHandle nh, const std::string &obj_name) {
55
std::stringstream ss;
56
const auto &msgs = gr.metadata(nh).get<Journal>().messages;
57
ss << "xlabel=\"";
58
if (!obj_name.empty()) { ss << "*** " << obj_name << " ***:\n"; };
59
for (const auto &msg : msgs) { ss << msg << "\n"; }
60
ss << "\"";
61
return ss.str();
62
};
63
64
// FIXME:
65
// Unify with format_log
66
auto format_log_e = [&gr](ade::EdgeHandle nh) {
67
std::stringstream ss;
68
const auto &msgs = gr.metadata(nh).get<Journal>().messages;
69
for (const auto &msg : msgs) { ss << "\n" << msg; }
70
return ss.str();
71
};
72
73
auto sorted = gr.metadata().get<ade::passes::TopologicalSortData>();
74
75
os << "digraph GAPI_Computation {\n";
76
77
// Prior to dumping the graph itself, list Data and Op nodes individually
78
// and put type information in labels.
79
// Also prepare list of nodes in islands, if any
80
std::map<std::string, std::vector<std::string> > islands;
81
for (auto &nh : sorted.nodes())
82
{
83
const auto node_type = gr.metadata(nh).get<NodeType>().t;
84
if (NodeType::DATA == node_type)
85
{
86
const auto obj_data = gr.metadata(nh).get<Data>();
87
const auto obj_name = format_obj(nh);
88
89
os << obj_name << " [label=\"" << obj_name << "\n" << obj_data.meta << "\"";
90
if (gr.metadata(nh).contains<Journal>()) { os << ", " << format_log(nh, obj_name); }
91
os << " ]\n";
92
93
if (gr.metadata(nh).contains<Island>())
94
islands[gr.metadata(nh).get<Island>().island].push_back(obj_name);
95
}
96
else if (NodeType::OP == gr.metadata(nh).get<NodeType>().t)
97
{
98
const auto obj_name = format_op(nh);
99
const auto obj_name_label = format_op_label(nh);
100
101
os << obj_name << " [label=\"" << obj_name_label << "\"";
102
if (gr.metadata(nh).contains<Journal>()) { os << ", " << format_log(nh, obj_name_label); }
103
os << " ]\n";
104
105
if (gr.metadata(nh).contains<Island>())
106
islands[gr.metadata(nh).get<Island>().island].push_back(obj_name);
107
}
108
}
109
110
// Then, dump Islands (only nodes, operations and data, without links)
111
for (const auto &isl : islands)
112
{
113
os << "subgraph \"cluster " + isl.first << "\" {\n";
114
for(auto isl_node : isl.second) os << isl_node << ";\n";
115
os << "label=\"" << isl.first << "\";";
116
os << "}\n";
117
}
118
119
// Now dump the graph
120
for (auto &nh : sorted.nodes())
121
{
122
// FIXME: Alan Kay probably hates me.
123
switch (gr.metadata(nh).get<NodeType>().t)
124
{
125
case NodeType::DATA:
126
{
127
const auto obj_name = format_obj(nh);
128
for (const auto &eh : nh->outEdges())
129
{
130
os << obj_name << " -> " << format_op(eh->dstNode())
131
<< " [ label = \"in_port: "
132
<< gr.metadata(eh).get<Input>().port;
133
if (gr.metadata(eh).contains<Journal>()) { os << format_log_e(eh); }
134
os << "\" ] \n";
135
}
136
}
137
break;
138
case NodeType::OP:
139
{
140
for (const auto &eh : nh->outEdges())
141
{
142
os << format_op(nh) << " -> " << format_obj(eh->dstNode())
143
<< " [ label = \"out_port: "
144
<< gr.metadata(eh).get<Output>().port
145
<< " \" ]; \n";
146
}
147
}
148
break;
149
default: GAPI_Assert(false);
150
}
151
}
152
153
// And finally dump a GIslandModel (not connected with GModel directly,
154
// but projected in the same .dot file side-by-side)
155
auto pIG = gr.metadata().get<IslandModel>().model;
156
GIslandModel::Graph gim(*pIG);
157
for (auto nh : gim.nodes())
158
{
159
switch (gim.metadata(nh).get<NodeKind>().k)
160
{
161
case NodeKind::ISLAND:
162
{
163
const auto island = gim.metadata(nh).get<FusedIsland>().object;
164
const auto isl_name = "\"" + island->name() + "\"";
165
for (auto out_nh : nh->outNodes())
166
{
167
os << isl_name << " -> \"slot:"
168
<< format_obj(gim.metadata(out_nh).get<DataSlot>()
169
.original_data_node)
170
<< "\"\n";
171
}
172
}
173
break;
174
175
case NodeKind::SLOT:
176
{
177
const auto obj_name = format_obj(gim.metadata(nh).get<DataSlot>()
178
.original_data_node);
179
for (auto cons_nh : nh->outNodes())
180
{
181
os << "\"slot:" << obj_name << "\" -> \""
182
<< gim.metadata(cons_nh).get<FusedIsland>().object->name()
183
<< "\"\n";
184
}
185
}
186
break;
187
188
default:
189
GAPI_Assert(false);
190
break;
191
}
192
}
193
194
os << "}" << std::endl;
195
}
196
197
void dumpDot(ade::passes::PassContext &ctx, std::ostream& os)
198
{
199
dumpDot(ctx.graph, os);
200
}
201
202
void dumpDotStdout(ade::passes::PassContext &ctx)
203
{
204
dumpDot(ctx, std::cout);
205
}
206
207
void dumpDotToFile(ade::passes::PassContext &ctx, const std::string& dump_path)
208
{
209
std::ofstream dump_file(dump_path);
210
211
if (dump_file.is_open())
212
{
213
dumpDot(ctx, dump_file);
214
dump_file << std::endl;
215
}
216
}
217
218
void dumpGraph(ade::passes::PassContext &ctx, const std::string& dump_path)
219
{
220
dump_path.empty() ? dumpDotStdout(ctx) : dumpDotToFile(ctx, dump_path);
221
}
222
223
}}} // cv::gimpl::passes
224
225