aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Amsel <lars.amsel@ni.com>2023-10-27 11:48:59 +0200
committerAki Tomita <121511582+atomita-ni@users.noreply.github.com>2024-03-05 09:57:51 -0600
commitd3e27d94052110b180267907c8c12f3c2d050271 (patch)
tree6bec6012746e54a407e3940cb658ae2033e51cc2
parenthost: cmake: Verify find_library (diff)
downloaduhd-d3e27d94052110b180267907c8c12f3c2d050271.tar.xz
uhd-d3e27d94052110b180267907c8c12f3c2d050271.zip
host: add ability to query dot representation of graph
Current implementation only support dot representation of the graph topology. This adds the ability to also query the current graph layout. The method prints out connected blocks (including streamers) and their port to port connections. The graph has to be commited before calling to_dot. Update host/lib/rfnoc/graph.cpp Co-authored-by: Martin Braun <martin.braun@ettus.com>
-rw-r--r--host/include/uhd/rfnoc_graph.hpp8
-rw-r--r--host/lib/include/uhdlib/rfnoc/graph.hpp8
-rw-r--r--host/lib/rfnoc/graph.cpp56
-rw-r--r--host/lib/rfnoc/rfnoc_graph.cpp6
-rw-r--r--host/lib/rfnoc/rfnoc_python.hpp1
5 files changed, 79 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc_graph.hpp b/host/include/uhd/rfnoc_graph.hpp
index dcb530e5a..867f6080e 100644
--- a/host/include/uhd/rfnoc_graph.hpp
+++ b/host/include/uhd/rfnoc_graph.hpp
@@ -327,6 +327,14 @@ public:
*/
virtual void release() = 0;
+ /*! Create a dot representation of the current graph
+ *
+ * The graph is represented in the dot language, which can be visualized
+ * using the Graphviz tools. It contains all blocks and their connections.
+ * The connections are drawn between the ports of the blocks.
+ */
+ virtual std::string to_dot() = 0;
+
/******************************************
* Streaming
******************************************/
diff --git a/host/lib/include/uhdlib/rfnoc/graph.hpp b/host/lib/include/uhdlib/rfnoc/graph.hpp
index f1d1b51ff..d0f5c864f 100644
--- a/host/lib/include/uhdlib/rfnoc/graph.hpp
+++ b/host/lib/include/uhdlib/rfnoc/graph.hpp
@@ -88,6 +88,14 @@ public:
*/
std::vector<graph_edge_t> enumerate_edges();
+ /*! Create a dot representation of the current graph
+ *
+ * The graph is represented in the dot language, which can be visualized
+ * using the Graphviz tools. It contains all blocks and their connections.
+ * The connections are drawn between the ports of the blocks.
+ */
+ std::string to_dot();
+
private:
friend class graph_accessor_t;
diff --git a/host/lib/rfnoc/graph.cpp b/host/lib/rfnoc/graph.cpp
index 3525faab5..12a179f44 100644
--- a/host/lib/rfnoc/graph.cpp
+++ b/host/lib/rfnoc/graph.cpp
@@ -286,6 +286,62 @@ std::vector<graph_t::graph_edge_t> graph_t::enumerate_edges()
return result;
}
+std::string graph_t::to_dot()
+{
+ std::string result("digraph rfnoc_graph {\n"
+ " rankdir=LR\n"
+ " node [shape=record]\n\n");
+
+ for (const auto& elem : _node_map) {
+ // add block, prepend with cluster,
+ // the cluster prefix ensures a box around the node
+ result += str(boost::format(" subgraph \"cluster_%s\" {\n"
+ " label=\"%s\"\n")
+ % elem.first->get_unique_id() % elem.first->get_unique_id());
+
+ // add input ports as joint blocks using "|<ref> label" notation
+ if (elem.first->get_num_input_ports() > 0) {
+ result += str(
+ boost::format(" \"%s_in\" [label=\"in") % elem.first->get_unique_id());
+ for (size_t i = 0; i < elem.first->get_num_input_ports(); i++) {
+ result += str(boost::format("|<in_%d> %d") % i % i);
+ }
+ result += "\"]\n";
+ }
+
+ // add input ports as joint blocks using "|<ref> label" notation
+ if (elem.first->get_num_output_ports() > 0) {
+ result += str(boost::format(" \"%s_out\" [label=\"out")
+ % elem.first->get_unique_id());
+ for (size_t i = 0; i < elem.first->get_num_output_ports(); i++) {
+ result += str(boost::format("|<out_%d> %d") % i % i);
+ }
+ result += "\"]\n";
+ }
+
+ result += " }\n";
+
+ // add an invisible connection between in and out ports so they
+ // get aligned inputs left and outputs right
+ if ((elem.first->get_num_input_ports() > 0)
+ && (elem.first->get_num_output_ports() > 0)) {
+ result += str(boost::format(" \"%s_in\" -> \"%s_out\" [style=invis]\n")
+ % elem.first->get_unique_id() % elem.first->get_unique_id());
+ }
+ result += "\n";
+ }
+ result += "\n";
+
+ // add current connections
+ for (const auto& elem : enumerate_edges()) {
+ result +=
+ str(boost::format(" \"%s_out\":\"out_%d\" -> \"%s_in\":\"in_%d\"\n")
+ % elem.src_blockid % elem.src_port % elem.dst_blockid % elem.dst_port);
+ }
+ result += "}\n";
+ 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 509f98b04..34f08250a 100644
--- a/host/lib/rfnoc/rfnoc_graph.cpp
+++ b/host/lib/rfnoc/rfnoc_graph.cpp
@@ -578,6 +578,7 @@ public:
void commit() override
{
_graph->commit();
+ UHD_LOG_TRACE(LOG_ID, "new graph committed" << std::endl << _graph->to_dot());
}
void release() override
@@ -585,6 +586,11 @@ public:
_graph->release();
}
+ std::string to_dot() override
+ {
+ return _graph->to_dot();
+ }
+
private:
/**************************************************************************
* Device Setup
diff --git a/host/lib/rfnoc/rfnoc_python.hpp b/host/lib/rfnoc/rfnoc_python.hpp
index b53de268c..53c61d3f2 100644
--- a/host/lib/rfnoc/rfnoc_python.hpp
+++ b/host/lib/rfnoc/rfnoc_python.hpp
@@ -223,6 +223,7 @@ void export_rfnoc(py::module& m)
.def("enumerate_active_connections", &rfnoc_graph::enumerate_active_connections)
.def("commit", &rfnoc_graph::commit)
.def("release", &rfnoc_graph::release)
+ .def("to_dot", &rfnoc_graph::to_dot)
.def("create_rx_streamer", &rfnoc_graph::create_rx_streamer)
.def("create_tx_streamer", &rfnoc_graph::create_tx_streamer)
.def("get_num_mboards", &rfnoc_graph::get_num_mboards)