Skip to content

Commit 87955de

Browse files
authored
Merge pull request #14 from tier4/validation_hardware
feat: validation of hardware information
2 parents bf44268 + 37fce24 commit 87955de

File tree

5 files changed

+135
-5
lines changed

5 files changed

+135
-5
lines changed

cie_thread_configurator/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ if(BUILD_TESTING)
2222
ament_lint_auto_find_test_dependencies()
2323
endif()
2424

25+
add_library(thread_configurator SHARED src/util.cpp)
26+
ament_target_dependencies(thread_configurator rclcpp cie_config_msgs)
27+
2528
add_executable(thread_configurator_node src/main.cpp src/thread_configurator_node.cpp src/prerun_node.cpp)
2629
ament_target_dependencies(thread_configurator_node rclcpp cie_config_msgs)
27-
target_link_libraries(thread_configurator_node yaml-cpp)
30+
target_link_libraries(thread_configurator_node yaml-cpp thread_configurator)
2831

2932
target_include_directories(thread_configurator_node PRIVATE
3033
${CMAKE_CURRENT_SOURCE_DIR}/include
3134
)
3235

33-
add_library(thread_configurator SHARED src/util.cpp)
34-
ament_target_dependencies(thread_configurator rclcpp cie_config_msgs)
35-
3636
target_include_directories(thread_configurator PUBLIC
3737
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
3838
$<INSTALL_INTERFACE:include>

cie_thread_configurator/include/cie_thread_configurator/cie_thread_configurator.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "rclcpp/rclcpp.hpp"
4+
#include <map>
45
#include <memory>
56
#include <string>
67

@@ -26,4 +27,7 @@ void publish_callback_group_info(
2627
&publisher,
2728
int64_t tid, const std::string &callback_group_id);
2829

30+
// Get hardware information from lscpu command
31+
std::map<std::string, std::string> get_hardware_info();
32+
2933
} // namespace cie_thread_configurator

cie_thread_configurator/src/main.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,73 @@
55
#include "rclcpp/rclcpp.hpp"
66
#include "yaml-cpp/yaml.h"
77

8+
#include "cie_thread_configurator/cie_thread_configurator.hpp"
89
#include "cie_thread_configurator/prerun_node.hpp"
910
#include "cie_thread_configurator/thread_configurator_node.hpp"
1011

