1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

G-API: Introduce streaming::desync and infer(ROI)

- desync() is a new (and for now, the only one) intrinsic
  which splits the graph execution into asynchronous parts
  when running in Streaming mode;
- desync() makes no effect when compiling in Traditional mode;
- Added tests on desync() working in various scenarios;
- Extended GStreamingExecutor to support desync(); also extended
  GStreamingCompiled() with a new version of pull() returning a
  vector of optional values;
- Fixed various issues with storing the type information & proper
  construction callbacks for GArray<> and GOpaque;

- Introduced a new infer(Roi,GMat) overload with a sample;

- Introduced an internal API for Islands to control fusion
  procedure (to fuse or not to fuse);
- Introduced handleStopStream() callback for island executables;
- Added GCompileArgs to metadata of the graph (required for other
  features).
This commit is contained in:
Dmitry Matveev
2020-03-18 02:38:24 +03:00
parent f345ed564a
commit ca8bb8d053
40 changed files with 2827 additions and 195 deletions
@@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "../test_precomp.hpp"
@@ -29,7 +29,9 @@ namespace
, ""
, nullptr
, { GShape::GMAT }
, { D::OpaqueKind::CV_UNKNOWN } }).pass(m).yield(0);
, { D::OpaqueKind::CV_UNKNOWN }
, { cv::detail::HostCtor{cv::util::monostate{}} }
}).pass(m).yield(0);
}
cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
@@ -38,7 +40,9 @@ namespace
, ""
, nullptr
, { GShape::GMAT }
, { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN } }).pass(m1, m2).yield(0);
, { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN }
, { cv::detail::HostCtor{cv::util::monostate{}} }
}).pass(m1, m2).yield(0);
}
std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
@@ -513,7 +513,65 @@ TEST(IslandFusion, Regression_ShouldFuseAll)
EXPECT_EQ(1u, isl_nhs.size()); // 1 island
}
// FIXME: add more tests on mixed (hetero) graphs
TEST(IslandFusion, Test_Desync_NoFuse)
{
cv::GMat in;
cv::GMat tmp1 = in*0.5f;
cv::GMat tmp2 = tmp1 + in;
cv::GMat tmp3 = cv::gapi::streaming::desync(tmp1);
cv::GMat tmp4 = tmp3*0.1f;
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
cv::GComputation comp(cv::GIn(in), cv::GOut(tmp2, tmp4));
//////////////////////////////////////////////////////////////////
// Compile the graph in "regular" mode, it should produce a single island
{
using namespace cv::gimpl;
GCompiler compiler(comp, {in_meta}, cv::compile_args());
GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
auto isl_model = GModel::ConstGraph(*graph).metadata()
.get<IslandModel>().model;
GIslandModel::ConstGraph gim(*isl_model);
const auto is_island = [&](ade::NodeHandle nh) {
return (NodeKind::ISLAND == gim.metadata(nh).get<NodeKind>().k);
};
const auto num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(1, num_isl);
}
//////////////////////////////////////////////////////////////////
// Now compile the graph in the streaming mode.
// It has to produce two islands
{
using namespace cv::gimpl;
GCompiler compiler(comp, {in_meta}, cv::compile_args());
GCompiler::GPtr graph = compiler.generateGraph();
GModel::Graph(*graph).metadata().set(Streaming{});
compiler.runPasses(*graph);
auto isl_model = GModel::ConstGraph(*graph).metadata()
.get<IslandModel>().model;
GIslandModel::ConstGraph gim(*isl_model);
const auto is_island = [&](ade::NodeHandle nh) {
return (NodeKind::ISLAND == gim.metadata(nh).get<NodeKind>().k);
};
const auto num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(2, num_isl);
}
}
// Fixme: add more tests on mixed (hetero) graphs
// ADE-222, ADE-223
// FIXME: add test on combination of user-specified island
@@ -2,11 +2,14 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018 - 2020 Intel Corporation
#include "../test_precomp.hpp"
#include <ade/graph.hpp>
#include <ade/typed_graph.hpp>
#include "compiler/transactions.hpp"
namespace opencv_test
@@ -33,10 +36,11 @@ struct SimpleGraph
enum { node_nums = 5 };
ade::Graph graph;
ade::NodeHandle fused_nh; /* For check that fusion node is connected to the
inputs of the prod and the outputs of the cons */
ade::NodeHandle fused_nh; // For check that fusion node is connected to the
// inputs of the prod and the outputs of the cons
std::array<ade::NodeHandle, node_nums> nhs;
std::array<ade::EdgeHandle, node_nums - 1> ehs;
using Change = ChangeT<>;
Change::List changes;
SimpleGraph()
@@ -192,8 +196,6 @@ TEST_F(Transactions, DropNode_Commit)
TEST_F(Transactions, Fusion_Commit)
{
namespace C = Change;
fuse();
commit();
@@ -204,8 +206,6 @@ TEST_F(Transactions, Fusion_Commit)
TEST_F(Transactions, Fusion_RollBack)
{
namespace C = Change;
fuse();
rollback();
@@ -219,4 +219,151 @@ TEST_F(Transactions, Fusion_RollBack)
}
}
namespace
{
struct MetaInt {
static const char *name() { return "int_meta"; }
int x;
};
struct MetaStr {
static const char *name() { return "string_meta"; }
std::string s;
};
}
TEST(PreservedMeta, TestMetaCopy_Full)
{
ade::Graph g;
ade::TypedGraph<MetaInt, MetaStr> tg(g);
auto src_nh = tg.createNode();
tg.metadata(src_nh).set(MetaInt{42});
tg.metadata(src_nh).set(MetaStr{"hi"});
auto dst_nh = tg.createNode();
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
// Here we specify all the meta types we know about the src node
// Assume Preserved copies its all for us
Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
ASSERT_TRUE(tg.metadata(dst_nh).contains<MetaInt>());
ASSERT_TRUE(tg.metadata(dst_nh).contains<MetaStr>());
EXPECT_EQ(42, tg.metadata(dst_nh).get<MetaInt>().x);
EXPECT_EQ("hi", tg.metadata(dst_nh).get<MetaStr>().s);
}
TEST(PreservedMeta, TestMetaCopy_Partial_Dst)
{
ade::Graph g;
ade::TypedGraph<MetaInt, MetaStr> tg(g);
auto tmp_nh1 = tg.createNode();
auto tmp_nh2 = tg.createNode();
auto src_eh = tg.link(tmp_nh1, tmp_nh2);
tg.metadata(src_eh).set(MetaInt{42});
tg.metadata(src_eh).set(MetaStr{"hi"});
auto tmp_nh3 = tg.createNode();
auto tmp_nh4 = tg.createNode();
auto dst_eh = tg.link(tmp_nh3, tmp_nh4);
EXPECT_FALSE(tg.metadata(dst_eh).contains<MetaInt>());
EXPECT_FALSE(tg.metadata(dst_eh).contains<MetaStr>());
// Here we specify just a single meta type for the src node
// Assume Preserved copies only this type and nothing else
Preserved<ade::EdgeHandle, MetaStr>(g, src_eh).copyTo(g, dst_eh);
ASSERT_FALSE(tg.metadata(dst_eh).contains<MetaInt>());
ASSERT_TRUE (tg.metadata(dst_eh).contains<MetaStr>());
EXPECT_EQ("hi", tg.metadata(dst_eh).get<MetaStr>().s);
}
TEST(PreservedMeta, TestMetaCopy_Partial_Src)
{
ade::Graph g;
ade::TypedGraph<MetaInt, MetaStr> tg(g);
auto src_nh = tg.createNode();
tg.metadata(src_nh).set(MetaInt{42});
auto dst_nh = tg.createNode();
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
// Here we specify all the meta types we know about the src node
// but the src node has just one of them.
// A valid situation, only MetaInt to be copied.
Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
ASSERT_TRUE (tg.metadata(dst_nh).contains<MetaInt>());
ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
EXPECT_EQ(42, tg.metadata(dst_nh).get<MetaInt>().x);
}
TEST(PreservedMeta, TestMetaCopy_Nothing)
{
ade::Graph g;
ade::TypedGraph<MetaInt, MetaStr> tg(g);
auto src_nh = tg.createNode();
auto dst_nh = tg.createNode();
EXPECT_FALSE(tg.metadata(src_nh).contains<MetaInt>());
EXPECT_FALSE(tg.metadata(src_nh).contains<MetaStr>());
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
EXPECT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
// Here we specify all the meta types we know about the src node
// but the src node has none of those. See how it works now
Preserved<ade::NodeHandle, MetaInt, MetaStr>(g, src_nh).copyTo(g, dst_nh);
ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaInt>());
ASSERT_FALSE(tg.metadata(dst_nh).contains<MetaStr>());
}
TEST(PreservedMeta, DropEdge)
{
ade::Graph g;
ade::TypedGraph<MetaInt, MetaStr> tg(g);
auto nh1 = tg.createNode();
auto nh2 = tg.createNode();
auto eh = tg.link(nh1, nh2);
tg.metadata(eh).set(MetaInt{42});
tg.metadata(eh).set(MetaStr{"hi"});
// Drop an edge using the transaction API
using Change = ChangeT<MetaInt, MetaStr>;
Change::List changes;
changes.enqueue<Change::DropLink>(g, nh1, eh);
EXPECT_EQ(0u, nh1->outNodes().size());
EXPECT_EQ(nullptr, eh);
// Now restore the edge and check if it's meta was restored
changes.rollback(g);
ASSERT_EQ(1u, nh1->outNodes().size());
eh = *nh1->outEdges().begin();
ASSERT_TRUE(tg.metadata(eh).contains<MetaInt>());
ASSERT_TRUE(tg.metadata(eh).contains<MetaStr>());
EXPECT_EQ(42, tg.metadata(eh).get<MetaInt>().x);
EXPECT_EQ("hi", tg.metadata(eh).get<MetaStr>().s);
}
} // opencv_test