Path: blob/master/modules/gapi/src/compiler/gislandmodel.cpp
16337 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 <sstream>10#include <unordered_set>11#include <unordered_map>1213#include <ade/util/checked_cast.hpp>1415#include "api/gbackend_priv.hpp" // GBackend::Priv().compile()16#include "compiler/gmodel.hpp"17#include "compiler/gislandmodel.hpp"18#include "logger.hpp" // GAPI_LOG1920namespace cv { namespace gimpl {2122GIsland::GIsland(const gapi::GBackend &bknd,23ade::NodeHandle op,24util::optional<std::string> &&user_tag)25: m_backend(bknd)26, m_user_tag(std::move(user_tag))27{28m_all.insert(op);29m_in_ops.insert(op);30m_out_ops.insert(op);31}3233// _ because of gcc4.8 wanings on ARM34GIsland::GIsland(const gapi::GBackend &_bknd,35node_set &&_all,36node_set &&_in_ops,37node_set &&_out_ops,38util::optional<std::string> &&_user_tag)39: m_backend(_bknd)40, m_all(std::move(_all))41, m_in_ops(std::move(_in_ops))42, m_out_ops(std::move(_out_ops))43, m_user_tag(std::move(_user_tag))44{45}4647const GIsland::node_set& GIsland::contents() const48{49return m_all;50}5152const GIsland::node_set& GIsland::in_ops() const53{54return m_in_ops;55}5657const GIsland::node_set& GIsland::out_ops() const58{59return m_out_ops;60}6162gapi::GBackend GIsland::backend() const63{64return m_backend;65}6667bool GIsland::is_user_specified() const68{69return m_user_tag.has_value();70}7172void GIsland::debug() const73{74std::stringstream stream;75stream << name() << " {{\n input ops: ";76for (const auto& nh : m_in_ops) stream << nh << "; ";77stream << "\n output ops: ";78for (const auto& nh : m_out_ops) stream << nh << "; ";79stream << "\n contents: ";80for (const auto& nh : m_all) stream << nh << "; ";81stream << "\n}}" << std::endl;82GAPI_LOG_INFO(NULL, stream.str());83}8485GIsland::node_set GIsland::consumers(const ade::Graph &g,86const ade::NodeHandle &slot_nh) const87{88GIslandModel::ConstGraph gim(g);89auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;90GIsland::node_set result;91for (const auto& in_op : m_in_ops)92{93auto it = std::find(in_op->inNodes().begin(),94in_op->inNodes().end(),95data_nh);96if (it != in_op->inNodes().end())97result.insert(in_op);98}99return result;100}101102ade::NodeHandle GIsland::producer(const ade::Graph &g,103const ade::NodeHandle &slot_nh) const104{105GIslandModel::ConstGraph gim(g);106auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;107for (const auto& out_op : m_out_ops)108{109auto it = std::find(out_op->outNodes().begin(),110out_op->outNodes().end(),111data_nh);112if (it != out_op->outNodes().end())113return out_op;114}115// Consistency: A GIsland requested for producer() of slot_nh should116// always had the appropriate GModel node handle in its m_out_ops vector.117GAPI_Assert(false);118return ade::NodeHandle();119}120121std::string GIsland::name() const122{123if (is_user_specified())124return m_user_tag.value();125126std::stringstream ss;127ss << "island_#" << std::hex << static_cast<const void*>(this);128return ss.str();129}130131void GIslandModel::generateInitial(GIslandModel::Graph &g,132const ade::Graph &src_graph)133{134const GModel::ConstGraph src_g(src_graph);135136// Initially GIslandModel is a 1:1 projection from GModel:137// 1) Every GModel::OP becomes a separate GIslandModel::FusedIsland;138// 2) Every GModel::DATA becomes GIslandModel::DataSlot;139// 3) Single-operation FusedIslands are connected with DataSlots in the140// same way as OPs and DATA (edges with the same metadata)141142using node_set = std::unordered_set143< ade::NodeHandle144, ade::HandleHasher<ade::Node>145>;146using node_map = std::unordered_map147< ade::NodeHandle148, ade::NodeHandle149, ade::HandleHasher<ade::Node>150>;151152node_set all_operations;153node_map data_to_slot;154155// First, list all operations and build create DataSlots in <g>156for (auto src_nh : src_g.nodes())157{158switch (src_g.metadata(src_nh).get<NodeType>().t)159{160case NodeType::OP: all_operations.insert(src_nh); break;161case NodeType::DATA: data_to_slot[src_nh] = mkSlotNode(g, src_nh); break;162default: GAPI_Assert(false); break;163}164} // for (src_g.nodes)165166// Now put single-op islands and connect it with DataSlots167for (auto src_op_nh : all_operations)168{169auto nh = mkIslandNode(g, src_g.metadata(src_op_nh).get<Op>().backend, src_op_nh, src_graph);170for (auto in_edge : src_op_nh->inEdges())171{172auto src_data_nh = in_edge->srcNode();173auto isl_slot_nh = data_to_slot.at(src_data_nh);174g.link(isl_slot_nh, nh); // no other data stored yet175}176for (auto out_edge : src_op_nh->outEdges())177{178auto dst_data_nh = out_edge->dstNode();179auto isl_slot_nh = data_to_slot.at(dst_data_nh);180g.link(nh, isl_slot_nh);181}182} // for(all_operations)183}184185ade::NodeHandle GIslandModel::mkSlotNode(Graph &g, const ade::NodeHandle &data_nh)186{187auto nh = g.createNode();188g.metadata(nh).set(DataSlot{data_nh});189g.metadata(nh).set(NodeKind{NodeKind::SLOT});190return nh;191}192193ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, const gapi::GBackend& bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g)194{195const GModel::ConstGraph src_g(orig_g);196util::optional<std::string> user_tag;197if (src_g.metadata(op_nh).contains<Island>())198{199user_tag = util::make_optional(src_g.metadata(op_nh).get<Island>().island);200}201202auto nh = g.createNode();203std::shared_ptr<GIsland> island(new GIsland(bknd, op_nh, std::move(user_tag)));204g.metadata(nh).set(FusedIsland{std::move(island)});205g.metadata(nh).set(NodeKind{NodeKind::ISLAND});206return nh;207}208209ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl)210{211ade::NodeHandle nh = g.createNode();212g.metadata(nh).set(cv::gimpl::NodeKind{cv::gimpl::NodeKind::ISLAND});213g.metadata(nh).set<cv::gimpl::FusedIsland>({std::move(isl)});214return nh;215}216217void GIslandModel::syncIslandTags(Graph &g, ade::Graph &orig_g)218{219GModel::Graph gm(orig_g);220for (auto nh : g.nodes())221{222if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)223{224auto island = g.metadata(nh).get<FusedIsland>().object;225auto isl_tag = island->name();226for (const auto& orig_nh_inside : island->contents())227{228gm.metadata(orig_nh_inside).set(Island{isl_tag});229}230}231}232}233234void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args)235{236GModel::ConstGraph gm(orig_g);237238auto original_sorted = gm.metadata().get<ade::passes::TopologicalSortData>();239for (auto nh : g.nodes())240{241if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)242{243auto island_obj = g.metadata(nh).get<FusedIsland>().object;244auto island_ops = island_obj->contents();245246std::vector<ade::NodeHandle> topo_sorted_list;247ade::util::copy_if(original_sorted.nodes(),248std::back_inserter(topo_sorted_list),249[&](ade::NodeHandle sorted_nh) {250return ade::util::contains(island_ops, sorted_nh);251});252253auto island_exe = island_obj->backend().priv()254.compile(orig_g, args, topo_sorted_list);255GAPI_Assert(nullptr != island_exe);256g.metadata(nh).set(IslandExec{std::move(island_exe)});257}258}259}260261ade::NodeHandle GIslandModel::producerOf(const ConstGraph &g, ade::NodeHandle &data_nh)262{263for (auto nh : g.nodes())264{265// find a data slot...266if (NodeKind::SLOT == g.metadata(nh).get<NodeKind>().k)267{268// which is associated with the given data object...269if (data_nh == g.metadata(nh).get<DataSlot>().original_data_node)270{271// which probably has a produrer...272if (0u != nh->inNodes().size())273{274// ...then the answer is that producer275return nh->inNodes().front();276}277else return ade::NodeHandle(); // input data object?278// return empty to break the cycle279}280}281}282// No appropriate data slot found - probably, the object has been283// optimized out during fusion284return ade::NodeHandle();285}286287} // namespace cv288} // namespace gimpl289290291