gapi_int_island_fusion_tests.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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. #include "../test_precomp.hpp"
  7. #include "compiler/transactions.hpp"
  8. #include "../gapi_mock_kernels.hpp"
  9. #include "compiler/gislandmodel.hpp"
  10. #include "compiler/gcompiler.hpp"
  11. #include "compiler/gmodel_priv.hpp"
  12. namespace opencv_test
  13. {
  14. TEST(IslandFusion, TwoOps_OneIsland)
  15. {
  16. namespace J = Jupiter; // see mock_kernels.cpp
  17. // Define a computation:
  18. //
  19. // (in) -> J::Foo1 -> (tmp0) -> J::Foo2 -> (out)
  20. // : :
  21. // : "island0" :
  22. // :<----------------------------->:
  23. cv::GMat in;
  24. cv::GMat tmp0 = I::Foo::on(in);
  25. cv::GMat out = I::Foo::on(tmp0);
  26. cv::GComputation cc(in, out);
  27. // Prepare compilation parameters manually
  28. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  29. const auto pkg = cv::gapi::kernels<J::Foo>();
  30. // Directly instantiate G-API graph compiler and run partial compilation
  31. cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
  32. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  33. compiler.runPasses(*graph);
  34. // Inspect the graph and verify the islands configuration
  35. cv::gimpl::GModel::ConstGraph gm(*graph);
  36. cv::gimpl::GModel::ConstLayoutGraph glm(*graph);
  37. auto in_nh = cv::gimpl::GModel::dataNodeOf(glm, in);
  38. auto tmp_nh = cv::gimpl::GModel::dataNodeOf(glm, tmp0);
  39. auto out_nh = cv::gimpl::GModel::dataNodeOf(glm, out);
  40. // in/out mats shouldn't be assigned to any Island
  41. EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
  42. EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
  43. // Since tmp is surrounded by two J kernels, tmp should be assigned
  44. // to island J
  45. EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
  46. }
  47. TEST(IslandFusion, TwoOps_TwoIslands)
  48. {
  49. namespace J = Jupiter; // see mock_kernels.cpp
  50. namespace S = Saturn; // see mock_kernels.cpp
  51. // Define a computation:
  52. //
  53. // (in) -> J::Foo --> (tmp0) -> S::Bar --> (out)
  54. // : : -> :
  55. // : : : :
  56. // :<-------->: :<-------->:
  57. cv::GMat in;
  58. cv::GMat tmp0 = I::Foo::on(in);
  59. cv::GMat out = I::Bar::on(tmp0, tmp0);
  60. cv::GComputation cc(in, out);
  61. // Prepare compilation parameters manually
  62. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  63. const auto pkg = cv::gapi::kernels<J::Foo, S::Bar>();
  64. // Directly instantiate G-API graph compiler and run partial compilation
  65. cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
  66. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  67. compiler.runPasses(*graph);
  68. // Inspect the graph and verify the islands configuration
  69. cv::gimpl::GModel::ConstGraph gm(*graph);
  70. auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
  71. auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
  72. auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
  73. // in/tmp/out mats shouldn't be assigned to any Island
  74. EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
  75. EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
  76. EXPECT_FALSE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
  77. auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
  78. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  79. // There should be two islands in the GIslandModel
  80. const auto is_island = [&](ade::NodeHandle nh) {
  81. return (cv::gimpl::NodeKind::ISLAND
  82. == gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
  83. };
  84. const std::size_t num_isl = std::count_if(gim.nodes().begin(),
  85. gim.nodes().end(),
  86. is_island);
  87. EXPECT_EQ(2u, num_isl);
  88. auto isl_foo_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
  89. auto isl_bar_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
  90. ASSERT_NE(nullptr, isl_foo_nh);
  91. ASSERT_NE(nullptr, isl_bar_nh);
  92. // Islands should be different
  93. auto isl_foo_obj = gim.metadata(isl_foo_nh).get<cv::gimpl::FusedIsland>().object;
  94. auto isl_bar_obj = gim.metadata(isl_bar_nh).get<cv::gimpl::FusedIsland>().object;
  95. EXPECT_FALSE(isl_foo_obj == isl_bar_obj);
  96. }
  97. TEST(IslandFusion, ConsumerHasTwoInputs)
  98. {
  99. namespace J = Jupiter; // see mock_kernels.cpp
  100. // Define a computation: island
  101. // ............................
  102. // (in0) ->:J::Foo -> (tmp) -> S::Bar :--> (out)
  103. // :....................^.....:
  104. // |
  105. // (in1) -----------------------`
  106. //
  107. // Check that island is build correctly, when consumer has two inputs
  108. GMat in[2];
  109. GMat tmp = I::Foo::on(in[0]);
  110. GMat out = I::Bar::on(tmp, in[1]);
  111. cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
  112. // Prepare compilation parameters manually
  113. cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)}),
  114. GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)})};
  115. const auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
  116. // Directly instantiate G-API graph compiler and run partial compilation
  117. cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
  118. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  119. compiler.runPasses(*graph);
  120. cv::gimpl::GModel::ConstGraph gm(*graph);
  121. auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
  122. auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
  123. auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
  124. auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
  125. EXPECT_FALSE(gm.metadata(in0_nh ).contains<cv::gimpl::Island>());
  126. EXPECT_FALSE(gm.metadata(in1_nh ).contains<cv::gimpl::Island>());
  127. EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
  128. EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
  129. auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
  130. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  131. const auto is_island = [&](ade::NodeHandle nh) {
  132. return (cv::gimpl::NodeKind::ISLAND
  133. == gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
  134. };
  135. const std::size_t num_isl = std::count_if(gim.nodes().begin(),
  136. gim.nodes().end(),
  137. is_island);
  138. EXPECT_EQ(1u, num_isl);
  139. auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
  140. auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
  141. EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp_nh));
  142. EXPECT_EQ(2u, static_cast<std::size_t>(isl_nh->inNodes().size()));
  143. EXPECT_EQ(1u, static_cast<std::size_t>(isl_nh->outNodes().size()));
  144. }
  145. TEST(IslandFusion, DataNodeUsedDifferentBackend)
  146. {
  147. // Define a computation:
  148. //
  149. // internal isl isl0
  150. // ...........................
  151. // (in1) -> :J::Foo--> (tmp) -> J::Foo: --> (out0)
  152. // :............|............:
  153. // | ........
  154. // `---->:S::Baz: --> (out1)
  155. // :......:
  156. // Check that the node was not dropped out of the island
  157. // because it is used by the kernel from another backend
  158. namespace J = Jupiter;
  159. namespace S = Saturn;
  160. cv::GMat in, tmp, out0;
  161. cv::GScalar out1;
  162. tmp = I::Foo::on(in);
  163. out0 = I::Foo::on(tmp);
  164. out1 = I::Baz::on(tmp);
  165. cv::GComputation cc(cv::GIn(in), cv::GOut(out0, out1));
  166. // Prepare compilation parameters manually
  167. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  168. const auto pkg = cv::gapi::kernels<J::Foo, S::Baz>();
  169. // Directly instantiate G-API graph compiler and run partial compilation
  170. cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
  171. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  172. compiler.runPasses(*graph);
  173. // Inspect the graph and verify the islands configuration
  174. cv::gimpl::GModel::ConstGraph gm(*graph);
  175. auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
  176. auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
  177. auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out0);
  178. auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out1);
  179. EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
  180. auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
  181. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  182. auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
  183. auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
  184. EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp_nh));
  185. EXPECT_EQ(2u, static_cast<std::size_t>(isl_nh->outNodes().size()));
  186. EXPECT_EQ(7u, static_cast<std::size_t>(gm.nodes().size()));
  187. EXPECT_EQ(6u, static_cast<std::size_t>(gim.nodes().size()));
  188. }
  189. TEST(IslandFusion, LoopBetweenDifferentBackends)
  190. {
  191. // Define a computation:
  192. //
  193. //
  194. // .............................
  195. // (in) -> :J::Baz -> (tmp0) -> J::Quux: -> (out0)
  196. // | :............|..........^....
  197. // | ........ | | ........
  198. // `---->:S::Foo: `----------|-------->:S::Qux:-> (out1)
  199. // :....|.: | :....^.:
  200. // | | |
  201. // `-------------- (tmp1) -----------`
  202. // Kernels S::Foo and S::Qux cannot merge, because there will be a cycle between islands
  203. namespace J = Jupiter;
  204. namespace S = Saturn;
  205. cv::GScalar tmp0;
  206. cv::GMat in, tmp1, out0, out1;
  207. tmp0 = I::Baz::on(in);
  208. tmp1 = I::Foo::on(in);
  209. out1 = I::Qux::on(tmp1, tmp0);
  210. out0 = I::Quux::on(tmp0, tmp1);
  211. cv::GComputation cc(cv::GIn(in), cv::GOut(out1, out0));
  212. // Prepare compilation parameters manually
  213. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  214. const auto pkg = cv::gapi::kernels<J::Baz, J::Quux, S::Foo, S::Qux>();
  215. // Directly instantiate G-API graph compiler and run partial compilation
  216. cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
  217. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  218. compiler.runPasses(*graph);
  219. cv::gimpl::GModel::ConstGraph gm(*graph);
  220. auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
  221. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  222. auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
  223. auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
  224. auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp1);
  225. auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out0);
  226. auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out1);
  227. EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
  228. EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>());
  229. EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>());
  230. // The node does not belong to the island so as not to form a cycle
  231. EXPECT_FALSE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
  232. EXPECT_TRUE(gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
  233. // There should be three islands in the GIslandModel
  234. const auto is_island = [&](ade::NodeHandle nh) {
  235. return (cv::gimpl::NodeKind::ISLAND
  236. == gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
  237. };
  238. const std::size_t num_isl = std::count_if(gim.nodes().begin(),
  239. gim.nodes().end(),
  240. is_island);
  241. EXPECT_EQ(3u, num_isl);
  242. }
  243. TEST(IslandsFusion, PartionOverlapUserIsland)
  244. {
  245. // Define a computation:
  246. //
  247. // internal isl isl0
  248. // ........ ........
  249. // (in0) -> :J::Foo:--> (tmp) ->:S::Bar: --> (out)
  250. // :......: :......:
  251. // ^
  252. // |
  253. // (in1) --------------------------`
  254. // Check that internal islands doesn't overlap user island
  255. namespace J = Jupiter;
  256. namespace S = Saturn;
  257. GMat in[2];
  258. GMat tmp = I::Foo::on(in[0]);
  259. GMat out = I::Bar::on(tmp, in[1]);
  260. cv::gapi::island("isl0", cv::GIn(tmp, in[1]), cv::GOut(out));
  261. cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
  262. // Prepare compilation parameters manually
  263. cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)}),
  264. GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)})};
  265. const auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
  266. // Directly instantiate G-API graph compiler and run partial compilation
  267. cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
  268. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  269. compiler.runPasses(*graph);
  270. cv::gimpl::GModel::ConstGraph gm(*graph);
  271. auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
  272. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  273. auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
  274. auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
  275. auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
  276. auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
  277. auto foo_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
  278. auto foo_obj = gim.metadata(foo_nh).get<cv::gimpl::FusedIsland>().object;
  279. auto bar_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
  280. auto bar_obj = gim.metadata(bar_nh).get<cv::gimpl::FusedIsland>().object;
  281. EXPECT_FALSE(gm.metadata(in0_nh ).contains<cv::gimpl::Island>());
  282. EXPECT_FALSE(gm.metadata(in1_nh ).contains<cv::gimpl::Island>());
  283. EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
  284. EXPECT_FALSE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
  285. EXPECT_FALSE(foo_obj->is_user_specified());
  286. EXPECT_TRUE(bar_obj->is_user_specified());
  287. }
  288. TEST(IslandsFusion, DISABLED_IslandContainsDifferentBackends)
  289. {
  290. // Define a computation:
  291. //
  292. // isl0
  293. // ............................
  294. // (in0) -> :J::Foo:--> (tmp) -> S::Bar: --> (out)
  295. // :..........................:
  296. // ^
  297. // |
  298. // (in1) --------------------------`
  299. // Try create island contains different backends
  300. namespace J = Jupiter;
  301. namespace S = Saturn;
  302. GMat in[2];
  303. GMat tmp = I::Foo::on(in[0]);
  304. GMat out = I::Bar::on(tmp, in[1]);
  305. cv::gapi::island("isl0", cv::GIn(in[0], in[1]), cv::GOut(out));
  306. cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
  307. // Prepare compilation parameters manually
  308. cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)}),
  309. GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)})};
  310. const auto pkg = cv::gapi::kernels<J::Foo, S::Bar>();
  311. // Directly instantiate G-API graph compiler and run partial compilation
  312. cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
  313. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  314. EXPECT_ANY_THROW(compiler.runPasses(*graph));
  315. }
  316. TEST(IslandFusion, WithLoop)
  317. {
  318. namespace J = Jupiter; // see mock_kernels.cpp
  319. // Define a computation:
  320. //
  321. // (in) -> J::Foo --> (tmp0) -> J::Foo --> (tmp1) -> J::Qux -> (out)
  322. // : ^
  323. // '--> J::Baz --> (scl0) --'
  324. //
  325. // The whole thing should be merged to a single island
  326. // There's a cycle warning if Foo/Foo/Qux are merged first
  327. // Then this island both produces data for Baz and consumes data
  328. // from Baz. This is a cycle and it should be avoided by the merging code.
  329. //
  330. cv::GMat in;
  331. cv::GMat tmp0 = I::Foo::on(in);
  332. cv::GMat tmp1 = I::Foo::on(tmp0);
  333. cv::GScalar scl0 = I::Baz::on(tmp0);
  334. cv::GMat out = I::Qux::on(tmp1, scl0);
  335. cv::GComputation cc(in, out);
  336. // Prepare compilation parameters manually
  337. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  338. const auto pkg = cv::gapi::kernels<J::Foo, J::Baz, J::Qux>();
  339. // Directly instantiate G-API graph compiler and run partial compilation
  340. cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
  341. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  342. compiler.runPasses(*graph);
  343. // Inspect the graph and verify the islands configuration
  344. cv::gimpl::GModel::ConstGraph gm(*graph);
  345. auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
  346. auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
  347. auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp1);
  348. auto scl0_nh = cv::gimpl::GModel::dataNodeOf(gm, scl0);
  349. auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
  350. // in/out mats shouldn't be assigned to any Island
  351. EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
  352. EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
  353. // tmp0/tmp1/scl should be assigned to island
  354. EXPECT_TRUE(gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
  355. EXPECT_TRUE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
  356. EXPECT_TRUE(gm.metadata(scl0_nh).contains<cv::gimpl::Island>());
  357. // Check that there's a single island object and it contains all
  358. // that data object handles
  359. cv::gimpl::GModel::ConstGraph cg(*graph);
  360. auto isl_model = cg.metadata().get<cv::gimpl::IslandModel>().model;
  361. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  362. const auto is_island = [&](ade::NodeHandle nh) {
  363. return (cv::gimpl::NodeKind::ISLAND
  364. == gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
  365. };
  366. const std::size_t num_isl = std::count_if(gim.nodes().begin(),
  367. gim.nodes().end(),
  368. is_island);
  369. EXPECT_EQ(1u, num_isl);
  370. auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
  371. auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
  372. EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp0_nh));
  373. EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp1_nh));
  374. EXPECT_TRUE(ade::util::contains(isl_obj->contents(), scl0_nh));
  375. }
  376. TEST(IslandFusion, Regression_ShouldFuseAll)
  377. {
  378. // Initially the merge procedure didn't work as expected and
  379. // stopped fusion even if it could be continued (e.g. full
  380. // GModel graph could be fused into a single GIsland node).
  381. // Example of this is custom RGB 2 YUV pipeline as shown below:
  382. cv::GMat r, g, b;
  383. cv::GMat y = 0.299f*r + 0.587f*g + 0.114f*b;
  384. cv::GMat u = 0.492f*(b - y);
  385. cv::GMat v = 0.877f*(r - y);
  386. cv::GComputation customCvt({r, g, b}, {y, u, v});
  387. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  388. // Directly instantiate G-API graph compiler and run partial compilation
  389. cv::gimpl::GCompiler compiler(customCvt, {in_meta,in_meta,in_meta}, cv::compile_args());
  390. cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
  391. compiler.runPasses(*graph);
  392. cv::gimpl::GModel::ConstGraph cg(*graph);
  393. auto isl_model = cg.metadata().get<cv::gimpl::IslandModel>().model;
  394. cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
  395. std::vector<ade::NodeHandle> data_nhs;
  396. std::vector<ade::NodeHandle> isl_nhs;
  397. for (auto &&nh : gim.nodes())
  398. {
  399. if (gim.metadata(nh).contains<cv::gimpl::FusedIsland>())
  400. isl_nhs.push_back(std::move(nh));
  401. else if (gim.metadata(nh).contains<cv::gimpl::DataSlot>())
  402. data_nhs.push_back(std::move(nh));
  403. else FAIL() << "GIslandModel node with unexpected metadata type";
  404. }
  405. EXPECT_EQ(6u, data_nhs.size()); // 3 input nodes + 3 output nodes
  406. EXPECT_EQ(1u, isl_nhs.size()); // 1 island
  407. }
  408. TEST(IslandFusion, Test_Desync_NoFuse)
  409. {
  410. cv::GMat in;
  411. cv::GMat tmp1 = in*0.5f;
  412. cv::GMat tmp2 = tmp1 + in;
  413. cv::GMat tmp3 = cv::gapi::streaming::desync(tmp1);
  414. cv::GMat tmp4 = tmp3*0.1f;
  415. const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
  416. cv::GComputation comp(cv::GIn(in), cv::GOut(tmp2, tmp4));
  417. //////////////////////////////////////////////////////////////////
  418. // Compile the graph in "regular" mode, it should produce a single island
  419. // Note: with copy moved to a separate backend there is always 3 islands in this test
  420. {
  421. using namespace cv::gimpl;
  422. GCompiler compiler(comp, {in_meta}, cv::compile_args());
  423. GCompiler::GPtr graph = compiler.generateGraph();
  424. compiler.runPasses(*graph);
  425. auto isl_model = GModel::ConstGraph(*graph).metadata()
  426. .get<IslandModel>().model;
  427. GIslandModel::ConstGraph gim(*isl_model);
  428. const auto is_island = [&](ade::NodeHandle nh) {
  429. return (NodeKind::ISLAND == gim.metadata(nh).get<NodeKind>().k);
  430. };
  431. const auto num_isl = std::count_if(gim.nodes().begin(),
  432. gim.nodes().end(),
  433. is_island);
  434. EXPECT_EQ(3, num_isl);
  435. }
  436. //////////////////////////////////////////////////////////////////
  437. // Now compile the graph in the streaming mode.
  438. // It has to produce two islands
  439. // Note: with copy moved to a separate backend there is always 3 islands in this test
  440. {
  441. using namespace cv::gimpl;
  442. GCompiler compiler(comp, {in_meta}, cv::compile_args());
  443. GCompiler::GPtr graph = compiler.generateGraph();
  444. GModel::Graph(*graph).metadata().set(Streaming{});
  445. compiler.runPasses(*graph);
  446. auto isl_model = GModel::ConstGraph(*graph).metadata()
  447. .get<IslandModel>().model;
  448. GIslandModel::ConstGraph gim(*isl_model);
  449. const auto is_island = [&](ade::NodeHandle nh) {
  450. return (NodeKind::ISLAND == gim.metadata(nh).get<NodeKind>().k);
  451. };
  452. const auto num_isl = std::count_if(gim.nodes().begin(),
  453. gim.nodes().end(),
  454. is_island);
  455. EXPECT_EQ(3, num_isl);
  456. }
  457. }
  458. // Fixme: add more tests on mixed (hetero) graphs
  459. // ADE-222, ADE-223
  460. // FIXME: add test on combination of user-specified island
  461. // which should be heterogeneous (based on kernel availability)
  462. // but as we don't support this, compilation should fail
  463. // FIXME: add tests on automatic inferred islands which are
  464. // connected via 1) gmat 2) gscalar 3) garray,
  465. // check the case with executor
  466. // check the case when this 1/2/3 interim object is also gcomputation output
  467. } // namespace opencv_test