diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/tests/rfnoc_graph_mock_nodes.hpp | 148 | ||||
-rw-r--r-- | host/tests/rfnoc_propprop_test.cpp | 112 |
2 files changed, 259 insertions, 1 deletions
diff --git a/host/tests/rfnoc_graph_mock_nodes.hpp b/host/tests/rfnoc_graph_mock_nodes.hpp index 63e542e40..bfa08bea6 100644 --- a/host/tests/rfnoc_graph_mock_nodes.hpp +++ b/host/tests/rfnoc_graph_mock_nodes.hpp @@ -428,4 +428,152 @@ private: }; size_t mock_terminator_t::counter = 0; +/*! Mock node with configurable number of input and output ports that have + * an edge property associated with each. The node can source actions with + * key 'action' from any of its edges. Incoming actions with key 'action' + * are stored in a (source port --> list of incoming actions) map. + */ +class mock_edge_node_t : public node_t +{ +public: + using received_actions_map_t = + std::unordered_map<res_source_info, std::vector<action_info::sptr>>; + + mock_edge_node_t(size_t input_ports, + size_t output_ports, + const std::string& name = "MOCK_EDGE_NODE") + : _input_ports(input_ports), _output_ports(output_ports), _name(name) + { + _in_props.reserve(_input_ports); + _out_props.reserve(_output_ports); + set_action_forwarding_policy(forwarding_policy_t::ONE_TO_ONE); + + for (size_t i = 0; i < _input_ports; i++) { + _in_props.emplace_back( + property_t<int>{"prop", 0, {res_source_info::INPUT_EDGE, i}}); + register_property(&_in_props.back()); + } + for (size_t i = 0; i < _output_ports; i++) { + _out_props.emplace_back( + property_t<int>{"prop", 0, {res_source_info::OUTPUT_EDGE, i}}); + register_property(&_out_props.back()); + } + + register_action_handler( + "action", [this](const res_source_info& src, action_info::sptr action) { + auto itr = _received_actions.find(src); + if (itr == _received_actions.end()) { + _received_actions.insert({src, {action}}); + } else { + itr->second.push_back(action); + } + }); + } + + template <typename T> + void set_edge_property( + const std::string& id, const T& val, const res_source_info& rsi) + { + node_t::set_property<T>(id, val, rsi); + } + + template <typename T> + T get_edge_property(const std::string& id, const res_source_info& rsi) + { + return node_t::get_property<T>(id, rsi); + } + + size_t get_num_input_ports() const + { + return _input_ports; + } + + size_t get_num_output_ports() const + { + return _output_ports; + } + + std::string get_unique_id() const + { + return _name; + } + + void post_input_edge_action(action_info::sptr action, size_t port) + { + UHD_ASSERT_THROW(port < _input_ports); + post_action({res_source_info::INPUT_EDGE, port}, action); + } + + void post_output_edge_action(action_info::sptr action, size_t port) + { + UHD_ASSERT_THROW(port < _output_ports); + post_action({res_source_info::OUTPUT_EDGE, port}, action); + } + + const received_actions_map_t& get_received_actions_map() const + { + return _received_actions; + } + + void clear_received_actions_map() + { + _received_actions.clear(); + } + +private: + size_t _input_ports; + size_t _output_ports; + std::string _name; + std::vector<property_t<int>> _in_props; + std::vector<property_t<int>> _out_props; + received_actions_map_t _received_actions; +}; + +/*! Do-nothing mock node used for testing property and action propagation + * between various edges with the USE_MAP forwarding strategy. + */ +class mock_routing_node_t : public node_t +{ +public: + mock_routing_node_t(size_t input_ports, size_t output_ports) + : _input_ports(input_ports), _output_ports(output_ports) + { + // By default, the node will drop incoming properties and actions. + // Call set_property_prop_map() or set_action_forwarding_map() to + // configure the node to use the provided map. + set_prop_forwarding_policy(forwarding_policy_t::DROP); + set_action_forwarding_policy(forwarding_policy_t::DROP); + } + + size_t get_num_input_ports() const + { + return _input_ports; + } + + size_t get_num_output_ports() const + { + return _output_ports; + } + + std::string get_unique_id() const + { + return "MOCK_ROUTING_NODE"; + } + + void set_prop_forwarding_map(const node_t::forwarding_map_t& fwd_map) + { + set_prop_forwarding_policy(forwarding_policy_t::USE_MAP); + node_t::set_prop_forwarding_map(fwd_map); + } + + void set_action_forwarding_map(const node_t::forwarding_map_t& fwd_map) + { + set_action_forwarding_policy(forwarding_policy_t::USE_MAP); + node_t::set_action_forwarding_map(fwd_map); + } + +private: + size_t _input_ports; + size_t _output_ports; +}; #endif /* INCLUDED_LIBUHD_TESTS_MOCK_NODES_HPP */ diff --git a/host/tests/rfnoc_propprop_test.cpp b/host/tests/rfnoc_propprop_test.cpp index 2b8cd635c..224783e22 100644 --- a/host/tests/rfnoc_propprop_test.cpp +++ b/host/tests/rfnoc_propprop_test.cpp @@ -156,7 +156,6 @@ public: property_t<double> _x4{"x4", 4.0, {res_source_info::USER}}; }; - // Do some sanity checks on the mock just so we don't get surprised later BOOST_AUTO_TEST_CASE(test_mock) { @@ -430,3 +429,114 @@ BOOST_AUTO_TEST_CASE(test_circular_deps) mock_circular_prop_node.set_property<double>("x1", 5.0, 0); BOOST_CHECK_EQUAL(mock_circular_prop_node.get_property<double>("x4"), 4 * 5.0); } + +BOOST_AUTO_TEST_CASE(test_propagation_map) +{ + // Set up the graph + node_accessor_t node_accessor{}; + uhd::rfnoc::detail::graph_t graph{}; + + constexpr size_t NUM_INPUTS = 8; + constexpr size_t NUM_OUTPUTS = 8; + + node_t::forwarding_map_t fwd_map = { + // input edges 0-3 --> output edges 3-0 + {{res_source_info::INPUT_EDGE, 0}, {{res_source_info::OUTPUT_EDGE, 3}}}, + {{res_source_info::INPUT_EDGE, 1}, {{res_source_info::OUTPUT_EDGE, 2}}}, + {{res_source_info::INPUT_EDGE, 2}, {{res_source_info::OUTPUT_EDGE, 1}}}, + {{res_source_info::INPUT_EDGE, 3}, {{res_source_info::OUTPUT_EDGE, 0}}}, + // input edge 4 --> output edges 4 and 5 + {{res_source_info::INPUT_EDGE, 4}, + {{res_source_info::OUTPUT_EDGE, 4}, {res_source_info::OUTPUT_EDGE, 5}}}, + // input edge 5 --> output edges 6 and 7 + {{res_source_info::INPUT_EDGE, 5}, + {{res_source_info::OUTPUT_EDGE, 6}, {res_source_info::OUTPUT_EDGE, 7}}}, + // input edge 6 no destination (i.e. drop) + {{res_source_info::INPUT_EDGE, 6}, {}} + // input edge 7 not in map (i.e. drop) + }; + + mock_edge_node_t input{0, NUM_INPUTS, "MOCK_EDGE_NODE<input>"}; + mock_routing_node_t middle{NUM_INPUTS, NUM_OUTPUTS}; + mock_edge_node_t output{NUM_OUTPUTS, 0, "MOCK_EDGE_NODE<output>"}; + + middle.set_prop_forwarding_map(fwd_map); + + // These init calls would normally be done by the framework + node_accessor.init_props(&input); + node_accessor.init_props(&middle); + node_accessor.init_props(&output); + + // Prime the output edge properties on the input block + for (size_t i = 0; i < NUM_INPUTS; i++) { + input.set_edge_property<int>("prop", 100 + i, {res_source_info::OUTPUT_EDGE, i}); + } + + using graph_edge_t = uhd::rfnoc::detail::graph_t::graph_edge_t; + + // Connect the nodes in the graph + for (size_t i = 0; i < NUM_INPUTS; i++) { + graph.connect(&input, &middle, {i, i, graph_edge_t::DYNAMIC, true}); + } + for (size_t i = 0; i < NUM_OUTPUTS; i++) { + graph.connect(&middle, &output, {i, i, graph_edge_t::DYNAMIC, true}); + } + UHD_LOG_INFO("TEST", "Now testing map-driven property propagation"); + graph.commit(); + + // Verify that the properties were propagated per the table + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 0}), 103); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 1}), 102); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 2}), 101); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 3}), 100); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 4}), 104); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 5}), 104); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 6}), 105); + BOOST_CHECK_EQUAL( + output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 7}), 105); +} + +BOOST_AUTO_TEST_CASE(test_propagation_map_exception_invalid_destination) +{ + // Set up the graph + node_accessor_t node_accessor{}; + uhd::rfnoc::detail::graph_t graph{}; + + // Create a map that will generate an exception at propagation time due + // to the mapping pointing to a non-existent port + node_t::forwarding_map_t no_port_fwd_map = { + // input edge 0 --> output edge 1 (output port does not exist) + {{res_source_info::INPUT_EDGE, 0}, {{res_source_info::OUTPUT_EDGE, 1}}}}; + + mock_edge_node_t generator{0, 1, "MOCK_EDGE_NODE<generator>"}; + mock_routing_node_t router{1, 1}; + mock_edge_node_t receiver{1, 0, "MOCK_EDGE_NODE<receiver>"}; + + router.set_prop_forwarding_map(no_port_fwd_map); + + // These init calls would normally be done by the framework + node_accessor.init_props(&generator); + node_accessor.init_props(&router); + node_accessor.init_props(&receiver); + + generator.set_edge_property<int>("prop", 100, {res_source_info::OUTPUT_EDGE, 0}); + + using graph_edge_t = uhd::rfnoc::detail::graph_t::graph_edge_t; + + // Connect the nodes in the graph + graph.connect(&generator, &router, {0, 0, graph_edge_t::DYNAMIC, true}); + graph.connect(&router, &receiver, {0, 0, graph_edge_t::DYNAMIC, true}); + + UHD_LOG_INFO("TEST", + "Now testing map-driven property propagation with invalid map (no destination " + "port)"); + BOOST_REQUIRE_THROW(graph.commit(), uhd::rfnoc_error); +} + |