12+
static bool validate_hardware_info(const YAML::Node &yaml) {
13+
YAML::Node yaml_hw_info = yaml["hardware_info"];
14+
auto current_hw_info = cie_thread_configurator::get_hardware_info();
15+
16+
bool all_match = true;
17+
std::vector<std::string> mismatches;
18+
19+
for (const auto &[key, current_value] : current_hw_info) {
20+
if (!yaml_hw_info[key]) {
21+
continue;
22+
}
23+
24+
std::string yaml_value = yaml_hw_info[key].as<std::string>();
25+
if (yaml_value != current_value) {
26+
all_match = false;
27+
mismatches.push_back(key + ": expected '" + yaml_value + "', got '" +
28+
current_value + "'");
29+
}
30+
}
31+
32+
// Report results
33+
if (!all_match) {
34+
std::cerr << "[ERROR] Hardware validation failed with the following "
35+
"mismatches:"
36+
<< std::endl;
37+
for (const auto &mismatch : mismatches) {
38+
std::cerr << " - " << mismatch << std::endl;
39+
}
40+
} else {
41+
std::cout << "[INFO] Hardware validation successful. Configuration matches "
42+
"this system."
43+
<< std::endl;
44+
}
45+
46+
return all_match;
47+
}
48+
1149
static void spin_thread_configurator_node(const std::string &config_filename) {
1250
YAML::Node config;
1351

1452
try {
1553
config = YAML::LoadFile(config_filename);
16-
std::cout << config << std::endl;
1754
} catch (const std::exception &e) {
1855
std::cerr << "Error reading the YAML file: " << e.what() << std::endl;
1956
return;
2057
}
2158

59+
// Validate hardware information if present in YAML
60+
if (config["hardware_info"]) {
61+
if (!validate_hardware_info(config)) {
62+
std::cerr << "[ERROR] Hardware information validation failed. The "
63+
"configuration may not match this system."
64+
<< std::endl;
65+
return;
66+
}
67+
} else {
68+
std::cout << "[WARN] No hardware_info section found in configuration file. "
69+
"Skipping hardware validation."
70+
<< std::endl;
71+
}
72+
73+
std::cout << config["callback_groups"] << std::endl;
74+
2275
auto node = std::make_shared<ThreadConfiguratorNode>(config);
2376
auto executor = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
2477

cie_thread_configurator/src/prerun_node.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "rclcpp/rclcpp.hpp"
88
#include "yaml-cpp/yaml.h"
99

10+
#include "cie_thread_configurator/cie_thread_configurator.hpp"
1011
#include "cie_thread_configurator/prerun_node.hpp"
1112

1213
PrerunNode::PrerunNode() : Node("prerun_node") {
@@ -32,6 +33,20 @@ void PrerunNode::dump_yaml_config(std::filesystem::path path) {
3233
YAML::Emitter out;
3334

3435
out << YAML::BeginMap;
36+
37+
// Add hardware information section
38+
out << YAML::Key << "hardware_info";
39+
out << YAML::Value << YAML::BeginMap;
40+
41+
auto hw_info = cie_thread_configurator::get_hardware_info();
42+
43+
for (const auto &[key, value] : hw_info) {
44+
out << YAML::Key << key << YAML::Value << value;
45+
}
46+
47+
out << YAML::EndMap;
48+
49+
// Add callback_groups section
3550
out << YAML::Key << "callback_groups";
3651
out << YAML::Value << YAML::BeginSeq;
3752

cie_thread_configurator/src/util.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <array>
12
#include <chrono>
23
#include <functional>
34
#include <memory>
@@ -85,4 +86,61 @@ void publish_callback_group_info(
8586
rclcpp::sleep_for(std::chrono::milliseconds(500));
8687
}
8788

89+
std::map<std::string, std::string> get_hardware_info() {
90+
std::map<std::string, std::string> hw_info;
91+
92+
// Execute lscpu command and capture output
93+
std::array<char, 128> buffer;
94+
std::string result;
95+
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("/usr/bin/lscpu", "r"),
96+
pclose);
97+
98+
if (!pipe) {
99+
return hw_info;
100+
}
101+
102+
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
103+
result += buffer.data();
104+
}
105+
106+
// Parse lscpu output
107+
std::istringstream iss(result);
108+
std::string line;
109+
110+
while (std::getline(iss, line)) {
111+
size_t colon_pos = line.find(':');
112+
if (colon_pos == std::string::npos)
113+
continue;
114+
115+
std::string key = line.substr(0, colon_pos);
116+
std::string value = line.substr(colon_pos + 1);
117+
118+
// Trim leading/trailing whitespace from value
119+
size_t start = value.find_first_not_of(" \t");
120+
size_t end = value.find_last_not_of(" \t\r\n");
121+
if (start != std::string::npos && end != std::string::npos) {
122+
value = value.substr(start, end - start + 1);
123+
}
124+
125+
// Store relevant hardware information
126+
if (key == "Model name") {
127+
hw_info["model_name"] = value;
128+
} else if (key == "CPU family") {
129+
hw_info["cpu_family"] = value;
130+
} else if (key == "Model") {
131+
hw_info["model"] = value;
132+
} else if (key == "Thread(s) per core") {
133+
hw_info["threads_per_core"] = value;
134+
} else if (key == "Frequency boost") {
135+
hw_info["frequency_boost"] = value;
136+
} else if (key == "CPU max MHz") {
137+
hw_info["cpu_max_mhz"] = value;
138+
} else if (key == "CPU min MHz") {
139+
hw_info["cpu_min_mhz"] = value;
140+
}
141+
}
142+
143+
return hw_info;
144+
}
145+
88146
} // namespace cie_thread_configurator

0 commit comments

Comments
 (0)