Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / src / compiler / gislandmodel.cpp
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-2019 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