Apollo 10.0
自动驾驶开放平台
resource_monitor.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <algorithm>
20#include <string>
21#include <unordered_map>
22#include <vector>
23
24#include <boost/filesystem.hpp>
25
26#include "absl/strings/match.h"
27#include "absl/strings/str_cat.h"
28#include "absl/strings/str_split.h"
29#include "cyber/common/file.h"
30#include "cyber/common/log.h"
31#include "gflags/gflags.h"
35
36DEFINE_string(resource_monitor_name, "ResourceMonitor",
37 "Name of the resource monitor.");
38
39DEFINE_double(resource_monitor_interval, 5,
40 "Topic status checking interval (s).");
41
42namespace apollo {
43namespace monitor {
44
45namespace {
46
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";
50 const auto dirs = cyber::common::ListSubPaths(system_proc_path);
51 std::string cmd_line;
52 for (const auto& dir_name : dirs) {
53 if (!std::all_of(dir_name.begin(), dir_name.end(), isdigit)) {
54 continue;
55 }
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)) {
61 return true;
62 }
63 }
64 return false;
65}
66
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) {
72 std::string line;
73 std::getline(buffer, line);
74 if (line.empty()) {
75 break;
76 }
77 stats_lines.push_back(line);
78 }
79 return stats_lines;
80}
81
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;
87
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;
91 return 0.f;
92 }
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;
97 return 0.f;
98 }
99 return static_cast<float>(std::stoll(stats[resident_idx]) * page_size_kb) /
100 gb_2_kb;
101}
102
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;
109
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;
113 return 0.f;
114 }
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;
119 return 0.f;
120 }
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) {
127 return 0.f;
128 }
129 return 100.f * (static_cast<float>(jiffies - prev_jiffies) / hertz /
130 static_cast<float>(FLAGS_resource_monitor_interval));
131}
132
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;
139 return 0;
140 }
141 return std::stoll(stats[kMemoryValueIdx]);
142}
143
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;
151 return 0.f;
152 }
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]);
161 }
162 }
163 return 100.f * (static_cast<float>(used_memory) / total_memory);
164}
165
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;
175 return 0.f;
176 }
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;
181 return 0.f;
182 }
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;
189 }
190 }
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) {
196 return 0.f;
197 }
198 return 100.f * (static_cast<float>(work_jiffies - tmp_prev_work_jiffies) /
199 (jiffies - tmp_prev_jiffies));
200}
201
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;
208
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]);
216 break;
217 }
218 }
219 const uint64_t tmp_prev_disk_stats = prev_disk_stats;
220 prev_disk_stats = disk_stats;
221 if (tmp_prev_disk_stats == 0) {
222 return 0.f;
223 }
224 return 100.f *
225 (static_cast<float>(disk_stats - tmp_prev_disk_stats) /
226 static_cast<float>(FLAGS_resource_monitor_interval * seconds_to_ms));
227}
228
229} // namespace
230
232 : RecurrentRunner(FLAGS_resource_monitor_name,
233 FLAGS_resource_monitor_interval) {}
234
235void ResourceMonitor::RunOnce(const double current_time) {
236 auto manager = MonitorManager::Instance();
237 const auto& mode = manager->GetHMIMode();
238 auto* components = manager->GetStatus()->mutable_components();
239
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());
246 }
247 }
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());
255 }
256 }
257}
258
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);
267 SummaryMonitor::EscalateStatus(ComponentStatus::OK, "", status);
268}
269
270void ResourceMonitor::CheckDiskSpace(
272 ComponentStatus* status) {
273 // Monitor available disk space.
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());
282 SummaryMonitor::EscalateStatus(ComponentStatus::ERROR, err, status);
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());
287 SummaryMonitor::EscalateStatus(ComponentStatus::WARN, err, status);
288 }
289 }
290 }
291}
292
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();
301 } else {
302 int pid = 0;
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;
307 }
308 cpu_usage_value = GetCPUUsage(pid, process_dag_path, &prev_jiffies_map);
309 }
310 }
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, "%");
317 SummaryMonitor::EscalateStatus(ComponentStatus::ERROR, err, status);
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, "%");
322 SummaryMonitor::EscalateStatus(ComponentStatus::WARN, warn, status);
323 }
324 }
325}
326
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();
335 } else {
336 int pid = 0;
337 if (GetPIDByCmdLine(process_dag_path, &pid)) {
338 memory_usage_value = GetMemoryUsage(pid, process_dag_path);
339 }
340 }
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);
347 SummaryMonitor::EscalateStatus(ComponentStatus::ERROR, err, status);
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);
352 SummaryMonitor::EscalateStatus(ComponentStatus::WARN, warn, status);
353 }
354 }
355}
356
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);
368 SummaryMonitor::EscalateStatus(ComponentStatus::ERROR, err, status);
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);
373 SummaryMonitor::EscalateStatus(ComponentStatus::WARN, warn, status);
374 }
375 }
376}
377
378} // namespace monitor
379} // namespace apollo
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
Definition readme.txt:2
#define AERROR
Definition log.h:44
Some map util functions.
std::vector< std::string > ListSubPaths(const std::string &directory_path, const unsigned char d_type)
List sub-paths.
Definition file.cc:353
class register implement
Definition arena_queue.h:37
DEFINE_double(resource_monitor_interval, 5, "Topic status checking interval (s).")
DEFINE_string(resource_monitor_name, "ResourceMonitor", "Name of the resource monitor.")