diff --git a/system/diagnostic_graph_aggregator/CMakeLists.txt b/system/diagnostic_graph_aggregator/CMakeLists.txt index c4a67032541b2..574978ec5adce 100644 --- a/system/diagnostic_graph_aggregator/CMakeLists.txt +++ b/system/diagnostic_graph_aggregator/CMakeLists.txt @@ -22,10 +22,17 @@ ament_auto_add_executable(converter ) target_include_directories(converter PRIVATE src/common) -ament_auto_add_executable(tool - src/tool/tool.cpp +ament_auto_add_executable(tree + src/tool/tree.cpp + src/tool/utils/loader.cpp ) -target_include_directories(tool PRIVATE src/common) +target_include_directories(tree PRIVATE src/common) + +ament_auto_add_executable(plantuml + src/tool/plantuml.cpp + src/tool/utils/loader.cpp +) +target_include_directories(plantuml PRIVATE src/common) if(BUILD_TESTING) get_filename_component(RESOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test/files ABSOLUTE) diff --git a/system/diagnostic_graph_aggregator/README.md b/system/diagnostic_graph_aggregator/README.md index dabbb1402db4c..cc49ed88ba98f 100644 --- a/system/diagnostic_graph_aggregator/README.md +++ b/system/diagnostic_graph_aggregator/README.md @@ -71,6 +71,12 @@ You can reuse the graph by making partial edits. For example, disable hardware c ros2 launch diagnostic_graph_aggregator example-edit.launch.xml ``` +## Debug tools + +- [dump](./doc/tool/dump.md) +- [converter](./doc/tool/converter.md) +- [tree](./doc/tool/tree.md) + ## Graph file format - [graph](./doc/format/graph.md) diff --git a/system/diagnostic_graph_aggregator/doc/tool/converter.md b/system/diagnostic_graph_aggregator/doc/tool/converter.md new file mode 100644 index 0000000000000..2351bc1e01054 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/converter.md @@ -0,0 +1,29 @@ +# Converter tool + +This tool converts `/diagnostics_graph` to `/diagnostics_agg` so it can be read by tools such as `rqt_runtime_monitor` and `rqt_robot_monitor`. + +## Usage + +```bash +ros2 launch diagnostic_graph_aggregator converter.launch.xml complement:=false +``` + +The `complement` argument specifies whether to add an intermediate path that does not exist. +This means that if the graph contains paths `/A/B` and `/A/B/C/D/E`, the intermediate paths `/A`, `/A/B/C` and `/A/B/C/D` will be added. +This is useful for tree view in `rqt_robot_monitor`. The completed node has an error level of `STALE`. + +## Examples + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml complement:=false +ros2 run rqt_runtime_monitor rqt_runtime_monitor --ros-args -r diagnostics:=diagnostics_agg +``` + +![rqt_runtime_monitor](./images/rqt_runtime_monitor.png) + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml complement:=true +ros2 run rqt_robot_monitor rqt_robot_monitor +``` + +![rqt_robot_monitor](./images/rqt_robot_monitor.png) diff --git a/system/diagnostic_graph_aggregator/doc/tool/dump.md b/system/diagnostic_graph_aggregator/doc/tool/dump.md new file mode 100644 index 0000000000000..33f05ff866603 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/dump.md @@ -0,0 +1,36 @@ +# Dump tool + +This tool displays `/diagnostics_graph` in table format. + +## Usage + +```bash +ros2 run diagnostic_graph_aggregator dump +``` + +## Examples + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml +ros2 run diagnostic_graph_aggregator dump +``` + +```txt +| ----- | ----- | -------------------------------- | ----- | +| index | level | name | links | +| ----- | ----- | -------------------------------- | ----- | +| 0 | OK | /sensing/radars/front | | +| 1 | OK | /sensing/lidars/front | | +| 2 | ERROR | /sensing/lidars/top | | +| 3 | OK | /functions/obstacle_detection | 1 0 | +| 4 | ERROR | /functions/pose_estimation | 2 | +| 5 | OK | /external/remote_command | | +| 6 | OK | /external/joystick_command | | +| 7 | ERROR | /autoware/modes/pull_over | 4 3 | +| 8 | OK | /autoware/modes/comfortable_stop | 3 | +| 9 | OK | /autoware/modes/emergency_stop | | +| 10 | OK | /autoware/modes/remote | 5 | +| 11 | OK | /autoware/modes/local | 6 | +| 12 | ERROR | /autoware/modes/autonomous | 4 3 | +| 13 | OK | /autoware/modes/stop | | +``` diff --git a/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png new file mode 100644 index 0000000000000..e4aa169f02add Binary files /dev/null and b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png differ diff --git a/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png new file mode 100644 index 0000000000000..768fee688f594 Binary files /dev/null and b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png differ diff --git a/system/diagnostic_graph_aggregator/doc/tool/tree.md b/system/diagnostic_graph_aggregator/doc/tool/tree.md new file mode 100644 index 0000000000000..79fa61f527038 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/tree.md @@ -0,0 +1,40 @@ +# Tree tool + +This tool displays the graph structure of the configuration file in tree format. + +## Usage + +```bash +ros2 run diagnostic_graph_aggregator tree +``` + +## Examples + +```bash +ros2 run diagnostic_graph_aggregator tree system/diagnostic_graph_aggregator/example/graph/main.yaml +``` + +```txt +===== root nodes ================================= +- /autoware/modes/local (and) + - /external/joystick_command (diag) +- /autoware/modes/comfortable_stop (and) + - /functions/obstacle_detection (or) +- /autoware/modes/pull_over (and) + - /functions/pose_estimation (and) + - /functions/obstacle_detection (or) +- /autoware/modes/autonomous (and) + - /functions/pose_estimation (and) + - /functions/obstacle_detection (or) +- /autoware/modes/remote (and) + - /external/remote_command (diag) +===== intermediate nodes ========================= +- /functions/obstacle_detection (or) + - /sensing/lidars/front (diag) + - /sensing/radars/front (diag) +- /functions/pose_estimation (and) + - /sensing/lidars/top (diag) +===== isolated nodes ============================= +- /autoware/modes/stop (const) +- /autoware/modes/emergency_stop (const) +``` diff --git a/system/diagnostic_graph_aggregator/example/dummy-diags.py b/system/diagnostic_graph_aggregator/example/dummy-diags.py index 52d6189a63f30..08f81bcd738ed 100755 --- a/system/diagnostic_graph_aggregator/example/dummy-diags.py +++ b/system/diagnostic_graph_aggregator/example/dummy-diags.py @@ -59,6 +59,9 @@ def create_status(name: str): "external_command_checker: joystick_command", "external_command_checker: remote_command", ] - rclpy.init() - rclpy.spin(DummyDiagnostics(diags)) - rclpy.shutdown() + try: + rclpy.init() + rclpy.spin(DummyDiagnostics(diags)) + rclpy.shutdown() + except KeyboardInterrupt: + pass diff --git a/system/diagnostic_graph_aggregator/example/example-edit.launch.xml b/system/diagnostic_graph_aggregator/example/example-edit.launch.xml index 91bcc46df6494..c168b76f19c21 100644 --- a/system/diagnostic_graph_aggregator/example/example-edit.launch.xml +++ b/system/diagnostic_graph_aggregator/example/example-edit.launch.xml @@ -1,7 +1,10 @@ + - + + + diff --git a/system/diagnostic_graph_aggregator/example/example-main.launch.xml b/system/diagnostic_graph_aggregator/example/example-main.launch.xml index ab7bfaa2e0617..cdc1bc8afca53 100644 --- a/system/diagnostic_graph_aggregator/example/example-main.launch.xml +++ b/system/diagnostic_graph_aggregator/example/example-main.launch.xml @@ -1,7 +1,10 @@ - + + - + + + diff --git a/system/diagnostic_graph_aggregator/launch/diagnostic_graph_aggregator.launch.xml b/system/diagnostic_graph_aggregator/launch/aggregator.launch.xml similarity index 100% rename from system/diagnostic_graph_aggregator/launch/diagnostic_graph_aggregator.launch.xml rename to system/diagnostic_graph_aggregator/launch/aggregator.launch.xml diff --git a/system/diagnostic_graph_aggregator/launch/converter.launch.xml b/system/diagnostic_graph_aggregator/launch/converter.launch.xml new file mode 100644 index 0000000000000..9111338bf622a --- /dev/null +++ b/system/diagnostic_graph_aggregator/launch/converter.launch.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/system/diagnostic_graph_aggregator/script/dump.py b/system/diagnostic_graph_aggregator/script/dump.py index 3e639cbce104d..9abcaeb7a080c 100755 --- a/system/diagnostic_graph_aggregator/script/dump.py +++ b/system/diagnostic_graph_aggregator/script/dump.py @@ -84,7 +84,6 @@ def callback(self, msg): if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--topic", default="/diagnostics_graph") - parser.add_argument("--order", default="index") args, unparsed = parser.parse_known_args() try: diff --git a/system/diagnostic_graph_aggregator/src/node/aggregator.cpp b/system/diagnostic_graph_aggregator/src/node/aggregator.cpp index 48f489c186bdb..cd16ce8e33e59 100644 --- a/system/diagnostic_graph_aggregator/src/node/aggregator.cpp +++ b/system/diagnostic_graph_aggregator/src/node/aggregator.cpp @@ -20,7 +20,7 @@ namespace diagnostic_graph_aggregator { -MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") +AggregatorNode::AggregatorNode() : Node("aggregator") { // Init diagnostics graph. { @@ -39,7 +39,7 @@ MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") const auto qos_input = rclcpp::QoS(declare_parameter("input_qos_depth")); const auto qos_graph = rclcpp::QoS(declare_parameter("graph_qos_depth")); - const auto callback = std::bind(&MainNode::on_diag, this, _1); + const auto callback = std::bind(&AggregatorNode::on_diag, this, _1); sub_input_ = create_subscription("/diagnostics", qos_input, callback); pub_graph_ = create_publisher("/diagnostics_graph", qos_graph); @@ -51,12 +51,12 @@ MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") debug_ = declare_parameter("use_debug_mode"); } -MainNode::~MainNode() +AggregatorNode::~AggregatorNode() { // for unique_ptr } -void MainNode::on_timer() +void AggregatorNode::on_timer() { const auto stamp = now(); pub_graph_->publish(graph_.report(stamp)); @@ -64,7 +64,7 @@ void MainNode::on_timer() if (modes_) modes_->update(stamp); } -void MainNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) +void AggregatorNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) { graph_.callback(now(), *msg); } @@ -73,10 +73,10 @@ void MainNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) int main(int argc, char ** argv) { - using diagnostic_graph_aggregator::MainNode; + using diagnostic_graph_aggregator::AggregatorNode; rclcpp::init(argc, argv); rclcpp::executors::SingleThreadedExecutor executor; - auto node = std::make_shared(); + auto node = std::make_shared(); executor.add_node(node); executor.spin(); executor.remove_node(node); diff --git a/system/diagnostic_graph_aggregator/src/node/aggregator.hpp b/system/diagnostic_graph_aggregator/src/node/aggregator.hpp index dd64809e939cc..6bf9aead9754d 100644 --- a/system/diagnostic_graph_aggregator/src/node/aggregator.hpp +++ b/system/diagnostic_graph_aggregator/src/node/aggregator.hpp @@ -26,11 +26,11 @@ namespace diagnostic_graph_aggregator { -class MainNode : public rclcpp::Node +class AggregatorNode : public rclcpp::Node { public: - MainNode(); - ~MainNode(); + AggregatorNode(); + ~AggregatorNode(); private: Graph graph_; diff --git a/system/diagnostic_graph_aggregator/src/node/converter.cpp b/system/diagnostic_graph_aggregator/src/node/converter.cpp index 89acfce31a5ab..f0b2108374017 100644 --- a/system/diagnostic_graph_aggregator/src/node/converter.cpp +++ b/system/diagnostic_graph_aggregator/src/node/converter.cpp @@ -14,8 +14,7 @@ #include "converter.hpp" -#include -#include +#include namespace diagnostic_graph_aggregator { @@ -35,18 +34,46 @@ std::string level_to_string(DiagnosticLevel level) return "UNKNOWN"; } -ToolNode::ToolNode() : Node("diagnostic_graph_aggregator_converter") +std::string parent_path(const std::string & path) +{ + return path.substr(0, path.rfind('/')); +} + +auto create_tree(const DiagnosticGraph & graph) +{ + std::map, std::greater> tree; + for (const auto & node : graph.nodes) { + tree.emplace(node.status.name, std::make_unique(true)); + } + for (const auto & node : graph.nodes) { + std::string path = node.status.name; + while (path = parent_path(path), !path.empty()) { + if (tree.count(path)) break; + tree.emplace(path, std::make_unique(false)); + } + } + for (const auto & [path, node] : tree) { + const auto parent = parent_path(path); + node->parent = parent.empty() ? nullptr : tree[parent].get(); + } + return tree; +} + +ConverterNode::ConverterNode() : Node("converter") { using std::placeholders::_1; const auto qos_graph = rclcpp::QoS(1); const auto qos_array = rclcpp::QoS(1); - const auto callback = std::bind(&ToolNode::on_graph, this, _1); + const auto callback = std::bind(&ConverterNode::on_graph, this, _1); sub_graph_ = create_subscription("/diagnostics_graph", qos_graph, callback); - pub_array_ = create_publisher("/diagnostics_array", qos_array); + pub_array_ = create_publisher("/diagnostics_agg", qos_array); + + initialize_tree_ = false; + complement_tree_ = declare_parameter("complement_tree"); } -void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) +void ConverterNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) { DiagnosticArray message; message.header.stamp = msg->stamp; @@ -63,6 +90,31 @@ void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) } } } + + if (complement_tree_ && !initialize_tree_) { + initialize_tree_ = true; + tree_ = create_tree(*msg); + } + + if (complement_tree_) { + for (const auto & [path, node] : tree_) { + node->level = DiagnosticStatus::OK; + } + for (const auto & node : msg->nodes) { + tree_[node.status.name]->level = node.status.level; + } + for (const auto & [path, node] : tree_) { + if (!node->parent) continue; + node->parent->level = std::max(node->parent->level, node->level); + } + for (const auto & [path, node] : tree_) { + if (node->leaf) continue; + message.status.emplace_back(); + message.status.back().name = path; + message.status.back().level = node->level; + } + } + pub_array_->publish(message); } @@ -70,10 +122,10 @@ void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) int main(int argc, char ** argv) { - using diagnostic_graph_aggregator::ToolNode; + using diagnostic_graph_aggregator::ConverterNode; rclcpp::init(argc, argv); rclcpp::executors::SingleThreadedExecutor executor; - auto node = std::make_shared(); + auto node = std::make_shared(); executor.add_node(node); executor.spin(); executor.remove_node(node); diff --git a/system/diagnostic_graph_aggregator/src/node/converter.hpp b/system/diagnostic_graph_aggregator/src/node/converter.hpp index 7a3e8e4e58033..1f98abed4d619 100644 --- a/system/diagnostic_graph_aggregator/src/node/converter.hpp +++ b/system/diagnostic_graph_aggregator/src/node/converter.hpp @@ -19,15 +19,32 @@ #include +#include +#include // Use map for sorting keys. +#include +#include +#include + namespace diagnostic_graph_aggregator { -class ToolNode : public rclcpp::Node +struct TreeNode +{ + explicit TreeNode(bool leaf) : leaf(leaf) {} + bool leaf; + TreeNode * parent; + uint8_t level; +}; + +class ConverterNode : public rclcpp::Node { public: - ToolNode(); + ConverterNode(); private: + bool initialize_tree_; + bool complement_tree_; + std::map, std::greater> tree_; rclcpp::Subscription::SharedPtr sub_graph_; rclcpp::Publisher::SharedPtr pub_array_; void on_graph(const DiagnosticGraph::ConstSharedPtr msg); diff --git a/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp b/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp new file mode 100644 index 0000000000000..bfbb382a78fcb --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp @@ -0,0 +1,49 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/loader.hpp" + +#include + +namespace diagnostic_graph_aggregator +{ + +void dump_root(const std::string & path) +{ + const auto graph = load_graph_nodes(path); + const auto color = "#FFFFFF"; + + for (const auto & node : graph.nodes) { + std::cout << "card " << node << " " << color << " [" << std::endl; + std::cout << node->path << std::endl; + std::cout << "]" << std::endl; + } + + for (const auto & node : graph.nodes) { + for (const auto & child : node->children) { + std::cout << node << " --> " << child << std::endl; + } + } +} + +} // namespace diagnostic_graph_aggregator + +int main(int argc, char ** argv) +{ + if (argc != 2) { + std::cerr << "usage: plantuml " << std::endl; + return 1; + } + diagnostic_graph_aggregator::dump_root(argv[1]); +} diff --git a/system/diagnostic_graph_aggregator/src/tool/tool.cpp b/system/diagnostic_graph_aggregator/src/tool/tool.cpp deleted file mode 100644 index 657f76c2d91b7..0000000000000 --- a/system/diagnostic_graph_aggregator/src/tool/tool.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 The Autoware Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "graph/graph.hpp" -#include "graph/types.hpp" -#include "graph/units.hpp" - -#include -#include -#include - -namespace diagnostic_graph_aggregator -{ - -struct GraphNode -{ - using UniquePtr = std::unique_ptr; - std::string type; - std::string path; - std::vector children; - std::vector parents; -}; - -struct GraphRoot -{ - std::vector owner; - std::vector nodes; -}; - -GraphRoot load_graph_nodes(const std::string & path) -{ - GraphRoot result; - { - std::unordered_map mapping; - Graph graph; - graph.init(path); - - for (const auto & node : graph.nodes()) { - auto data = std::make_unique(); - data->path = node->path(); - data->type = node->type(); - mapping[node] = std::move(data); - } - - for (const auto & [node, data] : mapping) { - for (const auto & link : node->children()) { - const auto parent = data.get(); - const auto child = mapping.at(link).get(); - child->parents.push_back(parent); - parent->children.push_back(child); - } - } - - for (auto & [node, data] : mapping) { - result.owner.push_back(std::move(data)); - } - for (const auto & node : result.owner) { - result.nodes.push_back(node.get()); - } - } - return result; -} - -void dump_plantuml_path(const std::string & path) -{ - const auto graph = load_graph_nodes(path); - const auto color = "#FFFFFF"; - - for (const auto & node : graph.nodes) { - std::cout << "card " << node << " " << color << " [" << std::endl; - std::cout << node->path << std::endl; - std::cout << "]" << std::endl; - } - - for (const auto & node : graph.nodes) { - for (const auto & child : node->children) { - std::cout << node << " --> " << child << std::endl; - } - } -} - -void dump_tree_node(const GraphNode * node, const std::string & indent = "", bool root = true) -{ - const auto path = node->path.empty() ? "" : node->path + " "; - const auto type = "(" + node->type + ")"; - std::cout << indent << "- " << path << type << std::endl; - - if (root || node->parents.size() == 1) { - for (const auto child : node->children) { - dump_tree_node(child, indent + " ", false); - } - } -} - -void dump_tree_path(const std::string & path) -{ - const auto graph = load_graph_nodes(path); - - std::cout << "===== root nodes =================================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() == 0 && node->children.size() != 0) { - dump_tree_node(node); - } - } - std::cout << "===== intermediate nodes =========================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() >= 2) { - dump_tree_node(node); - } - } - - std::cout << "===== isolated nodes =============================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() == 0 && node->children.size() == 0) { - dump_tree_node(node); - } - } -} - -} // namespace diagnostic_graph_aggregator - -int main(int argc, char ** argv) -{ - if (argc != 2) { - std::cerr << "usage: " << argv[0] << " " << std::endl; - return 1; - } - diagnostic_graph_aggregator::dump_tree_path(argv[1]); -} diff --git a/system/diagnostic_graph_aggregator/src/tool/tree.cpp b/system/diagnostic_graph_aggregator/src/tool/tree.cpp new file mode 100644 index 0000000000000..9dbbc539b3b91 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/tree.cpp @@ -0,0 +1,69 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/loader.hpp" + +#include + +namespace diagnostic_graph_aggregator +{ + +void dump_node(const GraphNode * node, const std::string & indent = "", bool root = true) +{ + const auto path = node->path.empty() ? "" : node->path + " "; + const auto type = "(" + node->type + ")"; + std::cout << indent << "- " << path << type << std::endl; + + if (root || node->parents.size() == 1) { + for (const auto child : node->children) { + dump_node(child, indent + " ", false); + } + } +} + +void dump_root(const std::string & path) +{ + const auto graph = load_graph_nodes(path); + + std::cout << "===== root nodes =================================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() == 0 && node->children.size() != 0) { + dump_node(node); + } + } + std::cout << "===== intermediate nodes =========================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() >= 2) { + dump_node(node); + } + } + + std::cout << "===== isolated nodes =============================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() == 0 && node->children.size() == 0) { + dump_node(node); + } + } +} + +} // namespace diagnostic_graph_aggregator + +int main(int argc, char ** argv) +{ + if (argc != 2) { + std::cerr << "usage: tree " << std::endl; + return 1; + } + diagnostic_graph_aggregator::dump_root(argv[1]); +} diff --git a/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp b/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp new file mode 100644 index 0000000000000..a2e6ce8b85334 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp @@ -0,0 +1,57 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "loader.hpp" + +#include +#include + +namespace diagnostic_graph_aggregator +{ + +GraphRoot load_graph_nodes(const std::string & path) +{ + GraphRoot result; + { + std::unordered_map mapping; + Graph graph; + graph.init(path); + + for (const auto & node : graph.nodes()) { + auto data = std::make_unique(); + data->path = node->path(); + data->type = node->type(); + mapping[node] = std::move(data); + } + + for (const auto & [node, data] : mapping) { + for (const auto & link : node->children()) { + const auto parent = data.get(); + const auto child = mapping.at(link).get(); + child->parents.push_back(parent); + parent->children.push_back(child); + } + } + + for (auto & [node, data] : mapping) { + result.owner.push_back(std::move(data)); + } + for (const auto & node : result.owner) { + result.nodes.push_back(node.get()); + } + } + return result; +} + +} // namespace diagnostic_graph_aggregator diff --git a/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp b/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp new file mode 100644 index 0000000000000..70e01ec2a77b4 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp @@ -0,0 +1,48 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TOOL__UTILS__LOADER_HPP_ +#define TOOL__UTILS__LOADER_HPP_ + +#include "graph/graph.hpp" +#include "graph/types.hpp" +#include "graph/units.hpp" + +#include +#include +#include + +namespace diagnostic_graph_aggregator +{ + +struct GraphNode +{ + using UniquePtr = std::unique_ptr; + std::string type; + std::string path; + std::vector children; + std::vector parents; +}; + +struct GraphRoot +{ + std::vector owner; + std::vector nodes; +}; + +GraphRoot load_graph_nodes(const std::string & path); + +} // namespace diagnostic_graph_aggregator + +#endif // TOOL__UTILS__LOADER_HPP_