151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2020-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 17b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER 18b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated 19b15aabb3Stbbdev #endif 2051c0b2f7Stbbdev 21*de0109beSIlya Mishin #define SEQUENCER_NODE 2251c0b2f7Stbbdev 2351c0b2f7Stbbdev #include "conformance_flowgraph.h" 2451c0b2f7Stbbdev 2551c0b2f7Stbbdev //! \file conformance_sequencer_node.cpp 2651c0b2f7Stbbdev //! \brief Test for [flow_graph.sequencer_node] specification 2751c0b2f7Stbbdev 2851c0b2f7Stbbdev 2951c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 30*de0109beSIlya Mishin template <typename Body> 31*de0109beSIlya Mishin void test_deduction_guides_common(Body body) { 32*de0109beSIlya Mishin using namespace tbb::flow; 33*de0109beSIlya Mishin graph g; 34*de0109beSIlya Mishin broadcast_node<int> br(g); 35*de0109beSIlya Mishin 36*de0109beSIlya Mishin sequencer_node s1(g, body); 37*de0109beSIlya Mishin static_assert(std::is_same_v<decltype(s1), sequencer_node<int>>); 38*de0109beSIlya Mishin 39*de0109beSIlya Mishin #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 40*de0109beSIlya Mishin sequencer_node s2(follows(br), body); 41*de0109beSIlya Mishin static_assert(std::is_same_v<decltype(s2), sequencer_node<int>>); 42*de0109beSIlya Mishin #endif 43*de0109beSIlya Mishin 44*de0109beSIlya Mishin sequencer_node s3(s1); 45*de0109beSIlya Mishin static_assert(std::is_same_v<decltype(s3), sequencer_node<int>>); 46*de0109beSIlya Mishin } 47*de0109beSIlya Mishin 48*de0109beSIlya Mishin std::size_t sequencer_body_f(const int&) { return 1; } 49*de0109beSIlya Mishin 5051c0b2f7Stbbdev void test_deduction_guides() { 51*de0109beSIlya Mishin test_deduction_guides_common([](const int&)->std::size_t { return 1; }); 52*de0109beSIlya Mishin test_deduction_guides_common([](const int&) mutable ->std::size_t { return 1; }); 53*de0109beSIlya Mishin test_deduction_guides_common(sequencer_body_f); 5451c0b2f7Stbbdev } 5551c0b2f7Stbbdev #endif 5651c0b2f7Stbbdev 57*de0109beSIlya Mishin //! Test deduction guides 58*de0109beSIlya Mishin //! \brief \ref interface \ref requirement 59*de0109beSIlya Mishin TEST_CASE("Deduction guides"){ 60*de0109beSIlya Mishin #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 61*de0109beSIlya Mishin test_deduction_guides(); 62*de0109beSIlya Mishin #endif 6351c0b2f7Stbbdev } 6451c0b2f7Stbbdev 65*de0109beSIlya Mishin //! Test sequencer_node single_push 66*de0109beSIlya Mishin //! \brief \ref requirement 67*de0109beSIlya Mishin TEST_CASE("sequencer_node single_push"){ 68*de0109beSIlya Mishin conformance::sequencer_functor<int> sequencer; 69*de0109beSIlya Mishin conformance::test_forwarding_single_push<oneapi::tbb::flow::sequencer_node<int>>(sequencer); 70*de0109beSIlya Mishin } 71*de0109beSIlya Mishin 72*de0109beSIlya Mishin //! Test function_node buffering 73*de0109beSIlya Mishin //! \brief \ref requirement 74*de0109beSIlya Mishin TEST_CASE("sequencer_node buffering"){ 75*de0109beSIlya Mishin conformance::sequencer_functor<int> sequencer; 76*de0109beSIlya Mishin conformance::test_buffering<oneapi::tbb::flow::sequencer_node<int>, int>(sequencer); 77*de0109beSIlya Mishin } 78*de0109beSIlya Mishin 79*de0109beSIlya Mishin //! Constructs an empty sequencer_node that belongs to the same graph g as src. 80*de0109beSIlya Mishin //! Any intermediate state of src, including its links to predecessors and successors, is not copied. 81*de0109beSIlya Mishin //! \brief \ref requirement 82*de0109beSIlya Mishin TEST_CASE("sequencer_node copy constructor"){ 83*de0109beSIlya Mishin conformance::sequencer_functor<int> sequencer; 84*de0109beSIlya Mishin conformance::test_copy_ctor_for_buffering_nodes<oneapi::tbb::flow::sequencer_node<int>>(sequencer); 85*de0109beSIlya Mishin } 86*de0109beSIlya Mishin 87*de0109beSIlya Mishin //! Test inheritance relations 88*de0109beSIlya Mishin //! \brief \ref interface 89*de0109beSIlya Mishin TEST_CASE("sequencer_node superclasses"){ 90*de0109beSIlya Mishin conformance::test_inheritance<oneapi::tbb::flow::sequencer_node<int>, int, int>(); 91*de0109beSIlya Mishin conformance::test_inheritance<oneapi::tbb::flow::sequencer_node<void*>, void*, void*>(); 92*de0109beSIlya Mishin } 93*de0109beSIlya Mishin 94*de0109beSIlya Mishin //! Test the sequencer_node rejects duplicate sequencer numbers 95*de0109beSIlya Mishin //! \brief \ref interface 96*de0109beSIlya Mishin TEST_CASE("sequencer_node rejects duplicate"){ 9749e08aacStbbdev oneapi::tbb::flow::graph g; 98*de0109beSIlya Mishin conformance::sequencer_functor<int> sequencer; 99*de0109beSIlya Mishin 100*de0109beSIlya Mishin oneapi::tbb::flow::sequencer_node<int> node(g, sequencer); 101*de0109beSIlya Mishin 102*de0109beSIlya Mishin node.try_put(1); 103*de0109beSIlya Mishin 104*de0109beSIlya Mishin CHECK_MESSAGE((node.try_put(1) == false), "sequencer_node must rejects duplicate sequencer numbers"); 105*de0109beSIlya Mishin g.wait_for_all(); 106*de0109beSIlya Mishin } 107*de0109beSIlya Mishin 108*de0109beSIlya Mishin //! Test queue_node node `try_put()` and `try_get()` 109*de0109beSIlya Mishin //! \brief \ref requirement 110*de0109beSIlya Mishin TEST_CASE("queue_node methods"){ 111*de0109beSIlya Mishin oneapi::tbb::flow::graph g; 112*de0109beSIlya Mishin conformance::sequencer_functor<int> sequencer; 11351c0b2f7Stbbdev 11449e08aacStbbdev oneapi::tbb::flow::sequencer_node<int> node(g, sequencer); 11551c0b2f7Stbbdev 11651c0b2f7Stbbdev node.try_put(1); 11751c0b2f7Stbbdev node.try_put(0); 11851c0b2f7Stbbdev node.try_put(1); 11951c0b2f7Stbbdev g.wait_for_all(); 12051c0b2f7Stbbdev 12151c0b2f7Stbbdev int tmp = -1; 12251c0b2f7Stbbdev CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed"); 12351c0b2f7Stbbdev CHECK_MESSAGE((tmp == 0), "Received value should be correct"); 12451c0b2f7Stbbdev 12551c0b2f7Stbbdev tmp = -1; 12651c0b2f7Stbbdev CHECK_MESSAGE((node.try_get(tmp) == true), "Getting from sequencer should succeed"); 12751c0b2f7Stbbdev CHECK_MESSAGE((tmp == 1), "Received value should be correct"); 12851c0b2f7Stbbdev 12951c0b2f7Stbbdev tmp = -1; 13051c0b2f7Stbbdev CHECK_MESSAGE((node.try_get(tmp) == false), "Getting from sequencer should not succeed"); 13151c0b2f7Stbbdev } 13251c0b2f7Stbbdev 133*de0109beSIlya Mishin //! The example demonstrates ordering capabilities of the sequencer_node. 134*de0109beSIlya Mishin //! While being processed in parallel, the data is passed to the successor node in the exact same order it was read. 13551c0b2f7Stbbdev //! \brief \ref requirement 136*de0109beSIlya Mishin TEST_CASE("sequencer_node ordering"){ 137*de0109beSIlya Mishin using namespace oneapi::tbb::flow; 138*de0109beSIlya Mishin using message = conformance::sequencer_functor<int>::seq_message; 139*de0109beSIlya Mishin graph g; 140*de0109beSIlya Mishin 141*de0109beSIlya Mishin // Due to parallelism the node can push messages to its successors in any order 142*de0109beSIlya Mishin function_node<message, message> process(g, unlimited, [] (message msg) { 143*de0109beSIlya Mishin msg.data++; 144*de0109beSIlya Mishin return msg; 145*de0109beSIlya Mishin }); 146*de0109beSIlya Mishin 147*de0109beSIlya Mishin sequencer_node<message> ordering(g, conformance::sequencer_functor<int>()); 148*de0109beSIlya Mishin 149*de0109beSIlya Mishin std::atomic<std::size_t> counter{0}; 150*de0109beSIlya Mishin function_node<message> writer(g, tbb::flow::serial, [&] (const message& msg) { 151*de0109beSIlya Mishin CHECK_MESSAGE((msg.id == counter++), "The data is passed to the successor node in the exact same order it was read"); 152*de0109beSIlya Mishin }); 153*de0109beSIlya Mishin 154*de0109beSIlya Mishin tbb::flow::make_edge(process, ordering); 155*de0109beSIlya Mishin tbb::flow::make_edge(ordering, writer); 156*de0109beSIlya Mishin 157*de0109beSIlya Mishin for (std::size_t i = 0; i < 100; ++i) { 158*de0109beSIlya Mishin message msg = {i, 0}; 159*de0109beSIlya Mishin process.try_put(msg); 16051c0b2f7Stbbdev } 16151c0b2f7Stbbdev 162*de0109beSIlya Mishin g.wait_for_all(); 16351c0b2f7Stbbdev } 164