From 52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c Mon Sep 17 00:00:00 2001 From: Alex Williams Date: Wed, 19 Jun 2019 17:40:46 -0700 Subject: rfnoc: Enable users to query connections in the graph Implement uhd::rfnoc::rfnoc_graph::enumerate_*_connections() --- host/include/uhd/rfnoc_graph.hpp | 30 ++++--- host/lib/include/uhdlib/rfnoc/graph.hpp | 4 + host/lib/rfnoc/graph.cpp | 14 +++ host/lib/rfnoc/rfnoc_graph.cpp | 146 +++++++++++++++++++++++++++++++- host/tests/rfnoc_detailgraph_test.cpp | 8 ++ 5 files changed, 189 insertions(+), 13 deletions(-) (limited to 'host') 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 -#include -#include -#include #include +#include #include +#include #include +#include #include // for demangle #include #include @@ -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 find_blocks(const std::string& block_id_hint) const = 0; + virtual std::vector find_blocks( + const std::string& block_id_hint) const = 0; /*! Type-cast version of find_blocks(). */ @@ -139,8 +142,7 @@ public: template std::shared_ptr get_block(const block_id_t& block_id) const { - std::shared_ptr blk = - std::dynamic_pointer_cast(get_block(block_id)); + std::shared_ptr blk = std::dynamic_pointer_cast(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 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 enumerate_connections(); + virtual std::vector 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 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::enumerate_edges() +{ + auto e_iterators = boost::edges(_graph); + std::vector 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()) { setup_graph(dev_addr); + _init_static_connections(); } ~rfnoc_graph_impl() @@ -118,6 +119,16 @@ public: return _num_mboards; } + std::vector enumerate_active_connections() + { + return _graph->enumerate_edges(); + } + + std::vector 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 _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, 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(edge.src_blk_port) + % edge.dst_blk_index + % static_cast(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 _client_zeros; + //! Map a pair (motherboard index, control crossbar port) to an RFNoC block + // or SEP + std::map, block_id_t> _port_block_map; + + //! List of statically connected edges. Includes SEPs too! + std::vector _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) -- cgit v1.2.3