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); +} + | 
