21#include <unordered_map>
24#include <boost/filesystem.hpp>
26#include "absl/strings/match.h"
27#include "absl/strings/str_cat.h"
28#include "absl/strings/str_split.h"
31#include "gflags/gflags.h"
37 "Name of the resource monitor.");
40 "Topic status checking interval (s).");
47bool GetPIDByCmdLine(
const std::string& process_dag_path,
int* pid) {
48 const std::string system_proc_path =
"/proc";
49 const std::string proc_cmdline_path =
"/cmdline";
52 for (
const auto& dir_name : dirs) {
53 if (!std::all_of(dir_name.begin(), dir_name.end(), isdigit)) {
56 *pid = std::stoi(dir_name);
57 std::ifstream cmdline_file(
58 absl::StrCat(system_proc_path,
"/", dir_name, proc_cmdline_path));
59 std::getline(cmdline_file, cmd_line);
60 if (absl::StrContains(cmd_line, process_dag_path)) {
67std::vector<std::string> GetStatsLines(
const std::string& stat_file,
68 const int line_count) {
69 std::vector<std::string> stats_lines;
70 std::ifstream buffer(stat_file);
71 for (
int line_num = 0; line_num < line_count; ++line_num) {
73 std::getline(buffer, line);
77 stats_lines.push_back(line);
82float GetMemoryUsage(
const int pid,
const std::string& process_name) {
83 const std::string memory_stat_file = absl::StrCat(
"/proc/", pid,
"/statm");
84 const uint32_t page_size_kb = (sysconf(_SC_PAGE_SIZE) >> 10);
85 const int resident_idx = 1, gb_2_kb = (1 << 20);
86 constexpr static int kMemoryInfo = 0;
88 const auto stat_lines = GetStatsLines(memory_stat_file, kMemoryInfo + 1);
89 if (stat_lines.size() <= kMemoryInfo) {
90 AERROR <<
"failed to load contents from " << memory_stat_file;
93 const std::vector<std::string> stats =
94 absl::StrSplit(stat_lines[kMemoryInfo],
' ', absl::SkipWhitespace());
95 if (stats.size() <= resident_idx) {
96 AERROR <<
"failed to get memory info for process " << process_name;
99 return static_cast<float>(std::stoll(stats[resident_idx]) * page_size_kb) /
103float GetCPUUsage(
const int pid,
const std::string& process_name,
104 std::unordered_map<std::string, uint64_t>* prev_jiffies_map) {
105 const std::string cpu_stat_file = absl::StrCat(
"/proc/", pid,
"/stat");
106 const int hertz = sysconf(_SC_CLK_TCK);
107 const int utime = 13, stime = 14, cutime = 15, cstime = 16;
108 constexpr static int kCpuInfo = 0;
110 const auto stat_lines = GetStatsLines(cpu_stat_file, kCpuInfo + 1);
111 if (stat_lines.size() <= kCpuInfo) {
112 AERROR <<
"failed to load contents from " << cpu_stat_file;
115 const std::vector<std::string> stats =
116 absl::StrSplit(stat_lines[kCpuInfo],
' ', absl::SkipWhitespace());
117 if (stats.size() <= cstime) {
118 AERROR <<
"failed to get CPU info for process " << process_name;
121 const uint64_t jiffies = std::stoll(stats[utime]) + std::stoll(stats[stime]) +
122 std::stoll(stats[cutime]) +
123 std::stoll(stats[cstime]);
124 const uint64_t prev_jiffies = (*prev_jiffies_map)[process_name];
125 (*prev_jiffies_map)[process_name] = jiffies;
126 if (prev_jiffies == 0) {
129 return 100.f * (
static_cast<float>(jiffies - prev_jiffies) / hertz /
130 static_cast<float>(FLAGS_resource_monitor_interval));
133uint64_t GetSystemMemoryValueFromLine(std::string stat_line) {
134 constexpr static int kMemoryValueIdx = 1;
135 const std::vector<std::string> stats =
136 absl::StrSplit(stat_line,
' ', absl::SkipWhitespace());
137 if (stats.size() <= kMemoryValueIdx) {
138 AERROR <<
"failed to parse memory from line " << stat_line;
141 return std::stoll(stats[kMemoryValueIdx]);
144float GetSystemMemoryUsage() {
145 const std::string system_mem_stat_file =
"/proc/meminfo";
146 const int mem_total = 0, mem_free = 1, buffers = 3, cached = 4,
147 swap_total = 14, swap_free = 15, slab = 21;
148 const auto stat_lines = GetStatsLines(system_mem_stat_file, slab + 1);
149 if (stat_lines.size() <= slab) {
150 AERROR <<
"failed to load contents from " << system_mem_stat_file;
153 const auto total_memory =
154 GetSystemMemoryValueFromLine(stat_lines[mem_total]) +
155 GetSystemMemoryValueFromLine(stat_lines[swap_total]);
156 int64_t used_memory = total_memory;
157 for (
int cur_line = mem_free; cur_line <= slab; ++cur_line) {
158 if (cur_line == mem_free || cur_line == buffers || cur_line == cached ||
159 cur_line == swap_free || cur_line == slab) {
160 used_memory -= GetSystemMemoryValueFromLine(stat_lines[cur_line]);
163 return 100.f * (
static_cast<float>(used_memory) / total_memory);
166float GetSystemCPUUsage() {
167 const std::string system_cpu_stat_file =
"/proc/stat";
168 const int users = 1, system = 3, total = 7;
169 constexpr static int kSystemCpuInfo = 0;
170 static uint64_t prev_jiffies = 0, prev_work_jiffies = 0;
171 const auto stat_lines =
172 GetStatsLines(system_cpu_stat_file, kSystemCpuInfo + 1);
173 if (stat_lines.size() <= kSystemCpuInfo) {
174 AERROR <<
"failed to load contents from " << system_cpu_stat_file;
177 const std::vector<std::string> jiffies_stats =
178 absl::StrSplit(stat_lines[kSystemCpuInfo],
' ', absl::SkipWhitespace());
179 if (jiffies_stats.size() <= total) {
180 AERROR <<
"failed to get system CPU info from " << system_cpu_stat_file;
183 uint64_t jiffies = 0, work_jiffies = 0;
184 for (
int cur_stat = users; cur_stat <= total; ++cur_stat) {
185 const auto cur_stat_value = std::stoll(jiffies_stats[cur_stat]);
186 jiffies += cur_stat_value;
187 if (cur_stat <= system) {
188 work_jiffies += cur_stat_value;
191 const uint64_t tmp_prev_jiffies = prev_jiffies;
192 const uint64_t tmp_prev_work_jiffies = prev_work_jiffies;
193 prev_jiffies = jiffies;
194 prev_work_jiffies = work_jiffies;
195 if (tmp_prev_jiffies == 0) {
198 return 100.f * (
static_cast<float>(work_jiffies - tmp_prev_work_jiffies) /
199 (jiffies - tmp_prev_jiffies));
202float GetSystemDiskload(
const std::string& device_name) {
203 const std::string disks_stat_file =
"/proc/diskstats";
204 const int device = 2, in_out_ms = 12;
205 const int seconds_to_ms = 1000;
206 constexpr static int kDiskInfo = 128;
207 static uint64_t prev_disk_stats = 0;
209 const auto stat_lines = GetStatsLines(disks_stat_file, kDiskInfo);
210 uint64_t disk_stats = 0;
211 for (
const auto& line : stat_lines) {
212 const std::vector<std::string> stats =
213 absl::StrSplit(line,
' ', absl::SkipWhitespace());
214 if (stats[
device] == device_name) {
215 disk_stats = std::stoll(stats[in_out_ms]);
219 const uint64_t tmp_prev_disk_stats = prev_disk_stats;
220 prev_disk_stats = disk_stats;
221 if (tmp_prev_disk_stats == 0) {
225 (
static_cast<float>(disk_stats - tmp_prev_disk_stats) /
226 static_cast<float>(FLAGS_resource_monitor_interval * seconds_to_ms));
233 FLAGS_resource_monitor_interval) {}
236 auto manager = MonitorManager::Instance();
237 const auto& mode = manager->GetHMIMode();
238 auto* components = manager->GetStatus()->mutable_components();
240 for (
const auto& iter : mode.monitored_components()) {
241 const std::string& name = iter.first;
242 const auto& config = iter.second;
243 if (config.has_resource()) {
244 UpdateStatus(config.resource(),
245 components->at(name).mutable_resource_status());
248 auto* global_components = manager->GetStatus()->mutable_global_components();
249 for (
const auto& iter : mode.global_components()) {
250 const std::string& name = iter.first;
251 const auto& config = iter.second;
252 if (config.has_resource()) {
253 UpdateStatus(config.resource(),
254 global_components->at(name).mutable_resource_status());
259void ResourceMonitor::UpdateStatus(
261 ComponentStatus* status) {
262 status->clear_status();
263 CheckDiskSpace(config, status);
264 CheckCPUUsage(config, status);
265 CheckMemoryUsage(config, status);
266 CheckDiskLoads(config, status);
270void ResourceMonitor::CheckDiskSpace(
272 ComponentStatus* status) {
274 for (
const auto& disk_space : config.disk_spaces()) {
275 for (
const auto& path : cyber::common::Glob(disk_space.path())) {
276 const auto space = boost::filesystem::space(path);
277 const int available_gb =
static_cast<int>(space.available >> 30);
278 if (available_gb < disk_space.insufficient_space_error()) {
279 const std::string err =
280 absl::StrCat(path,
" has insufficient space: ", available_gb,
281 "GB < ", disk_space.insufficient_space_error());
283 }
else if (available_gb < disk_space.insufficient_space_warning()) {
284 const std::string err =
285 absl::StrCat(path,
" has insufficient space: ", available_gb,
286 "GB < ", disk_space.insufficient_space_warning());
293void ResourceMonitor::CheckCPUUsage(
295 ComponentStatus* status) {
296 for (
const auto& cpu_usage : config.cpu_usages()) {
297 const auto process_dag_path = cpu_usage.process_dag_path();
298 float cpu_usage_value = 0.f;
299 if (process_dag_path.empty()) {
300 cpu_usage_value = GetSystemCPUUsage();
303 if (GetPIDByCmdLine(process_dag_path, &pid)) {
304 static std::unordered_map<std::string, uint64_t> prev_jiffies_map;
305 if (prev_jiffies_map.find(process_dag_path) == prev_jiffies_map.end()) {
306 prev_jiffies_map[process_dag_path] = 0;
308 cpu_usage_value = GetCPUUsage(pid, process_dag_path, &prev_jiffies_map);
311 const auto high_cpu_warning = cpu_usage.high_cpu_usage_warning();
312 const auto high_cpu_error = cpu_usage.high_cpu_usage_error();
313 if (cpu_usage_value > high_cpu_error) {
314 const std::string
err = absl::StrCat(
315 process_dag_path,
" has high cpu usage: ", cpu_usage_value,
"% > ",
316 high_cpu_error,
"%");
318 }
else if (cpu_usage_value > high_cpu_warning) {
319 const std::string warn = absl::StrCat(
320 process_dag_path,
" has high cpu usage: ", cpu_usage_value,
"% > ",
321 high_cpu_warning,
"%");
327void ResourceMonitor::CheckMemoryUsage(
329 ComponentStatus* status) {
330 for (
const auto& memory_usage : config.memory_usages()) {
331 const auto process_dag_path = memory_usage.process_dag_path();
332 float memory_usage_value = 0.f;
333 if (process_dag_path.empty()) {
334 memory_usage_value = GetSystemMemoryUsage();
337 if (GetPIDByCmdLine(process_dag_path, &pid)) {
338 memory_usage_value = GetMemoryUsage(pid, process_dag_path);
341 const auto high_memory_warning = memory_usage.high_memory_usage_warning();
342 const auto high_memory_error = memory_usage.high_memory_usage_error();
343 if (memory_usage_value >
static_cast<float>(high_memory_error)) {
344 const std::string
err = absl::StrCat(
345 process_dag_path,
" has high memory usage: ", memory_usage_value,
346 " > ", high_memory_error);
348 }
else if (memory_usage_value >
static_cast<float>(high_memory_warning)) {
349 const std::string warn = absl::StrCat(
350 process_dag_path,
" has high memory usage: ", memory_usage_value,
351 " > ", high_memory_warning);
357void ResourceMonitor::CheckDiskLoads(
359 ComponentStatus* status) {
360 for (
const auto& disk_load : config.disk_load_usages()) {
361 const auto disk_load_value = GetSystemDiskload(disk_load.device_name());
362 const auto high_disk_load_warning = disk_load.high_disk_load_warning();
363 const auto high_disk_load_error = disk_load.high_disk_load_error();
364 if (disk_load_value >
static_cast<float>(high_disk_load_error)) {
365 const std::string
err = absl::StrCat(
366 disk_load.device_name(),
" has high disk load: ", disk_load_value,
367 " > ", high_disk_load_error);
369 }
else if (disk_load_value >
static_cast<float>(high_disk_load_warning)) {
370 const std::string warn = absl::StrCat(
371 disk_load.device_name(),
" has high disk load: ", disk_load_value,
372 " > ", high_disk_load_warning);
void RunOnce(const double current_time) override
static void EscalateStatus(const ComponentStatus::Status new_status, const std::string &message, ComponentStatus *current_status)
first check imutoantoffset saved in device
std::vector< std::string > ListSubPaths(const std::string &directory_path, const unsigned char d_type)
List sub-paths.
DEFINE_double(resource_monitor_interval, 5, "Topic status checking interval (s).")
DEFINE_string(resource_monitor_name, "ResourceMonitor", "Name of the resource monitor.")