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.
5 // Copyright (C) 2018-2019 Intel Corporation
11 #include <unordered_set>
12 #include <unordered_map>
14 #include <ade/util/checked_cast.hpp>
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
21 namespace cv { namespace gimpl {
23 GIsland::GIsland(const gapi::GBackend &bknd,
25 util::optional<std::string> &&user_tag)
27 , m_user_tag(std::move(user_tag))
34 // _ because of gcc4.8 wanings on ARM
35 GIsland::GIsland(const gapi::GBackend &_bknd,
39 util::optional<std::string> &&_user_tag)
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))
48 const GIsland::node_set& GIsland::contents() const
53 const GIsland::node_set& GIsland::in_ops() const
58 const GIsland::node_set& GIsland::out_ops() const
63 gapi::GBackend GIsland::backend() const
68 bool GIsland::is_user_specified() const
70 return m_user_tag.has_value();
73 void GIsland::debug() const
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());
86 GIsland::node_set GIsland::consumers(const ade::Graph &g,
87 const ade::NodeHandle &slot_nh) const
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)
94 auto it = std::find(in_op->inNodes().begin(),
95 in_op->inNodes().end(),
97 if (it != in_op->inNodes().end())
103 ade::NodeHandle GIsland::producer(const ade::Graph &g,
104 const ade::NodeHandle &slot_nh) const
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)
110 auto it = std::find(out_op->outNodes().begin(),
111 out_op->outNodes().end(),
113 if (it != out_op->outNodes().end())
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.
119 return ade::NodeHandle();
122 std::string GIsland::name() const
124 if (is_user_specified())
125 return m_user_tag.value();
127 std::stringstream ss;
128 ss << "island_#" << std::hex << static_cast<const void*>(this);
132 void GIslandModel::generateInitial(GIslandModel::Graph &g,
133 const ade::Graph &src_graph)
135 const GModel::ConstGraph src_g(src_graph);
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)
143 using node_set = std::unordered_set
145 , ade::HandleHasher<ade::Node>
147 using node_map = std::unordered_map
150 , ade::HandleHasher<ade::Node>
153 node_set all_operations;
154 node_map data_to_slot;
156 // First, list all operations and build create DataSlots in <g>
157 for (auto src_nh : src_g.nodes())
159 switch (src_g.metadata(src_nh).get<NodeType>().t)
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;
165 } // for (src_g.nodes)
167 // Now put single-op islands and connect it with DataSlots
168 for (auto src_op_nh : all_operations)
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())
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
177 for (auto out_edge : src_op_nh->outEdges())
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);
183 } // for(all_operations)
186 ade::NodeHandle GIslandModel::mkSlotNode(Graph &g, const ade::NodeHandle &data_nh)
188 auto nh = g.createNode();
189 g.metadata(nh).set(DataSlot{data_nh});
190 g.metadata(nh).set(NodeKind{NodeKind::SLOT});
194 ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, const gapi::GBackend& bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g)
196 const GModel::ConstGraph src_g(orig_g);
197 util::optional<std::string> user_tag;
198 if (src_g.metadata(op_nh).contains<Island>())
200 user_tag = util::make_optional(src_g.metadata(op_nh).get<Island>().island);
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});
210 ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl)
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)});
218 void GIslandModel::syncIslandTags(Graph &g, ade::Graph &orig_g)
220 GModel::Graph gm(orig_g);
221 for (auto nh : g.nodes())
223 if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
225 auto island = g.metadata(nh).get<FusedIsland>().object;
226 auto isl_tag = island->name();
227 for (const auto& orig_nh_inside : island->contents())
229 gm.metadata(orig_nh_inside).set(Island{isl_tag});
235 void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args)
237 GModel::ConstGraph gm(orig_g);
239 auto original_sorted = gm.metadata().get<ade::passes::TopologicalSortData>();
240 for (auto nh : g.nodes())
242 if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
244 auto island_obj = g.metadata(nh).get<FusedIsland>().object;
245 auto island_ops = island_obj->contents();
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);
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)});
262 ade::NodeHandle GIslandModel::producerOf(const ConstGraph &g, ade::NodeHandle &data_nh)
264 for (auto nh : g.nodes())
266 // find a data slot...
267 if (NodeKind::SLOT == g.metadata(nh).get<NodeKind>().k)
269 // which is associated with the given data object...
270 if (data_nh == g.metadata(nh).get<DataSlot>().original_data_node)
272 // which probably has a produrer...
273 if (0u != nh->inNodes().size())
275 // ...then the answer is that producer
276 return nh->inNodes().front();
278 else return ade::NodeHandle(); // input data object?
279 // return empty to break the cycle
283 // No appropriate data slot found - probably, the object has been
284 // optimized out during fusion
285 return ade::NodeHandle();