Line data Source code
1 : /************************************************************
2 : *
3 : * GraphBuilder.hpp
4 : *
5 : * JCF, Sep-11-2024
6 : *
7 : * GraphBuilder is the tool we can use to plot configurations. A quick overview:
8 : *
9 : * - Constructed from an OKS database file (XML) and the name of a session contained within it
10 : * - GraphBuilder::construct_graph will take a "root object" from the session and
11 : * construct a graph accordingly
12 : * - GraphBuilder::write_graph will take the name of an output DOT
13 : * file and write the graph to it
14 : *
15 : * The resulting DOT file can then be processed by, e.g., Graphviz in
16 : * order to generate a viewable graphic of the configuration
17 : *
18 : * This is part of the DUNE DAQ Application Framework, copyright 2020.
19 : * Licensing/copyright details are in the COPYING file that you should have
20 : * received with this code.
21 : *
22 : *************************************************************/
23 :
24 : #ifndef DAQCONF_APPS_GRAPHBUILDER_HPP_
25 : #define DAQCONF_APPS_GRAPHBUILDER_HPP_
26 :
27 : #include "conffwk/ConfigObject.hpp"
28 :
29 : #include "confmodel/Session.hpp"
30 : #include "ers/ers.hpp"
31 : #include "logging/Logging.hpp" // NOTE: if ISSUES ARE DECLARED BEFORE include logging/Logging.hpp, TLOG_DEBUG<<issue wont work.
32 :
33 : #include "boost/graph/adjacency_list.hpp"
34 : #include "boost/graph/graph_traits.hpp"
35 : #include "boost/graph/labeled_graph.hpp"
36 :
37 : #include <string>
38 : #include <unordered_map>
39 : #include <vector>
40 :
41 : namespace daqconf {
42 :
43 : class GraphBuilder
44 : {
45 :
46 : public:
47 : using ConfigObject = dunedaq::conffwk::ConfigObject;
48 :
49 : struct VertexLabel;
50 : struct EdgeLabel;
51 :
52 : // Switching container type to boost::listS seems to cause
53 : // compilation problems with the boost::write_graphviz function...
54 : using Graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexLabel, EdgeLabel>;
55 : using Edge_t = boost::graph_traits<Graph_t>::edge_descriptor;
56 : using Vertex_t = boost::graph_traits<Graph_t>::vertex_descriptor;
57 :
58 : enum class ObjectKind
59 : {
60 : kUndefined,
61 : kSession,
62 : kSegment,
63 : kApplication,
64 : kModule,
65 : kIncomingExternal, // Object is meant to represent the outside world, not an actual component of the DAQ
66 : kOutgoingExternal // ""
67 : };
68 :
69 : struct VertexLabel
70 : {
71 :
72 0 : VertexLabel() = default;
73 :
74 0 : VertexLabel(const std::string& uid, const std::string& classname)
75 0 : : displaylabel(uid + "\n" + classname)
76 : {
77 0 : }
78 :
79 : const std::string displaylabel{ "undefined" };
80 : };
81 :
82 : struct EdgeLabel
83 : {
84 : const std::string displaylabel{ "undefined" };
85 : };
86 :
87 : explicit GraphBuilder(const std::string& oksfilename, const std::string& sessionname);
88 :
89 : void construct_graph(std::string root_obj_uid);
90 : void write_graph(const std::string& outputfilename) const;
91 :
92 : GraphBuilder(const GraphBuilder&) = delete;
93 : GraphBuilder(GraphBuilder&&) = delete;
94 : GraphBuilder& operator=(const GraphBuilder&) = delete;
95 : GraphBuilder& operator=(GraphBuilder&&) = delete;
96 :
97 : private:
98 : struct EnhancedObject
99 : {
100 :
101 : struct ReceivingInfo
102 : {
103 0 : std::string connection_name;
104 0 : std::string receiver_label;
105 :
106 0 : bool operator==(const ReceivingInfo& other) const = default;
107 : };
108 :
109 0 : EnhancedObject(const ConfigObject& config_object_arg, ObjectKind kind_arg)
110 0 : : config_object{ config_object_arg }
111 0 : , kind{ kind_arg }
112 : {
113 0 : }
114 :
115 : ConfigObject config_object;
116 : ObjectKind kind;
117 :
118 : Vertex_t vertex_in_graph;
119 :
120 : // What objects is this one the parent of? E.g., a parent session with child segments
121 : std::vector<std::string> child_object_names;
122 :
123 : // What objects does this one send data to, and what are their connections called?
124 : std::vector<ReceivingInfo> receiving_object_infos;
125 : };
126 :
127 : void find_candidate_objects();
128 : [[nodiscard]] std::vector<dunedaq::conffwk::ConfigObject> find_child_objects(const ConfigObject& parent_obj);
129 : void calculate_graph(const std::string& root_obj_uid);
130 :
131 : // find_objects_and_connections fills m_objects_for_graph as well
132 : // as m_incoming_connections and m_outgoing_connections
133 :
134 : void find_objects_and_connections(const ConfigObject& object);
135 : void calculate_network_connections();
136 :
137 : const std::string m_oksfilename;
138 : dunedaq::conffwk::Configuration* m_confdb;
139 :
140 : const std::unordered_map<ObjectKind, std::vector<std::string>> m_included_classes;
141 :
142 : std::unordered_map<std::string, EnhancedObject> m_objects_for_graph;
143 :
144 : std::unordered_map<std::string, std::vector<std::string>> m_incoming_connections;
145 : std::unordered_map<std::string, std::vector<std::string>> m_outgoing_connections;
146 :
147 : Graph_t m_graph;
148 : ObjectKind m_root_object_kind;
149 :
150 : dunedaq::confmodel::Session* m_session;
151 : std::string m_session_name;
152 :
153 : std::vector<std::string> m_ignored_application_uids;
154 :
155 : std::vector<ConfigObject> m_all_objects;
156 : std::vector<ConfigObject> m_candidate_objects;
157 : };
158 :
159 : [[nodiscard]] constexpr GraphBuilder::ObjectKind
160 : get_object_kind(const std::string& class_name);
161 :
162 : } // namespace daqconf
163 :
164 0 : ERS_DECLARE_ISSUE(daqconf, GeneralGraphToolError, "A graph tool error occured: " << errmsg, ((std::string)errmsg))
165 :
166 : #endif // DAQCONF_APPS_GRAPHBUILDER_HPP_
|