xref: /aosp_15_r20/system/extras/iotop/taskstats.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker // Copyright (C) 2015 The Android Open Source Project
2*288bf522SAndroid Build Coastguard Worker //
3*288bf522SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*288bf522SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*288bf522SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*288bf522SAndroid Build Coastguard Worker //
7*288bf522SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*288bf522SAndroid Build Coastguard Worker //
9*288bf522SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*288bf522SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*288bf522SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*288bf522SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*288bf522SAndroid Build Coastguard Worker // limitations under the License.
14*288bf522SAndroid Build Coastguard Worker 
15*288bf522SAndroid Build Coastguard Worker #include <linux/taskstats.h>
16*288bf522SAndroid Build Coastguard Worker #include <netlink/genl/ctrl.h>
17*288bf522SAndroid Build Coastguard Worker #include <netlink/genl/genl.h>
18*288bf522SAndroid Build Coastguard Worker #include <netlink/socket.h>
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <algorithm>
21*288bf522SAndroid Build Coastguard Worker #include <memory>
22*288bf522SAndroid Build Coastguard Worker 
23*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker #include "taskstats.h"
26*288bf522SAndroid Build Coastguard Worker 
TaskstatsSocket()27*288bf522SAndroid Build Coastguard Worker TaskstatsSocket::TaskstatsSocket() : nl_(nullptr, nl_socket_free), family_id_(0) {}
28*288bf522SAndroid Build Coastguard Worker 
Open()29*288bf522SAndroid Build Coastguard Worker bool TaskstatsSocket::Open() {
30*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<nl_sock, decltype(&nl_socket_free)> nl(nl_socket_alloc(), nl_socket_free);
31*288bf522SAndroid Build Coastguard Worker   if (!nl.get()) {
32*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to allocate netlink socket";
33*288bf522SAndroid Build Coastguard Worker     return false;
34*288bf522SAndroid Build Coastguard Worker   }
35*288bf522SAndroid Build Coastguard Worker 
36*288bf522SAndroid Build Coastguard Worker   int ret = genl_connect(nl.get());
37*288bf522SAndroid Build Coastguard Worker   if (ret < 0) {
38*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << nl_geterror(ret) << std::endl << "Unable to open netlink socket (are you root?)";
39*288bf522SAndroid Build Coastguard Worker     return false;
40*288bf522SAndroid Build Coastguard Worker   }
41*288bf522SAndroid Build Coastguard Worker 
42*288bf522SAndroid Build Coastguard Worker   int family_id = genl_ctrl_resolve(nl.get(), TASKSTATS_GENL_NAME);
43*288bf522SAndroid Build Coastguard Worker   if (family_id < 0) {
44*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << nl_geterror(family_id) << std::endl
45*288bf522SAndroid Build Coastguard Worker                << "Unable to determine taskstats family id (does your kernel support taskstats?)";
46*288bf522SAndroid Build Coastguard Worker     return false;
47*288bf522SAndroid Build Coastguard Worker   }
48*288bf522SAndroid Build Coastguard Worker 
49*288bf522SAndroid Build Coastguard Worker   nl_ = std::move(nl);
50*288bf522SAndroid Build Coastguard Worker   family_id_ = family_id;
51*288bf522SAndroid Build Coastguard Worker 
52*288bf522SAndroid Build Coastguard Worker   return true;
53*288bf522SAndroid Build Coastguard Worker }
54*288bf522SAndroid Build Coastguard Worker 
Close()55*288bf522SAndroid Build Coastguard Worker void TaskstatsSocket::Close() {
56*288bf522SAndroid Build Coastguard Worker   nl_.reset();
57*288bf522SAndroid Build Coastguard Worker }
58*288bf522SAndroid Build Coastguard Worker 
59*288bf522SAndroid Build Coastguard Worker struct TaskStatsRequest {
60*288bf522SAndroid Build Coastguard Worker   pid_t requested_pid;
61*288bf522SAndroid Build Coastguard Worker   taskstats stats;
62*288bf522SAndroid Build Coastguard Worker };
63*288bf522SAndroid Build Coastguard Worker 
ParseAggregateTaskStats(nlattr * attr,int attr_size,taskstats * stats)64*288bf522SAndroid Build Coastguard Worker static pid_t ParseAggregateTaskStats(nlattr* attr, int attr_size, taskstats* stats) {
65*288bf522SAndroid Build Coastguard Worker   pid_t received_pid = -1;
66*288bf522SAndroid Build Coastguard Worker   nla_for_each_attr(attr, attr, attr_size, attr_size) {
67*288bf522SAndroid Build Coastguard Worker     switch (nla_type(attr)) {
68*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_PID:
69*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_TGID:
70*288bf522SAndroid Build Coastguard Worker         received_pid = nla_get_u32(attr);
71*288bf522SAndroid Build Coastguard Worker         break;
72*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_STATS: {
73*288bf522SAndroid Build Coastguard Worker         int len = static_cast<int>(sizeof(*stats));
74*288bf522SAndroid Build Coastguard Worker         len = std::min(len, nla_len(attr));
75*288bf522SAndroid Build Coastguard Worker         nla_memcpy(stats, attr, len);
76*288bf522SAndroid Build Coastguard Worker         return received_pid;
77*288bf522SAndroid Build Coastguard Worker       }
78*288bf522SAndroid Build Coastguard Worker       default:
79*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "unexpected attribute inside AGGR";
80*288bf522SAndroid Build Coastguard Worker         return -1;
81*288bf522SAndroid Build Coastguard Worker     }
82*288bf522SAndroid Build Coastguard Worker   }
83*288bf522SAndroid Build Coastguard Worker 
84*288bf522SAndroid Build Coastguard Worker   return -1;
85*288bf522SAndroid Build Coastguard Worker }
86*288bf522SAndroid Build Coastguard Worker 
ParseTaskStats(nl_msg * msg,void * arg)87*288bf522SAndroid Build Coastguard Worker static int ParseTaskStats(nl_msg* msg, void* arg) {
88*288bf522SAndroid Build Coastguard Worker   TaskStatsRequest* taskstats_request = static_cast<TaskStatsRequest*>(arg);
89*288bf522SAndroid Build Coastguard Worker   genlmsghdr* gnlh = static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(msg)));
90*288bf522SAndroid Build Coastguard Worker   nlattr* attr = genlmsg_attrdata(gnlh, 0);
91*288bf522SAndroid Build Coastguard Worker   int remaining = genlmsg_attrlen(gnlh, 0);
92*288bf522SAndroid Build Coastguard Worker 
93*288bf522SAndroid Build Coastguard Worker   nla_for_each_attr(attr, attr, remaining, remaining) {
94*288bf522SAndroid Build Coastguard Worker     switch (nla_type(attr)) {
95*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_AGGR_PID:
96*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_AGGR_TGID: {
97*288bf522SAndroid Build Coastguard Worker         nlattr* nested_attr = static_cast<nlattr*>(nla_data(attr));
98*288bf522SAndroid Build Coastguard Worker         taskstats stats;
99*288bf522SAndroid Build Coastguard Worker         pid_t ret;
100*288bf522SAndroid Build Coastguard Worker 
101*288bf522SAndroid Build Coastguard Worker         ret = ParseAggregateTaskStats(nested_attr, nla_len(attr), &stats);
102*288bf522SAndroid Build Coastguard Worker         if (ret < 0) {
103*288bf522SAndroid Build Coastguard Worker           LOG(ERROR) << "Bad AGGR_PID contents";
104*288bf522SAndroid Build Coastguard Worker         } else if (ret == taskstats_request->requested_pid) {
105*288bf522SAndroid Build Coastguard Worker           taskstats_request->stats = stats;
106*288bf522SAndroid Build Coastguard Worker         } else {
107*288bf522SAndroid Build Coastguard Worker           LOG(WARNING) << "got taskstats for unexpected pid " << ret << " (expected "
108*288bf522SAndroid Build Coastguard Worker                        << taskstats_request->requested_pid << ", continuing...";
109*288bf522SAndroid Build Coastguard Worker         }
110*288bf522SAndroid Build Coastguard Worker         break;
111*288bf522SAndroid Build Coastguard Worker       }
112*288bf522SAndroid Build Coastguard Worker       case TASKSTATS_TYPE_NULL:
113*288bf522SAndroid Build Coastguard Worker         break;
114*288bf522SAndroid Build Coastguard Worker       default:
115*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "unexpected attribute in taskstats";
116*288bf522SAndroid Build Coastguard Worker     }
117*288bf522SAndroid Build Coastguard Worker   }
118*288bf522SAndroid Build Coastguard Worker   return NL_OK;
119*288bf522SAndroid Build Coastguard Worker }
120*288bf522SAndroid Build Coastguard Worker 
GetStats(int pid,int type,TaskStatistics & stats)121*288bf522SAndroid Build Coastguard Worker bool TaskstatsSocket::GetStats(int pid, int type, TaskStatistics& stats) {
122*288bf522SAndroid Build Coastguard Worker   TaskStatsRequest taskstats_request = TaskStatsRequest();
123*288bf522SAndroid Build Coastguard Worker   taskstats_request.requested_pid = pid;
124*288bf522SAndroid Build Coastguard Worker 
125*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<nl_msg, decltype(&nlmsg_free)> message(nlmsg_alloc(), nlmsg_free);
126*288bf522SAndroid Build Coastguard Worker 
127*288bf522SAndroid Build Coastguard Worker   genlmsg_put(message.get(), NL_AUTO_PID, NL_AUTO_SEQ, family_id_, 0, 0, TASKSTATS_CMD_GET,
128*288bf522SAndroid Build Coastguard Worker               TASKSTATS_VERSION);
129*288bf522SAndroid Build Coastguard Worker   nla_put_u32(message.get(), type, pid);
130*288bf522SAndroid Build Coastguard Worker 
131*288bf522SAndroid Build Coastguard Worker   int result = nl_send_auto_complete(nl_.get(), message.get());
132*288bf522SAndroid Build Coastguard Worker   if (result < 0) {
133*288bf522SAndroid Build Coastguard Worker     return false;
134*288bf522SAndroid Build Coastguard Worker   }
135*288bf522SAndroid Build Coastguard Worker 
136*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<nl_cb, decltype(&nl_cb_put)> callbacks(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
137*288bf522SAndroid Build Coastguard Worker   nl_cb_set(callbacks.get(), NL_CB_VALID, NL_CB_CUSTOM, &ParseTaskStats,
138*288bf522SAndroid Build Coastguard Worker             static_cast<void*>(&taskstats_request));
139*288bf522SAndroid Build Coastguard Worker 
140*288bf522SAndroid Build Coastguard Worker   result = nl_recvmsgs(nl_.get(), callbacks.get());
141*288bf522SAndroid Build Coastguard Worker   if (result < 0) {
142*288bf522SAndroid Build Coastguard Worker     return false;
143*288bf522SAndroid Build Coastguard Worker   }
144*288bf522SAndroid Build Coastguard Worker   nl_wait_for_ack(nl_.get());
145*288bf522SAndroid Build Coastguard Worker 
146*288bf522SAndroid Build Coastguard Worker   stats = TaskStatistics(taskstats_request.stats);
147*288bf522SAndroid Build Coastguard Worker 
148*288bf522SAndroid Build Coastguard Worker   return true;
149*288bf522SAndroid Build Coastguard Worker }
150*288bf522SAndroid Build Coastguard Worker 
GetPidStats(int pid,TaskStatistics & stats)151*288bf522SAndroid Build Coastguard Worker bool TaskstatsSocket::GetPidStats(int pid, TaskStatistics& stats) {
152*288bf522SAndroid Build Coastguard Worker   return GetStats(pid, TASKSTATS_CMD_ATTR_PID, stats);
153*288bf522SAndroid Build Coastguard Worker }
154*288bf522SAndroid Build Coastguard Worker 
GetTgidStats(int tgid,TaskStatistics & stats)155*288bf522SAndroid Build Coastguard Worker bool TaskstatsSocket::GetTgidStats(int tgid, TaskStatistics& stats) {
156*288bf522SAndroid Build Coastguard Worker   bool ret = GetStats(tgid, TASKSTATS_CMD_ATTR_TGID, stats);
157*288bf522SAndroid Build Coastguard Worker   if (ret) {
158*288bf522SAndroid Build Coastguard Worker     stats.set_pid(tgid);
159*288bf522SAndroid Build Coastguard Worker   }
160*288bf522SAndroid Build Coastguard Worker   return ret;
161*288bf522SAndroid Build Coastguard Worker }
162*288bf522SAndroid Build Coastguard Worker 
TaskStatistics(const taskstats & taskstats_stats)163*288bf522SAndroid Build Coastguard Worker TaskStatistics::TaskStatistics(const taskstats& taskstats_stats) {
164*288bf522SAndroid Build Coastguard Worker   comm_ = std::string(taskstats_stats.ac_comm);
165*288bf522SAndroid Build Coastguard Worker   pid_ = taskstats_stats.ac_pid;
166*288bf522SAndroid Build Coastguard Worker 
167*288bf522SAndroid Build Coastguard Worker   uid_ = taskstats_stats.ac_uid;
168*288bf522SAndroid Build Coastguard Worker   gid_ = taskstats_stats.ac_gid;
169*288bf522SAndroid Build Coastguard Worker   pid_ = taskstats_stats.ac_pid;
170*288bf522SAndroid Build Coastguard Worker   ppid_ = taskstats_stats.ac_ppid;
171*288bf522SAndroid Build Coastguard Worker 
172*288bf522SAndroid Build Coastguard Worker   cpu_delay_count_ = taskstats_stats.cpu_count;
173*288bf522SAndroid Build Coastguard Worker   cpu_delay_ns_ = taskstats_stats.cpu_delay_total;
174*288bf522SAndroid Build Coastguard Worker 
175*288bf522SAndroid Build Coastguard Worker   block_io_delay_count_ = taskstats_stats.blkio_count;
176*288bf522SAndroid Build Coastguard Worker   block_io_delay_ns_ = taskstats_stats.blkio_delay_total;
177*288bf522SAndroid Build Coastguard Worker 
178*288bf522SAndroid Build Coastguard Worker   swap_in_delay_count_ = taskstats_stats.swapin_count;
179*288bf522SAndroid Build Coastguard Worker   swap_in_delay_ns_ = taskstats_stats.swapin_delay_total;
180*288bf522SAndroid Build Coastguard Worker 
181*288bf522SAndroid Build Coastguard Worker   reclaim_delay_count_ = taskstats_stats.freepages_count;
182*288bf522SAndroid Build Coastguard Worker   reclaim_delay_ns_ = taskstats_stats.freepages_delay_total;
183*288bf522SAndroid Build Coastguard Worker 
184*288bf522SAndroid Build Coastguard Worker   total_delay_ns_ = cpu_delay_ns_ + block_io_delay_ns_ + swap_in_delay_ns_ + reclaim_delay_ns_;
185*288bf522SAndroid Build Coastguard Worker 
186*288bf522SAndroid Build Coastguard Worker   cpu_time_real_ = taskstats_stats.cpu_run_real_total;
187*288bf522SAndroid Build Coastguard Worker   cpu_time_virtual_ = taskstats_stats.cpu_run_virtual_total;
188*288bf522SAndroid Build Coastguard Worker 
189*288bf522SAndroid Build Coastguard Worker   majflt_ = taskstats_stats.ac_majflt;
190*288bf522SAndroid Build Coastguard Worker   minflt_ = taskstats_stats.ac_minflt;
191*288bf522SAndroid Build Coastguard Worker 
192*288bf522SAndroid Build Coastguard Worker   read_bytes_ = taskstats_stats.read_bytes;
193*288bf522SAndroid Build Coastguard Worker   write_bytes_ = taskstats_stats.write_bytes;
194*288bf522SAndroid Build Coastguard Worker   read_write_bytes_ = read_bytes_ + write_bytes_;
195*288bf522SAndroid Build Coastguard Worker   cancelled_write_bytes_ = taskstats_stats.cancelled_write_bytes;
196*288bf522SAndroid Build Coastguard Worker   threads_ = 1;
197*288bf522SAndroid Build Coastguard Worker }
198*288bf522SAndroid Build Coastguard Worker 
AddPidToTgid(const TaskStatistics & pid_statistics)199*288bf522SAndroid Build Coastguard Worker void TaskStatistics::AddPidToTgid(const TaskStatistics& pid_statistics) {
200*288bf522SAndroid Build Coastguard Worker   // tgid statistics already contain delay values totalled across all pids
201*288bf522SAndroid Build Coastguard Worker   // only add IO statistics
202*288bf522SAndroid Build Coastguard Worker   read_bytes_ += pid_statistics.read_bytes_;
203*288bf522SAndroid Build Coastguard Worker   write_bytes_ += pid_statistics.write_bytes_;
204*288bf522SAndroid Build Coastguard Worker   read_write_bytes_ += pid_statistics.read_write_bytes_;
205*288bf522SAndroid Build Coastguard Worker   cancelled_write_bytes_ += pid_statistics.cancelled_write_bytes_;
206*288bf522SAndroid Build Coastguard Worker   if (pid_ == pid_statistics.pid_) {
207*288bf522SAndroid Build Coastguard Worker     comm_ = pid_statistics.comm_;
208*288bf522SAndroid Build Coastguard Worker     uid_ = pid_statistics.uid_;
209*288bf522SAndroid Build Coastguard Worker     gid_ = pid_statistics.pid_;
210*288bf522SAndroid Build Coastguard Worker     ppid_ = pid_statistics.ppid_;
211*288bf522SAndroid Build Coastguard Worker   } else {
212*288bf522SAndroid Build Coastguard Worker     threads_++;
213*288bf522SAndroid Build Coastguard Worker   }
214*288bf522SAndroid Build Coastguard Worker }
215*288bf522SAndroid Build Coastguard Worker 
216*288bf522SAndroid Build Coastguard Worker // Store new statistics and return the delta from the old statistics
Update(const TaskStatistics & new_statistics)217*288bf522SAndroid Build Coastguard Worker TaskStatistics TaskStatistics::Update(const TaskStatistics& new_statistics) {
218*288bf522SAndroid Build Coastguard Worker   TaskStatistics delta = new_statistics;
219*288bf522SAndroid Build Coastguard Worker   delta.minflt_ -= minflt_;
220*288bf522SAndroid Build Coastguard Worker   delta.majflt_ -= majflt_;
221*288bf522SAndroid Build Coastguard Worker   delta.cpu_delay_count_ -= cpu_delay_count_;
222*288bf522SAndroid Build Coastguard Worker   delta.cpu_delay_ns_ -= cpu_delay_ns_;
223*288bf522SAndroid Build Coastguard Worker   delta.block_io_delay_count_ -= block_io_delay_count_;
224*288bf522SAndroid Build Coastguard Worker   delta.block_io_delay_ns_ -= block_io_delay_ns_;
225*288bf522SAndroid Build Coastguard Worker   delta.swap_in_delay_count_ -= swap_in_delay_count_;
226*288bf522SAndroid Build Coastguard Worker   delta.swap_in_delay_ns_ -= swap_in_delay_ns_;
227*288bf522SAndroid Build Coastguard Worker   delta.reclaim_delay_count_ -= reclaim_delay_count_;
228*288bf522SAndroid Build Coastguard Worker   delta.reclaim_delay_ns_ -= reclaim_delay_ns_;
229*288bf522SAndroid Build Coastguard Worker   delta.total_delay_ns_ -= total_delay_ns_;
230*288bf522SAndroid Build Coastguard Worker   delta.cpu_time_real_ -= cpu_time_real_;
231*288bf522SAndroid Build Coastguard Worker   delta.cpu_time_virtual_ -= cpu_time_virtual_;
232*288bf522SAndroid Build Coastguard Worker   delta.read_bytes_ -= read_bytes_;
233*288bf522SAndroid Build Coastguard Worker   delta.write_bytes_ -= write_bytes_;
234*288bf522SAndroid Build Coastguard Worker   delta.read_write_bytes_ -= read_write_bytes_;
235*288bf522SAndroid Build Coastguard Worker   delta.cancelled_write_bytes_ -= cancelled_write_bytes_;
236*288bf522SAndroid Build Coastguard Worker   *this = new_statistics;
237*288bf522SAndroid Build Coastguard Worker   return delta;
238*288bf522SAndroid Build Coastguard Worker }
239