aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williams <alex.williams@ni.com>2019-06-19 17:40:46 -0700
committerMartin Braun <martin.braun@ettus.com>2019-11-26 11:49:29 -0800
commit52c38e3c22d7c83943c0e1fc0bc69a967d6fe25c (patch)
tree1fec490bc9297c21b43805f942cf8982b7c98260
parent50f8e9f35f776016ec8df7edad570d9d8084afdb (diff)
downloaduhd-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.hpp30
-rw-r--r--host/lib/include/uhdlib/rfnoc/graph.hpp4
-rw-r--r--host/lib/rfnoc/graph.cpp14
-rw-r--r--host/lib/rfnoc/rfnoc_graph.cpp146
-rw-r--r--host/tests/rfnoc_detailgraph_test.cpp8
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)