diff options
author | Lars Amsel <lars.amsel@ni.com> | 2023-10-27 11:48:59 +0200 |
---|---|---|
committer | Aki Tomita <121511582+atomita-ni@users.noreply.github.com> | 2024-03-05 09:57:51 -0600 |
commit | d3e27d94052110b180267907c8c12f3c2d050271 (patch) | |
tree | 6bec6012746e54a407e3940cb658ae2033e51cc2 | |
parent | host: cmake: Verify find_library (diff) | |
download | uhd-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.hpp | 8 | ||||
-rw-r--r-- | host/lib/include/uhdlib/rfnoc/graph.hpp | 8 | ||||
-rw-r--r-- | host/lib/rfnoc/graph.cpp | 56 | ||||
-rw-r--r-- | host/lib/rfnoc/rfnoc_graph.cpp | 6 | ||||
-rw-r--r-- | host/lib/rfnoc/rfnoc_python.hpp | 1 |
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) |