diff options
| author | Alex Williams <alex.williams@ni.com> | 2019-06-19 17:40:46 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:29 -0800 | 
| commit | 52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c (patch) | |
| tree | 1fec490bc9297c21b43805f942cf8982b7c98260 /host | |
| parent | 50f8e9f35f776016ec8df7edad570d9d8084afdb (diff) | |
| download | uhd-52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c.tar.gz uhd-52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c.tar.bz2 uhd-52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c.zip | |
rfnoc: Enable users to query connections in the graph
Implement uhd::rfnoc::rfnoc_graph::enumerate_*_connections()
Diffstat (limited to 'host')
| -rw-r--r-- | host/include/uhd/rfnoc_graph.hpp | 30 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/rfnoc/graph.hpp | 4 | ||||
| -rw-r--r-- | host/lib/rfnoc/graph.cpp | 14 | ||||
| -rw-r--r-- | host/lib/rfnoc/rfnoc_graph.cpp | 146 | ||||
| -rw-r--r-- | host/tests/rfnoc_detailgraph_test.cpp | 8 | 
5 files changed, 189 insertions, 13 deletions
| diff --git a/host/include/uhd/rfnoc_graph.hpp b/host/include/uhd/rfnoc_graph.hpp index 6a75a8668..c13939ac9 100644 --- a/host/include/uhd/rfnoc_graph.hpp +++ b/host/include/uhd/rfnoc_graph.hpp @@ -8,12 +8,12 @@  #define INCLUDED_LIBUHD_RFNOCDEV_GRAPH_HPP  #include <uhd/config.hpp> -#include <uhd/stream.hpp> -#include <uhd/utils/noncopyable.hpp> -#include <uhd/rfnoc/graph_edge.hpp>  #include <uhd/rfnoc/block_id.hpp> +#include <uhd/rfnoc/graph_edge.hpp>  #include <uhd/rfnoc/noc_block_base.hpp> +#include <uhd/stream.hpp>  #include <uhd/types/device_addr.hpp> +#include <uhd/utils/noncopyable.hpp>  #include <boost/units/detail/utility.hpp> // for demangle  #include <memory>  #include <vector> @@ -39,8 +39,10 @@ public:      virtual ~rfnoc_graph() {} -    //! Stuct to store information about which blocks are actually stored at a given port on the crossbar -    struct block_xbar_info { +    //! Stuct to store information about which blocks are actually stored at a given port +    //! on the crossbar +    struct block_xbar_info +    {          size_t xbar_port;          noc_block_base::noc_id_t noc_id;          size_t inst_num; @@ -75,7 +77,8 @@ public:       * \endcode       * \note this access is not thread safe if performed during block enumeration       */ -    virtual std::vector<block_id_t> find_blocks(const std::string& block_id_hint) const = 0; +    virtual std::vector<block_id_t> find_blocks( +        const std::string& block_id_hint) const = 0;      /*! Type-cast version of find_blocks().       */ @@ -139,8 +142,7 @@ public:      template <typename T>      std::shared_ptr<T> get_block(const block_id_t& block_id) const      { -        std::shared_ptr<T> blk = -            std::dynamic_pointer_cast<T>(get_block(block_id)); +        std::shared_ptr<T> blk = std::dynamic_pointer_cast<T>(get_block(block_id));          if (blk) {              return blk;          } else { @@ -204,11 +206,17 @@ public:          uhd::rx_streamer& streamer,          size_t strm_port) = 0; -    /*! Enumerate all the connections in the graph +    /*! Enumerate all the possible static connections in the graph +     * +     * \return A vector containing all the static edges in the graph. +     */ +    virtual std::vector<graph_edge_t> enumerate_static_connections() const = 0; + +    /*! Enumerate all the active connections in the graph       * -     * \return A vector containing all the edges in the graph. +     * \return A vector containing all the active edges in the graph.       */ -    std::vector<graph_edge_t> enumerate_connections(); +    virtual std::vector<graph_edge_t> enumerate_active_connections() = 0;      /*! Commit graph and run initial checks       * diff --git a/host/lib/include/uhdlib/rfnoc/graph.hpp b/host/lib/include/uhdlib/rfnoc/graph.hpp index 4b08b5842..87977a1dc 100644 --- a/host/lib/include/uhdlib/rfnoc/graph.hpp +++ b/host/lib/include/uhdlib/rfnoc/graph.hpp @@ -62,6 +62,10 @@ public:       */      void release(); +    /*! Return a list of all edges +     */ +    std::vector<graph_edge_t> enumerate_edges(); +  private:      friend class graph_accessor_t; diff --git a/host/lib/rfnoc/graph.cpp b/host/lib/rfnoc/graph.cpp index cbb7ab140..174d72389 100644 --- a/host/lib/rfnoc/graph.cpp +++ b/host/lib/rfnoc/graph.cpp @@ -189,6 +189,20 @@ void graph_t::release()      _release_count++;  } +std::vector<graph_t::graph_edge_t> graph_t::enumerate_edges() +{ +    auto e_iterators = boost::edges(_graph); +    std::vector<graph_edge_t> result; +    for (auto e_it = e_iterators.first; e_it != e_iterators.second; ++e_it) { +        graph_edge_t edge_info = boost::get(edge_property_t(), _graph, *e_it); +        // This is probably the dumbest way to make sure that the in- and out- +        // edges don't both get stashed, but it works for now +        if (std::find(result.begin(), result.end(), edge_info) == result.end()) { +            result.push_back(boost::get(edge_property_t(), _graph, *e_it)); +        } +    } +    return result; +}  /******************************************************************************   * Private methods to be called by friends diff --git a/host/lib/rfnoc/rfnoc_graph.cpp b/host/lib/rfnoc/rfnoc_graph.cpp index 1fbf440cf..dd3dd7b90 100644 --- a/host/lib/rfnoc/rfnoc_graph.cpp +++ b/host/lib/rfnoc/rfnoc_graph.cpp @@ -33,6 +33,7 @@ public:          , _graph(std::make_unique<uhd::rfnoc::detail::graph_t>())      {          setup_graph(dev_addr); +        _init_static_connections();      }      ~rfnoc_graph_impl() @@ -118,6 +119,16 @@ public:          return _num_mboards;      } +    std::vector<graph_edge_t> enumerate_active_connections() +    { +        return _graph->enumerate_edges(); +    } + +    std::vector<graph_edge_t> enumerate_static_connections() const +    { +        return _static_edges; +    } +      void commit()      {          _graph->commit(); @@ -242,14 +253,51 @@ private:                      block_factory_info.factory_fn(std::move(make_args_uptr)));                  _xbar_block_config[block_id.to_string()] = {                      portno, noc_id, block_id.get_block_count()}; + +                _port_block_map.insert({{mb_idx, portno + first_block_port}, block_id});              }          }          UHD_LOG_TRACE("RFNOC::GRAPH", "Initializing properties on all blocks...");          _block_registry->init_props(); +    } -        // Create graph, connect all static routes -        // FIXME +    void _init_static_connections() +    { +        UHD_LOG_TRACE("RFNOC::GRAPH", "Identifying static connections..."); +        for (auto& kv_cz : _client_zeros) { +            auto& adjacency_list          = kv_cz.second->get_adjacency_list(); +            const size_t first_block_port = 1 + kv_cz.second->get_num_stream_endpoints(); + +            for (auto& edge : adjacency_list) { +                // Assemble edge +                auto graph_edge = graph_edge_t(); +                if (edge.src_blk_index < first_block_port) { +                    block_id_t id(kv_cz.first, NODE_ID_SEP, edge.src_blk_index - 1); +                    _port_block_map.insert({{kv_cz.first, edge.src_blk_index}, id}); +                    graph_edge.src_blockid = id.to_string(); +                } else { +                    graph_edge.src_blockid = +                        _port_block_map.at({kv_cz.first, edge.src_blk_index}); +                } +                if (edge.dst_blk_index < first_block_port) { +                    block_id_t id(kv_cz.first, NODE_ID_SEP, edge.dst_blk_index - 1); +                    _port_block_map.insert({{kv_cz.first, edge.dst_blk_index}, id}); +                    graph_edge.dst_blockid = id.to_string(); +                } else { +                    graph_edge.dst_blockid = +                        _port_block_map.at({kv_cz.first, edge.dst_blk_index}); +                } +                graph_edge.src_port = edge.src_blk_port; +                graph_edge.dst_port = edge.dst_blk_port; +                graph_edge.edge     = graph_edge_t::edge_t::STATIC; +                _static_edges.push_back(graph_edge); +                UHD_LOG_TRACE("RFNOC::GRAPH", +                    "Static connection: " +                        << graph_edge.src_blockid << ":" << graph_edge.src_port << " -> " +                        << graph_edge.dst_blockid << ":" << graph_edge.dst_port); +            } +        }      }      /************************************************************************** @@ -273,6 +321,93 @@ private:          _graph->connect(src_blk.get(), dst_blk.get(), edge_info);      } +    /*! Helper method to find a stream endpoint connected to a block +     * +     * \param blk_id the block connected to the stream endpoint +     * \param port the port connected to the stream endpoint +     * \param blk_is_src true if the block is a data source, false if it is a +     *                   destination +     * \return the address of the stream endpoint, or boost::none if it is not +     *         directly connected to a stream endpoint +     */ +    boost::optional<sep_addr_t> _get_adjacent_sep( +        const block_id_t& blk_id, const size_t port, const bool blk_is_src) const +    { +        const std::string block_id_str = get_block(blk_id)->get_block_id().to_string(); +        UHD_LOG_TRACE("RFNOC::GRAPH", +            "Finding SEP for " << (blk_is_src ? "source" : "dst") << " block " +                               << block_id_str << ":" << port); +        // TODO: This is an attempt to simplify the algo, but it turns out to be +        // as many lines as before: +        //auto edge_predicate = [blk_is_src, block_id_str](const graph_edge_t edge) { +            //if (blk_is_src) { +                //return edge.src_blockid == block_id_str; +            //} +            //return edge.dst_blockid == block_id_str; +        //}; + +        //auto blk_edge_it = +            //std::find_if(_static_edges.cbegin(), _static_edges.cend(), edge_predicate); +        //if (blk_edge_it == _static_edges.cend()) { +            //return boost::none; +        //} + +        //const std::string sep_block_id = blk_is_src ? +            //blk_edge_it->dst_blockid : blk_edge_it->src_blockid; +        //UHD_LOG_TRACE("RFNOC::GRAPH", +            //"Found SEP: " << sep_block_id); + +        //auto port_map_result = std::find_if(_port_block_map.cbegin(), +            //_port_block_map.cend, +            //[sep_block_id](std::pair<std::pair<size_t, size_t>, block_id_t> port_block) { +                //return port_block.second == sep_block_id; +            //}); +        //if (port_map_result == _port_block_map.cend()) { +            //throw uhd::lookup_error( +                //std::string("SEP `") + sep_block_id + "' not found in port/block map!"); +        //} +        //const auto dev = _device->get_mb_iface(mb_idx).get_remote_device_id(); +        //const sep_inst_t sep_inst = blk_is_src ? +            //edge.dst_blk_index - 1 : edge.src_blk_index - 1; +        //return sep_addr_t(dev, sep_inst); + +        const auto& info  = _xbar_block_config.at(block_id_str); +        const auto mb_idx = blk_id.get_device_no(); +        const auto cz     = _client_zeros.at(mb_idx); + +        const size_t first_block_port = 1 + cz->get_num_stream_endpoints(); + +        for (const auto& edge : cz->get_adjacency_list()) { +            const auto edge_blk_idx = blk_is_src ? edge.src_blk_index +                                                 : edge.dst_blk_index; +            const auto edge_blk_port = blk_is_src ? edge.src_blk_port : edge.dst_blk_port; + +            if ((edge_blk_idx == info.xbar_port + first_block_port) +                and (edge_blk_port == port)) { +                UHD_LOGGER_DEBUG("RFNOC::GRAPH") +                    << boost::format("Block found in adjacency list. %d:%d->%d:%d") +                           % edge.src_blk_index +                           % static_cast<unsigned int>(edge.src_blk_port) +                           % edge.dst_blk_index +                           % static_cast<unsigned int>(edge.dst_blk_port); + +                // Check that the block is connected to a stream endpoint. The +                // minus one here is because index zero is client 0. +                const sep_inst_t sep_inst = blk_is_src ? +                    edge.dst_blk_index - 1 : edge.src_blk_index - 1; + +                if (sep_inst < cz->get_num_stream_endpoints()) { +                    const auto dev = _device->get_mb_iface(mb_idx).get_remote_device_id(); +                    return sep_addr_t(dev, sep_inst); +                } else { +                    // Block is connected to another block +                    return boost::none; +                } +            } +        } +        return boost::none; +    } +      /*! Internal physical connection helper       *       * Make the connections in the physical device @@ -441,6 +576,13 @@ private:      //! Stash of the client zeros for all motherboards      std::unordered_map<size_t, detail::client_zero::sptr> _client_zeros; +    //! Map a pair (motherboard index, control crossbar port) to an RFNoC block +    // or SEP +    std::map<std::pair<size_t, size_t>, block_id_t> _port_block_map; + +    //! List of statically connected edges. Includes SEPs too! +    std::vector<graph_edge_t> _static_edges; +      //! uptr to graph stream manager      graph_stream_manager::uptr _gsm;  }; /* class rfnoc_graph_impl */ diff --git a/host/tests/rfnoc_detailgraph_test.cpp b/host/tests/rfnoc_detailgraph_test.cpp index efae9ff4f..2e9abf39d 100644 --- a/host/tests/rfnoc_detailgraph_test.cpp +++ b/host/tests/rfnoc_detailgraph_test.cpp @@ -157,6 +157,13 @@ BOOST_AUTO_TEST_CASE(test_graph)      graph.connect(&mock_rx_radio, &mock_tx_radio, edge_info);      BOOST_CHECK_EQUAL(boost::num_vertices(bgl_graph), 2); +    BOOST_REQUIRE_EQUAL(graph.enumerate_edges().size(), 1); +    auto edge0_info = graph.enumerate_edges().at(0); +    BOOST_CHECK_EQUAL(edge0_info.src_blockid, "MOCK_RADIO0"); +    BOOST_CHECK_EQUAL(edge0_info.src_port, 0); +    BOOST_CHECK_EQUAL(edge0_info.dst_blockid, "MOCK_RADIO1"); +    BOOST_CHECK_EQUAL(edge0_info.dst_port, 0); +      // Now attempt illegal connections (they must all fail)      edge_info.src_port = 1;      edge_info.dst_port = 0; @@ -171,6 +178,7 @@ BOOST_AUTO_TEST_CASE(test_graph)      edge_info.property_propagation_active = false;      BOOST_REQUIRE_THROW(          graph.connect(&mock_rx_radio, &mock_tx_radio, edge_info), uhd::rfnoc_error); +    BOOST_CHECK_EQUAL(graph.enumerate_edges().size(), 1);  }  BOOST_AUTO_TEST_CASE(test_graph_unresolvable) | 
