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