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 | |
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()
-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) |