151c0b2f7Stbbdev /*
2*b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev
451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev you may not use this file except in compliance with the License.
651c0b2f7Stbbdev You may obtain a copy of the License at
751c0b2f7Stbbdev
851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev
1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev See the License for the specific language governing permissions and
1451c0b2f7Stbbdev limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev
17*b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18*b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19*b15aabb3Stbbdev #endif
20*b15aabb3Stbbdev
2151c0b2f7Stbbdev #include "common/config.h"
2251c0b2f7Stbbdev
2351c0b2f7Stbbdev #include "tbb/flow_graph.h"
2451c0b2f7Stbbdev
2551c0b2f7Stbbdev #include "common/test.h"
2651c0b2f7Stbbdev #include "common/utils.h"
2751c0b2f7Stbbdev #include "common/graph_utils.h"
2851c0b2f7Stbbdev #include "common/spin_barrier.h"
2951c0b2f7Stbbdev
3051c0b2f7Stbbdev
3151c0b2f7Stbbdev //! \file test_flow_graph.cpp
3251c0b2f7Stbbdev //! \brief Test for [flow_graph.continue_msg flow_graph.graph_node flow_graph.input_port flow_graph.output_port flow_graph.join_node flow_graph.split_node flow_graph.limiter_node flow_graph.write_once_node flow_graph.overwrite_node flow_graph.make_edge flow_graph.graph flow_graph.buffer_node flow_graph.function_node flow_graph.multifunction_node flow_graph.continue_node flow_graph.input_node] specification
3351c0b2f7Stbbdev
3451c0b2f7Stbbdev const int T = 4;
3551c0b2f7Stbbdev const int W = 4;
3651c0b2f7Stbbdev
3751c0b2f7Stbbdev struct decrement_wait : utils::NoAssign {
3851c0b2f7Stbbdev
3951c0b2f7Stbbdev tbb::flow::graph * const my_graph;
4051c0b2f7Stbbdev bool * const my_done_flag;
4151c0b2f7Stbbdev
decrement_waitdecrement_wait4251c0b2f7Stbbdev decrement_wait( tbb::flow::graph &h, bool *done_flag ) : my_graph(&h), my_done_flag(done_flag) {}
4351c0b2f7Stbbdev
operator ()decrement_wait4451c0b2f7Stbbdev void operator()(int i) const {
4551c0b2f7Stbbdev utils::Sleep(10 * i);
4651c0b2f7Stbbdev
4751c0b2f7Stbbdev my_done_flag[i] = true;
4851c0b2f7Stbbdev my_graph->release_wait();
4951c0b2f7Stbbdev }
5051c0b2f7Stbbdev };
5151c0b2f7Stbbdev
test_wait_count()5251c0b2f7Stbbdev static void test_wait_count() {
5351c0b2f7Stbbdev tbb::flow::graph h;
5451c0b2f7Stbbdev for (int i = 0; i < T; ++i ) {
5551c0b2f7Stbbdev bool done_flag[W];
5651c0b2f7Stbbdev for (int j = 0; j < W; ++j ) {
5751c0b2f7Stbbdev for ( int w = 0; w < W; ++w ) done_flag[w] = false;
5851c0b2f7Stbbdev for ( int w = 0; w < j; ++w ) h.reserve_wait();
5951c0b2f7Stbbdev
6051c0b2f7Stbbdev utils::NativeParallelFor( j, decrement_wait(h, done_flag) );
6151c0b2f7Stbbdev h.wait_for_all();
6251c0b2f7Stbbdev for ( int w = 0; w < W; ++w ) {
6351c0b2f7Stbbdev if ( w < j ) CHECK_MESSAGE( done_flag[w] == true, "" );
6451c0b2f7Stbbdev else CHECK_MESSAGE( done_flag[w] == false, "" );
6551c0b2f7Stbbdev }
6651c0b2f7Stbbdev }
6751c0b2f7Stbbdev }
6851c0b2f7Stbbdev }
6951c0b2f7Stbbdev
7051c0b2f7Stbbdev // Encapsulate object we want to store in vector (because contained type must have
7151c0b2f7Stbbdev // copy constructor and assignment operator
7251c0b2f7Stbbdev class my_int_buffer {
7351c0b2f7Stbbdev tbb::flow::buffer_node<int> *b;
7451c0b2f7Stbbdev tbb::flow::graph& my_graph;
7551c0b2f7Stbbdev public:
my_int_buffer(tbb::flow::graph & g)7651c0b2f7Stbbdev my_int_buffer(tbb::flow::graph &g) : my_graph(g) { b = new tbb::flow::buffer_node<int>(my_graph); }
my_int_buffer(const my_int_buffer & other)7751c0b2f7Stbbdev my_int_buffer(const my_int_buffer& other) : my_graph(other.my_graph) {
7851c0b2f7Stbbdev b = new tbb::flow::buffer_node<int>(my_graph);
7951c0b2f7Stbbdev }
~my_int_buffer()8051c0b2f7Stbbdev ~my_int_buffer() { delete b; }
operator =(const my_int_buffer &)8151c0b2f7Stbbdev my_int_buffer& operator=(const my_int_buffer& /*other*/) {
8251c0b2f7Stbbdev return *this;
8351c0b2f7Stbbdev }
8451c0b2f7Stbbdev };
8551c0b2f7Stbbdev
8651c0b2f7Stbbdev // test the graph iterator, delete nodes from graph, test again
test_iterator()8751c0b2f7Stbbdev void test_iterator() {
8851c0b2f7Stbbdev tbb::flow::graph g;
8951c0b2f7Stbbdev my_int_buffer a_buffer(g);
9051c0b2f7Stbbdev my_int_buffer b_buffer(g);
9151c0b2f7Stbbdev my_int_buffer c_buffer(g);
9251c0b2f7Stbbdev my_int_buffer *d_buffer = new my_int_buffer(g);
9351c0b2f7Stbbdev my_int_buffer e_buffer(g);
9451c0b2f7Stbbdev std::vector< my_int_buffer > my_buffer_vector(10, c_buffer);
9551c0b2f7Stbbdev
9651c0b2f7Stbbdev int count = 0;
9751c0b2f7Stbbdev for (tbb::flow::graph::iterator it = g.begin(); it != g.end(); ++it) {
9851c0b2f7Stbbdev count++;
9951c0b2f7Stbbdev }
10051c0b2f7Stbbdev CHECK_MESSAGE( (count==15), "error in iterator count");
10151c0b2f7Stbbdev
10251c0b2f7Stbbdev delete d_buffer;
10351c0b2f7Stbbdev
10451c0b2f7Stbbdev count = 0;
10551c0b2f7Stbbdev for (tbb::flow::graph::iterator it = g.begin(); it != g.end(); ++it) {
10651c0b2f7Stbbdev count++;
10751c0b2f7Stbbdev }
10851c0b2f7Stbbdev CHECK_MESSAGE( (count==14), "error in iterator count");
10951c0b2f7Stbbdev
11051c0b2f7Stbbdev my_buffer_vector.clear();
11151c0b2f7Stbbdev
11251c0b2f7Stbbdev count = 0;
11351c0b2f7Stbbdev for (tbb::flow::graph::iterator it = g.begin(); it != g.end(); ++it) {
11451c0b2f7Stbbdev count++;
11551c0b2f7Stbbdev }
11651c0b2f7Stbbdev CHECK_MESSAGE( (count==4), "error in iterator count");
11751c0b2f7Stbbdev }
11851c0b2f7Stbbdev
11951c0b2f7Stbbdev class AddRemoveBody : utils::NoAssign {
12051c0b2f7Stbbdev tbb::flow::graph& g;
12151c0b2f7Stbbdev int nThreads;
12251c0b2f7Stbbdev utils::SpinBarrier &barrier;
12351c0b2f7Stbbdev public:
AddRemoveBody(int nthr,utils::SpinBarrier & barrier_,tbb::flow::graph & _g)12451c0b2f7Stbbdev AddRemoveBody(int nthr, utils::SpinBarrier &barrier_, tbb::flow::graph& _g) :
12551c0b2f7Stbbdev g(_g), nThreads(nthr), barrier(barrier_)
12651c0b2f7Stbbdev {}
operator ()(const int) const12751c0b2f7Stbbdev void operator()(const int /*threadID*/) const {
12851c0b2f7Stbbdev my_int_buffer b(g);
12951c0b2f7Stbbdev {
13051c0b2f7Stbbdev std::vector<my_int_buffer> my_buffer_vector(100, b);
13151c0b2f7Stbbdev barrier.wait(); // wait until all nodes are created
13251c0b2f7Stbbdev // now test that the proper number of nodes were created
13351c0b2f7Stbbdev int count = 0;
13451c0b2f7Stbbdev for (tbb::flow::graph::iterator it = g.begin(); it != g.end(); ++it) {
13551c0b2f7Stbbdev count++;
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev CHECK_MESSAGE( (count==101*nThreads), "error in iterator count");
13851c0b2f7Stbbdev barrier.wait(); // wait until all threads are done counting
13951c0b2f7Stbbdev } // all nodes but for the initial node on this thread are deleted
14051c0b2f7Stbbdev barrier.wait(); // wait until all threads have deleted all nodes in their vectors
14151c0b2f7Stbbdev // now test that all the nodes were deleted except for the initial node
14251c0b2f7Stbbdev int count = 0;
14351c0b2f7Stbbdev for (tbb::flow::graph::iterator it = g.begin(); it != g.end(); ++it) {
14451c0b2f7Stbbdev count++;
14551c0b2f7Stbbdev }
14651c0b2f7Stbbdev CHECK_MESSAGE( (count==nThreads), "error in iterator count");
14751c0b2f7Stbbdev barrier.wait(); // wait until all threads are done counting
14851c0b2f7Stbbdev } // initial node gets deleted
14951c0b2f7Stbbdev };
15051c0b2f7Stbbdev
test_parallel(int nThreads)15151c0b2f7Stbbdev void test_parallel(int nThreads) {
15251c0b2f7Stbbdev tbb::flow::graph g;
15351c0b2f7Stbbdev utils::SpinBarrier barrier(nThreads);
15451c0b2f7Stbbdev AddRemoveBody body(nThreads, barrier, g);
15551c0b2f7Stbbdev NativeParallelFor(nThreads, body);
15651c0b2f7Stbbdev }
15751c0b2f7Stbbdev
15851c0b2f7Stbbdev /*
15951c0b2f7Stbbdev * Functors for graph arena spawn tests
16051c0b2f7Stbbdev */
16151c0b2f7Stbbdev
check_arena(tbb::task_arena * midway_arena)16251c0b2f7Stbbdev inline void check_arena(tbb::task_arena* midway_arena) {
16351c0b2f7Stbbdev CHECK_MESSAGE(midway_arena->max_concurrency() == 2, "");
16451c0b2f7Stbbdev CHECK_MESSAGE(tbb::this_task_arena::max_concurrency() == 1, "");
16551c0b2f7Stbbdev }
16651c0b2f7Stbbdev
16751c0b2f7Stbbdev struct run_functor {
16851c0b2f7Stbbdev tbb::task_arena* midway_arena;
16951c0b2f7Stbbdev int return_value;
run_functorrun_functor17051c0b2f7Stbbdev run_functor(tbb::task_arena* a) : midway_arena(a), return_value(1) {}
operator ()run_functor17151c0b2f7Stbbdev int operator()() {
17251c0b2f7Stbbdev check_arena(midway_arena);
17351c0b2f7Stbbdev return return_value;
17451c0b2f7Stbbdev }
17551c0b2f7Stbbdev };
17651c0b2f7Stbbdev
17751c0b2f7Stbbdev template < typename T >
17851c0b2f7Stbbdev struct function_body {
17951c0b2f7Stbbdev tbb::task_arena* midway_arena;
function_bodyfunction_body18051c0b2f7Stbbdev function_body(tbb::task_arena* a) : midway_arena(a) {}
operator ()function_body18151c0b2f7Stbbdev tbb::flow::continue_msg operator()(const T& /*arg*/) {
18251c0b2f7Stbbdev check_arena(midway_arena);
18351c0b2f7Stbbdev return tbb::flow::continue_msg();
18451c0b2f7Stbbdev }
18551c0b2f7Stbbdev };
18651c0b2f7Stbbdev
18751c0b2f7Stbbdev typedef tbb::flow::multifunction_node< int, std::tuple< int > > mf_node;
18851c0b2f7Stbbdev
18951c0b2f7Stbbdev struct multifunction_body {
19051c0b2f7Stbbdev tbb::task_arena* midway_arena;
multifunction_bodymultifunction_body19151c0b2f7Stbbdev multifunction_body(tbb::task_arena* a) : midway_arena(a) {}
operator ()multifunction_body19251c0b2f7Stbbdev void operator()(const int& /*arg*/, mf_node::output_ports_type& /*outports*/) {
19351c0b2f7Stbbdev check_arena(midway_arena);
19451c0b2f7Stbbdev }
19551c0b2f7Stbbdev };
19651c0b2f7Stbbdev
19751c0b2f7Stbbdev struct input_body {
19851c0b2f7Stbbdev tbb::task_arena* midway_arena;
19951c0b2f7Stbbdev int counter;
input_bodyinput_body20051c0b2f7Stbbdev input_body(tbb::task_arena* a) : midway_arena(a), counter(0) {}
operator ()input_body20151c0b2f7Stbbdev int operator()(tbb::flow_control &fc) {
20251c0b2f7Stbbdev check_arena(midway_arena);
20351c0b2f7Stbbdev if (counter++ >= 1) {
20451c0b2f7Stbbdev fc.stop();
20551c0b2f7Stbbdev }
20651c0b2f7Stbbdev return int();
20751c0b2f7Stbbdev }
20851c0b2f7Stbbdev };
20951c0b2f7Stbbdev
21051c0b2f7Stbbdev struct nodes_test_functor : utils::NoAssign {
21151c0b2f7Stbbdev tbb::task_arena* midway_arena;
21251c0b2f7Stbbdev tbb::flow::graph& my_graph;
21351c0b2f7Stbbdev
nodes_test_functornodes_test_functor21451c0b2f7Stbbdev nodes_test_functor(tbb::task_arena* a, tbb::flow::graph& g) : midway_arena(a), my_graph(g) {}
operator ()nodes_test_functor21551c0b2f7Stbbdev void operator()() const {
21651c0b2f7Stbbdev
21751c0b2f7Stbbdev // Define test nodes
21851c0b2f7Stbbdev // Continue, function, source nodes
21951c0b2f7Stbbdev tbb::flow::continue_node< tbb::flow::continue_msg > c_n(my_graph, function_body<tbb::flow::continue_msg>(midway_arena));
22051c0b2f7Stbbdev tbb::flow::function_node< int > f_n(my_graph, tbb::flow::unlimited, function_body<int>(midway_arena));
22151c0b2f7Stbbdev tbb::flow::input_node< int > s_n(my_graph, input_body(midway_arena));
22251c0b2f7Stbbdev
22351c0b2f7Stbbdev // Multifunction node
22451c0b2f7Stbbdev mf_node m_n(my_graph, tbb::flow::unlimited, multifunction_body(midway_arena));
22551c0b2f7Stbbdev
22651c0b2f7Stbbdev // Join node
22751c0b2f7Stbbdev tbb::flow::function_node< std::tuple< int, int > > join_f_n(
22851c0b2f7Stbbdev my_graph, tbb::flow::unlimited, function_body< std::tuple< int, int > >(midway_arena)
22951c0b2f7Stbbdev );
23051c0b2f7Stbbdev tbb::flow::join_node< std::tuple< int, int > > j_n(my_graph);
23151c0b2f7Stbbdev make_edge(j_n, join_f_n);
23251c0b2f7Stbbdev
23351c0b2f7Stbbdev // Split node
23451c0b2f7Stbbdev tbb::flow::function_node< int > split_f_n1 = f_n;
23551c0b2f7Stbbdev tbb::flow::function_node< int > split_f_n2 = f_n;
23651c0b2f7Stbbdev tbb::flow::split_node< std::tuple< int, int > > sp_n(my_graph);
23751c0b2f7Stbbdev make_edge(tbb::flow::output_port<0>(sp_n), split_f_n1);
23851c0b2f7Stbbdev make_edge(tbb::flow::output_port<1>(sp_n), split_f_n2);
23951c0b2f7Stbbdev
24051c0b2f7Stbbdev // Overwrite node
24151c0b2f7Stbbdev tbb::flow::function_node< int > ow_f_n = f_n;
24251c0b2f7Stbbdev tbb::flow::overwrite_node< int > ow_n(my_graph);
24351c0b2f7Stbbdev make_edge(ow_n, ow_f_n);
24451c0b2f7Stbbdev
24551c0b2f7Stbbdev // Write once node
24651c0b2f7Stbbdev tbb::flow::function_node< int > w_f_n = f_n;
24751c0b2f7Stbbdev tbb::flow::write_once_node< int > w_n(my_graph);
24851c0b2f7Stbbdev make_edge(w_n, w_f_n);
24951c0b2f7Stbbdev
25051c0b2f7Stbbdev // Buffer node
25151c0b2f7Stbbdev tbb::flow::function_node< int > buf_f_n = f_n;
25251c0b2f7Stbbdev tbb::flow::buffer_node< int > buf_n(my_graph);
25351c0b2f7Stbbdev make_edge(w_n, buf_f_n);
25451c0b2f7Stbbdev
25551c0b2f7Stbbdev // Limiter node
25651c0b2f7Stbbdev tbb::flow::function_node< int > l_f_n = f_n;
25751c0b2f7Stbbdev tbb::flow::limiter_node< int > l_n(my_graph, 1);
25851c0b2f7Stbbdev make_edge(l_n, l_f_n);
25951c0b2f7Stbbdev
26051c0b2f7Stbbdev // Execute nodes
26151c0b2f7Stbbdev c_n.try_put( tbb::flow::continue_msg() );
26251c0b2f7Stbbdev f_n.try_put(1);
26351c0b2f7Stbbdev m_n.try_put(1);
26451c0b2f7Stbbdev s_n.activate();
26551c0b2f7Stbbdev
26651c0b2f7Stbbdev tbb::flow::input_port<0>(j_n).try_put(1);
26751c0b2f7Stbbdev tbb::flow::input_port<1>(j_n).try_put(1);
26851c0b2f7Stbbdev
26951c0b2f7Stbbdev std::tuple< int, int > sp_tuple(1, 1);
27051c0b2f7Stbbdev sp_n.try_put(sp_tuple);
27151c0b2f7Stbbdev
27251c0b2f7Stbbdev ow_n.try_put(1);
27351c0b2f7Stbbdev w_n.try_put(1);
27451c0b2f7Stbbdev buf_n.try_put(1);
27551c0b2f7Stbbdev l_n.try_put(1);
27651c0b2f7Stbbdev
27751c0b2f7Stbbdev my_graph.wait_for_all();
27851c0b2f7Stbbdev }
27951c0b2f7Stbbdev };
28051c0b2f7Stbbdev
test_graph_arena()28151c0b2f7Stbbdev void test_graph_arena() {
282*b15aabb3Stbbdev // There is only one thread for execution (external thread).
28351c0b2f7Stbbdev // So, if graph's tasks get spawned in different arena
284*b15aabb3Stbbdev // external thread won't be able to find them in its own arena.
28551c0b2f7Stbbdev // In this case test should hang.
28651c0b2f7Stbbdev tbb::task_arena arena(1);
28751c0b2f7Stbbdev arena.execute(
28851c0b2f7Stbbdev [&]() {
28951c0b2f7Stbbdev tbb::flow::graph g;
29051c0b2f7Stbbdev tbb::task_arena midway_arena;
29151c0b2f7Stbbdev midway_arena.initialize(2);
29251c0b2f7Stbbdev midway_arena.execute(nodes_test_functor(&midway_arena, g));
29351c0b2f7Stbbdev
29451c0b2f7Stbbdev }
29551c0b2f7Stbbdev );
29651c0b2f7Stbbdev }
29751c0b2f7Stbbdev
29851c0b2f7Stbbdev //! Test wait counts
29951c0b2f7Stbbdev //! \brief error_guessing
30051c0b2f7Stbbdev TEST_CASE("Test wait_count"){
30151c0b2f7Stbbdev for(unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) {
30251c0b2f7Stbbdev tbb::task_arena arena(p);
30351c0b2f7Stbbdev arena.execute(
__anon515993d30202() 30451c0b2f7Stbbdev [&]() {
30551c0b2f7Stbbdev test_wait_count();
30651c0b2f7Stbbdev }
30751c0b2f7Stbbdev );
30851c0b2f7Stbbdev }
30951c0b2f7Stbbdev }
31051c0b2f7Stbbdev
31151c0b2f7Stbbdev //! Test graph iterators
31251c0b2f7Stbbdev //! \brief interface
31351c0b2f7Stbbdev TEST_CASE("Test graph::iterator"){
31451c0b2f7Stbbdev for(unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) {
31551c0b2f7Stbbdev tbb::task_arena arena(p);
31651c0b2f7Stbbdev arena.execute(
__anon515993d30302() 31751c0b2f7Stbbdev [&]() {
31851c0b2f7Stbbdev test_iterator();
31951c0b2f7Stbbdev }
32051c0b2f7Stbbdev );
32151c0b2f7Stbbdev }
32251c0b2f7Stbbdev }
32351c0b2f7Stbbdev
32451c0b2f7Stbbdev //! Test parallel for body
32551c0b2f7Stbbdev //! \brief \ref error_guessing
32651c0b2f7Stbbdev TEST_CASE("Test parallel"){
32751c0b2f7Stbbdev for(unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) {
32851c0b2f7Stbbdev tbb::task_arena arena(p);
32951c0b2f7Stbbdev arena.execute(
__anon515993d30402() 33051c0b2f7Stbbdev [&]() {
33151c0b2f7Stbbdev test_parallel(p);
33251c0b2f7Stbbdev }
33351c0b2f7Stbbdev );
33451c0b2f7Stbbdev }
33551c0b2f7Stbbdev }
33651c0b2f7Stbbdev
33751c0b2f7Stbbdev //! Test separate arena isn't used
33851c0b2f7Stbbdev //! \brief \ref error_guessing
33951c0b2f7Stbbdev TEST_CASE("Test graph_arena"){
34051c0b2f7Stbbdev test_graph_arena();
34151c0b2f7Stbbdev }
34251c0b2f7Stbbdev
34351c0b2f7Stbbdev //! Graph iterator
34451c0b2f7Stbbdev //! \brief \ref error_guessing
34551c0b2f7Stbbdev TEST_CASE("graph iterator") {
34651c0b2f7Stbbdev using namespace tbb::flow;
34751c0b2f7Stbbdev
34851c0b2f7Stbbdev graph g;
34951c0b2f7Stbbdev
35051c0b2f7Stbbdev auto past_end = g.end();
35151c0b2f7Stbbdev ++past_end;
35251c0b2f7Stbbdev
__anon515993d30502(const continue_msg &)35351c0b2f7Stbbdev continue_node<int> n(g, [](const continue_msg &){return 1;});
35451c0b2f7Stbbdev
35551c0b2f7Stbbdev size_t item_count = 0;
35651c0b2f7Stbbdev
35751c0b2f7Stbbdev for(auto it = g.cbegin(); it != g.cend(); it++)
35851c0b2f7Stbbdev ++item_count;
35951c0b2f7Stbbdev CHECK_MESSAGE((item_count == 1), "Should find 1 item");
36051c0b2f7Stbbdev
36151c0b2f7Stbbdev item_count = 0;
36251c0b2f7Stbbdev auto jt(g.begin());
36351c0b2f7Stbbdev for(; jt != g.end(); jt++)
36451c0b2f7Stbbdev ++item_count;
36551c0b2f7Stbbdev CHECK_MESSAGE((item_count == 1), "Should find 1 item");
36651c0b2f7Stbbdev
36751c0b2f7Stbbdev graph g2;
__anon515993d30602(const continue_msg &)36851c0b2f7Stbbdev continue_node<int> n2(g, [](const continue_msg &){return 1;});
36951c0b2f7Stbbdev CHECK_MESSAGE((g.begin() != g2.begin()), "Different graphs should have different iterators");
37051c0b2f7Stbbdev }
371