blob: 8698bc19d2274f38eb83ad27b01d6897d78c67de [file] [log] [blame]
James Kuszmaul418fd062022-03-22 15:22:27 -07001#ifndef AOS_UTIL_TOP_H_
2#define AOS_UTIL_TOP_H_
3
4#include <map>
5#include <string>
6
7#include "aos/containers/ring_buffer.h"
8#include "aos/events/event_loop.h"
9#include "aos/util/process_info_generated.h"
10
11namespace aos::util {
12
13// ProcStat is a struct to hold all the fields available in /proc/[pid]/stat.
14// Currently we only use a small subset of the feilds. See man 5 proc for
15// details on what the fields are--these are in the same order as they appear in
16// the stat file.
17//
18// Things are signed or unsigned based on whether they are listed
19// as signed/unsigned in man 5 proc. We just make everything 64 bits wide
20// because otherwise we have to write out way too many casts everywhere.
21struct ProcStat {
22 int pid;
23 std::string name;
24 char state;
25 int64_t parent_pid;
26 int64_t group_id;
27 int64_t session_id;
28 int64_t tty;
29 int64_t tpgid;
30 uint64_t kernel_flags;
31 uint64_t minor_faults;
32 uint64_t children_minor_faults;
33 uint64_t major_faults;
34 uint64_t children_major_faults;
35 uint64_t user_mode_ticks;
36 uint64_t kernel_mode_ticks;
37 int64_t children_user_mode_ticks;
38 int64_t children_kernel_mode_ticks;
39 int64_t priority;
40 int64_t nice;
41 int64_t num_threads;
42 int64_t itrealvalue; // always zero.
43 uint64_t start_time_ticks;
44 uint64_t virtual_memory_size;
45 // Number of pages in real memory.
46 int64_t resident_set_size;
47 uint64_t rss_soft_limit;
48 uint64_t start_code_address;
49 uint64_t end_code_address;
50 uint64_t start_stack_address;
51 uint64_t stack_pointer;
52 uint64_t instruction_pointer;
53 uint64_t signal_bitmask;
54 uint64_t blocked_signals;
55 uint64_t ignored_signals;
56 uint64_t caught_signals;
57 uint64_t wchan;
58 // swap_pages fields are not maintained.
59 uint64_t swap_pages;
60 uint64_t children_swap_pages;
61 int64_t exit_signal;
62 // CPU number last exitted on.
63 int64_t processor;
64 // Zero for non-realtime processes.
65 uint64_t rt_priority;
66 uint64_t scheduling_policy;
67 // Aggregated block I/O delay.
68 uint64_t block_io_delay_ticks;
69 uint64_t guest_ticks;
70 uint64_t children_guest_ticks;
71 uint64_t start_data_address;
72 uint64_t end_data_address;
73 uint64_t start_brk_address;
74 uint64_t start_arg_address;
75 uint64_t end_arg_address;
76 uint64_t start_env_address;
77 uint64_t end_env_address;
78 int64_t exit_code;
79};
80
81// Retrieves the stats for a particular process (note that there also exists a
82// /proc/[pid]/task/[tid]/stat with the same format for per-thread information;
83// we currently do not read that).
84// Returns nullopt if unable to read/parse the file.
85std::optional<ProcStat> ReadProcStat(int pid);
86
87// This class provides a basic utility for retrieving general performance
88// information on running processes (named after the top utility). It can either
89// be used to directly get information on individual processes (via
90// set_track_pids()) or used to track a list of the top N processes with the
91// highest CPU usage.
92// Note that this currently relies on sampling processes in /proc every second
93// and using the differences between the two readings to calculate CPU usage.
94// For crash-looping processees or other situations with highly variable or
95// extremely short-lived loads, this may do a poor job of capturing information.
96class Top {
97 public:
Austin Schuh979d4772022-12-30 14:50:41 -080098 // A snapshot of the resource usage of a process.
99 struct Reading {
100 aos::monotonic_clock::time_point reading_time;
101 std::chrono::nanoseconds total_run_time;
102 // Memory usage in bytes.
103 uint64_t memory_usage;
104 };
105
106 // All the information we have about a process.
107 struct ProcessReadings {
108 std::string name;
109 aos::monotonic_clock::time_point start_time;
110 // CPU usage is based on the past two readings.
111 double cpu_percent;
112 // True if this is a kernel thread, false if this is a userspace thread.
113 bool kthread;
114 // Last 2 readings
115 aos::RingBuffer<Reading, 2> readings;
116 };
117
James Kuszmaul418fd062022-03-22 15:22:27 -0700118 Top(aos::EventLoop *event_loop);
119
120 // Set whether to track all the top processes (this will result in us having
121 // to track every single process on the system, so that we can sort them).
122 void set_track_top_processes(bool track_all) { track_all_ = track_all; }
123
124 // Specify a set of individual processes to track statistics for.
125 // This can be changed at run-time, although it may take up to kSamplePeriod
126 // to have full statistics on all the relevant processes, since we need at
127 // least two samples to estimate CPU usage.
128 void set_track_pids(const std::set<pid_t> &pids) { pids_to_track_ = pids; }
129
130 // Retrieve statistics for the specified process. Will return the null offset
131 // of no such pid is being tracked.
132 flatbuffers::Offset<ProcessInfo> InfoForProcess(
133 flatbuffers::FlatBufferBuilder *fbb, pid_t pid);
134
135 // Returns information on up to n processes, sorted by CPU usage.
136 flatbuffers::Offset<TopProcessesFbs> TopProcesses(
137 flatbuffers::FlatBufferBuilder *fbb, int n);
138
Austin Schuh979d4772022-12-30 14:50:41 -0800139 const std::map<pid_t, ProcessReadings> &readings() const { return readings_; }
140
James Kuszmaul418fd062022-03-22 15:22:27 -0700141 private:
142 // Rate at which to sample /proc/[pid]/stat.
143 static constexpr std::chrono::seconds kSamplePeriod{1};
144
James Kuszmaul418fd062022-03-22 15:22:27 -0700145 std::chrono::nanoseconds TotalProcessTime(const ProcStat &proc_stat);
146 aos::monotonic_clock::time_point ProcessStartTime(const ProcStat &proc_stat);
147 uint64_t RealMemoryUsage(const ProcStat &proc_stat);
148 void UpdateReadings();
149
150 aos::EventLoop *event_loop_;
151
152 // Length of a clock tick (used to convert from raw numbers in /proc to actual
153 // times).
154 const std::chrono::nanoseconds clock_tick_;
155 // Page size, in bytes, on the current system.
156 const long page_size_;
157
158 std::set<pid_t> pids_to_track_;
159 bool track_all_ = false;
160
161 std::map<pid_t, ProcessReadings> readings_;
162};
163
164} // namespace aos::util
165#endif // AOS_UTIL_TOP_H_