aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/tests/rfnoc_graph_mock_nodes.hpp148
-rw-r--r--host/tests/rfnoc_propprop_test.cpp112
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);
+}
+