Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/gapi/src/compiler/gislandmodel.cpp
16337 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 <sstream>
11
#include <unordered_set>
12
#include <unordered_map>
13
14
#include <ade/util/checked_cast.hpp>
15
16
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile()
17
#include "compiler/gmodel.hpp"
18
#include "compiler/gislandmodel.hpp"
19
#include "logger.hpp" // GAPI_LOG
20
21
namespace cv { namespace gimpl {
22
23
GIsland::GIsland(const gapi::GBackend &bknd,
24
ade::NodeHandle op,
25
util::optional<std::string> &&user_tag)
26
: m_backend(bknd)
27
, m_user_tag(std::move(user_tag))
28
{
29
m_all.insert(op);
30
m_in_ops.insert(op);
31
m_out_ops.insert(op);
32
}
33
34
// _ because of gcc4.8 wanings on ARM
35
GIsland::GIsland(const gapi::GBackend &_bknd,
36
node_set &&_all,
37
node_set &&_in_ops,
38
node_set &&_out_ops,
39
util::optional<std::string> &&_user_tag)
40
: m_backend(_bknd)
41
, m_all(std::move(_all))
42
, m_in_ops(std::move(_in_ops))
43
, m_out_ops(std::move(_out_ops))
44
, m_user_tag(std::move(_user_tag))
45
{
46
}
47
48
const GIsland::node_set& GIsland::contents() const
49
{
50
return m_all;
51
}
52
53
const GIsland::node_set& GIsland::in_ops() const
54
{
55
return m_in_ops;
56
}
57
58
const GIsland::node_set& GIsland::out_ops() const
59
{
60
return m_out_ops;
61
}
62
63
gapi::GBackend GIsland::backend() const
64
{
65
return m_backend;
66
}
67
68
bool GIsland::is_user_specified() const
69
{
70
return m_user_tag.has_value();
71
}
72
73
void GIsland::debug() const
74
{
75
std::stringstream stream;
76
stream << name() << " {{\n input ops: ";
77
for (const auto& nh : m_in_ops) stream << nh << "; ";
78
stream << "\n output ops: ";
79
for (const auto& nh : m_out_ops) stream << nh << "; ";
80
stream << "\n contents: ";
81
for (const auto& nh : m_all) stream << nh << "; ";
82
stream << "\n}}" << std::endl;
83
GAPI_LOG_INFO(NULL, stream.str());
84
}
85
86
GIsland::node_set GIsland::consumers(const ade::Graph &g,
87
const ade::NodeHandle &slot_nh) const
88
{
89
GIslandModel::ConstGraph gim(g);
90
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;
91
GIsland::node_set result;
92
for (const auto& in_op : m_in_ops)
93
{
94
auto it = std::find(in_op->inNodes().begin(),
95
in_op->inNodes().end(),
96
data_nh);
97
if (it != in_op->inNodes().end())
98
result.insert(in_op);
99
}
100
return result;
101
}
102
103
ade::NodeHandle GIsland::producer(const ade::Graph &g,
104
const ade::NodeHandle &slot_nh) const
105
{
106
GIslandModel::ConstGraph gim(g);
107
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;
108
for (const auto& out_op : m_out_ops)
109
{
110
auto it = std::find(out_op->outNodes().begin(),
111
out_op->outNodes().end(),
112
data_nh);
113
if (it != out_op->outNodes().end())
114
return out_op;
115
}
116
// Consistency: A GIsland requested for producer() of slot_nh should
117
// always had the appropriate GModel node handle in its m_out_ops vector.
118
GAPI_Assert(false);
119
return ade::NodeHandle();
120
}
121
122
std::string GIsland::name() const
123
{
124
if (is_user_specified())
125
return m_user_tag.value();
126
127
std::stringstream ss;
128
ss << "island_#" << std::hex << static_cast<const void*>(this);
129
return ss.str();
130
}
131
132
void GIslandModel::generateInitial(GIslandModel::Graph &g,
133
const ade::Graph &src_graph)
134
{
135
const GModel::ConstGraph src_g(src_graph);
136
137
// Initially GIslandModel is a 1:1 projection from GModel:
138
// 1) Every GModel::OP becomes a separate GIslandModel::FusedIsland;
139
// 2) Every GModel::DATA becomes GIslandModel::DataSlot;
140
// 3) Single-operation FusedIslands are connected with DataSlots in the
141
// same way as OPs and DATA (edges with the same metadata)
142
143
using node_set = std::unordered_set
144
< ade::NodeHandle
145
, ade::HandleHasher<ade::Node>
146
>;
147
using node_map = std::unordered_map
148
< ade::NodeHandle
149
, ade::NodeHandle
150
, ade::HandleHasher<ade::Node>
151
>;
152
153
node_set all_operations;
154
node_map data_to_slot;
155
156
// First, list all operations and build create DataSlots in <g>
157
for (auto src_nh : src_g.nodes())
158
{
159
switch (src_g.metadata(src_nh).get<NodeType>().t)
160
{
161
case NodeType::OP: all_operations.insert(src_nh); break;
162
case NodeType::DATA: data_to_slot[src_nh] = mkSlotNode(g, src_nh); break;
163
default: GAPI_Assert(false); break;
164
}
165
} // for (src_g.nodes)
166
167
// Now put single-op islands and connect it with DataSlots
168
for (auto src_op_nh : all_operations)
169
{
170
auto nh = mkIslandNode(g, src_g.metadata(src_op_nh).get<Op>().backend, src_op_nh, src_graph);
171
for (auto in_edge : src_op_nh->inEdges())
172
{
173
auto src_data_nh = in_edge->srcNode();
174
auto isl_slot_nh = data_to_slot.at(src_data_nh);
175
g.link(isl_slot_nh, nh); // no other data stored yet
176
}
177
for (auto out_edge : src_op_nh->outEdges())
178
{
179
auto dst_data_nh = out_edge->dstNode();
180
auto isl_slot_nh = data_to_slot.at(dst_data_nh);
181
g.link(nh, isl_slot_nh);
182
}
183
} // for(all_operations)
184
}
185
186
ade::NodeHandle GIslandModel::mkSlotNode(Graph &g, const ade::NodeHandle &data_nh)
187
{
188
auto nh = g.createNode();
189
g.metadata(nh).set(DataSlot{data_nh});
190
g.metadata(nh).set(NodeKind{NodeKind::SLOT});
191
return nh;
192
}
193
194
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, const gapi::GBackend& bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g)
195
{
196
const GModel::ConstGraph src_g(orig_g);
197
util::optional<std::string> user_tag;
198
if (src_g.metadata(op_nh).contains<Island>())
199
{
200
user_tag = util::make_optional(src_g.metadata(op_nh).get<Island>().island);
201
}
202
203
auto nh = g.createNode();
204
std::shared_ptr<GIsland> island(new GIsland(bknd, op_nh, std::move(user_tag)));
205
g.metadata(nh).set(FusedIsland{std::move(island)});
206
g.metadata(nh).set(NodeKind{NodeKind::ISLAND});
207
return nh;
208
}
209
210
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl)
211
{
212
ade::NodeHandle nh = g.createNode();
213
g.metadata(nh).set(cv::gimpl::NodeKind{cv::gimpl::NodeKind::ISLAND});
214
g.metadata(nh).set<cv::gimpl::FusedIsland>({std::move(isl)});
215
return nh;
216
}
217
218
void GIslandModel::syncIslandTags(Graph &g, ade::Graph &orig_g)
219
{
220
GModel::Graph gm(orig_g);
221
for (auto nh : g.nodes())
222
{
223
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
224
{
225
auto island = g.metadata(nh).get<FusedIsland>().object;
226
auto isl_tag = island->name();
227
for (const auto& orig_nh_inside : island->contents())
228
{
229
gm.metadata(orig_nh_inside).set(Island{isl_tag});
230
}
231
}
232
}
233
}
234
235
void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args)
236
{
237
GModel::ConstGraph gm(orig_g);
238
239
auto original_sorted = gm.metadata().get<ade::passes::TopologicalSortData>();
240
for (auto nh : g.nodes())
241
{
242
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
243
{
244
auto island_obj = g.metadata(nh).get<FusedIsland>().object;
245
auto island_ops = island_obj->contents();
246
247
std::vector<ade::NodeHandle> topo_sorted_list;
248
ade::util::copy_if(original_sorted.nodes(),
249
std::back_inserter(topo_sorted_list),
250
[&](ade::NodeHandle sorted_nh) {
251
return ade::util::contains(island_ops, sorted_nh);
252
});
253
254
auto island_exe = island_obj->backend().priv()
255
.compile(orig_g, args, topo_sorted_list);
256
GAPI_Assert(nullptr != island_exe);
257
g.metadata(nh).set(IslandExec{std::move(island_exe)});
258
}
259
}
260
}
261
262
ade::NodeHandle GIslandModel::producerOf(const ConstGraph &g, ade::NodeHandle &data_nh)
263
{
264
for (auto nh : g.nodes())
265
{
266
// find a data slot...
267
if (NodeKind::SLOT == g.metadata(nh).get<NodeKind>().k)
268
{
269
// which is associated with the given data object...
270
if (data_nh == g.metadata(nh).get<DataSlot>().original_data_node)
271
{
272
// which probably has a produrer...
273
if (0u != nh->inNodes().size())
274
{
275
// ...then the answer is that producer
276
return nh->inNodes().front();
277
}
278
else return ade::NodeHandle(); // input data object?
279
// return empty to break the cycle
280
}
281
}
282
}
283
// No appropriate data slot found - probably, the object has been
284
// optimized out during fusion
285
return ade::NodeHandle();
286
}
287
288
} // namespace cv
289
} // namespace gimpl
290
291