xref: /aosp_15_r20/system/extras/iotop/iotop.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 <getopt.h>
16*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
17*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
18*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <algorithm>
21*288bf522SAndroid Build Coastguard Worker #include <map>
22*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
23*288bf522SAndroid Build Coastguard Worker #include <vector>
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
26*288bf522SAndroid Build Coastguard Worker 
27*288bf522SAndroid Build Coastguard Worker #include "tasklist.h"
28*288bf522SAndroid Build Coastguard Worker #include "taskstats.h"
29*288bf522SAndroid Build Coastguard Worker 
30*288bf522SAndroid Build Coastguard Worker constexpr uint64_t NSEC_PER_SEC = 1000000000;
31*288bf522SAndroid Build Coastguard Worker 
BytesToKB(uint64_t bytes)32*288bf522SAndroid Build Coastguard Worker static uint64_t BytesToKB(uint64_t bytes) {
33*288bf522SAndroid Build Coastguard Worker   return (bytes + 1024 - 1) / 1024;
34*288bf522SAndroid Build Coastguard Worker }
35*288bf522SAndroid Build Coastguard Worker 
TimeToTgidPercent(uint64_t ns,int time,const TaskStatistics & stats)36*288bf522SAndroid Build Coastguard Worker static float TimeToTgidPercent(uint64_t ns, int time, const TaskStatistics& stats) {
37*288bf522SAndroid Build Coastguard Worker   float percent = ns / stats.threads() / (time * NSEC_PER_SEC / 100.0f);
38*288bf522SAndroid Build Coastguard Worker   return std::min(percent, 99.99f);
39*288bf522SAndroid Build Coastguard Worker }
40*288bf522SAndroid Build Coastguard Worker 
usage(char * myname)41*288bf522SAndroid Build Coastguard Worker static void usage(char* myname) {
42*288bf522SAndroid Build Coastguard Worker   printf(
43*288bf522SAndroid Build Coastguard Worker       "Usage: %s [-h] [-P] [-d <delay>] [-n <cycles>] [-s <column>]\n"
44*288bf522SAndroid Build Coastguard Worker       "   -a  Show byte count instead of rate\n"
45*288bf522SAndroid Build Coastguard Worker       "   -d  Set the delay between refreshes in seconds.\n"
46*288bf522SAndroid Build Coastguard Worker       "   -h  Display this help screen.\n"
47*288bf522SAndroid Build Coastguard Worker       "   -m  Set the number of processes or threads to show\n"
48*288bf522SAndroid Build Coastguard Worker       "   -n  Set the number of refreshes before exiting.\n"
49*288bf522SAndroid Build Coastguard Worker       "   -P  Show processes instead of the default threads.\n"
50*288bf522SAndroid Build Coastguard Worker       "   -s  Set the column to sort by:\n"
51*288bf522SAndroid Build Coastguard Worker       "       pid, read, write, total, io, swap, faults, sched, mem or delay.\n",
52*288bf522SAndroid Build Coastguard Worker       myname);
53*288bf522SAndroid Build Coastguard Worker }
54*288bf522SAndroid Build Coastguard Worker 
55*288bf522SAndroid Build Coastguard Worker using Sorter = std::function<void(std::vector<TaskStatistics>&)>;
GetSorter(const std::string & field)56*288bf522SAndroid Build Coastguard Worker static Sorter GetSorter(const std::string& field) {
57*288bf522SAndroid Build Coastguard Worker   // Generic comparator
58*288bf522SAndroid Build Coastguard Worker   static auto comparator = [](auto& lhs, auto& rhs, auto field, bool ascending) -> bool {
59*288bf522SAndroid Build Coastguard Worker     auto a = (lhs.*field)();
60*288bf522SAndroid Build Coastguard Worker     auto b = (rhs.*field)();
61*288bf522SAndroid Build Coastguard Worker     if (a != b) {
62*288bf522SAndroid Build Coastguard Worker       // Sort by selected field
63*288bf522SAndroid Build Coastguard Worker       return ascending ^ (a < b);
64*288bf522SAndroid Build Coastguard Worker     } else {
65*288bf522SAndroid Build Coastguard Worker       // And then fall back to sorting by pid
66*288bf522SAndroid Build Coastguard Worker       return lhs.pid() < rhs.pid();
67*288bf522SAndroid Build Coastguard Worker     }
68*288bf522SAndroid Build Coastguard Worker   };
69*288bf522SAndroid Build Coastguard Worker 
70*288bf522SAndroid Build Coastguard Worker   auto make_sorter = [](auto field, bool ascending) {
71*288bf522SAndroid Build Coastguard Worker     // Make closure for comparator on a specific field
72*288bf522SAndroid Build Coastguard Worker     using namespace std::placeholders;
73*288bf522SAndroid Build Coastguard Worker     auto bound_comparator = std::bind(comparator, _1, _2, field, ascending);
74*288bf522SAndroid Build Coastguard Worker 
75*288bf522SAndroid Build Coastguard Worker     // Return closure to std::sort with specialized comparator
76*288bf522SAndroid Build Coastguard Worker     return [bound_comparator](auto& vector) {
77*288bf522SAndroid Build Coastguard Worker       return std::sort(vector.begin(), vector.end(), bound_comparator);
78*288bf522SAndroid Build Coastguard Worker     };
79*288bf522SAndroid Build Coastguard Worker   };
80*288bf522SAndroid Build Coastguard Worker 
81*288bf522SAndroid Build Coastguard Worker   static const std::map<std::string, Sorter> sorters{
82*288bf522SAndroid Build Coastguard Worker       {"pid", make_sorter(&TaskStatistics::pid, false)},
83*288bf522SAndroid Build Coastguard Worker       {"read", make_sorter(&TaskStatistics::read, true)},
84*288bf522SAndroid Build Coastguard Worker       {"write", make_sorter(&TaskStatistics::write, true)},
85*288bf522SAndroid Build Coastguard Worker       {"total", make_sorter(&TaskStatistics::read_write, true)},
86*288bf522SAndroid Build Coastguard Worker       {"io", make_sorter(&TaskStatistics::delay_io, true)},
87*288bf522SAndroid Build Coastguard Worker       {"swap", make_sorter(&TaskStatistics::delay_swap, true)},
88*288bf522SAndroid Build Coastguard Worker       {"faults", make_sorter(&TaskStatistics::faults, true)},
89*288bf522SAndroid Build Coastguard Worker       {"sched", make_sorter(&TaskStatistics::delay_sched, true)},
90*288bf522SAndroid Build Coastguard Worker       {"mem", make_sorter(&TaskStatistics::delay_mem, true)},
91*288bf522SAndroid Build Coastguard Worker       {"delay", make_sorter(&TaskStatistics::delay_total, true)},
92*288bf522SAndroid Build Coastguard Worker   };
93*288bf522SAndroid Build Coastguard Worker 
94*288bf522SAndroid Build Coastguard Worker   auto it = sorters.find(field);
95*288bf522SAndroid Build Coastguard Worker   if (it == sorters.end()) {
96*288bf522SAndroid Build Coastguard Worker     return nullptr;
97*288bf522SAndroid Build Coastguard Worker   }
98*288bf522SAndroid Build Coastguard Worker   return it->second;
99*288bf522SAndroid Build Coastguard Worker }
100*288bf522SAndroid Build Coastguard Worker 
main(int argc,char * argv[])101*288bf522SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
102*288bf522SAndroid Build Coastguard Worker   bool accumulated = false;
103*288bf522SAndroid Build Coastguard Worker   bool processes = false;
104*288bf522SAndroid Build Coastguard Worker   int delay = 1;
105*288bf522SAndroid Build Coastguard Worker   int cycles = -1;
106*288bf522SAndroid Build Coastguard Worker   int limit = -1;
107*288bf522SAndroid Build Coastguard Worker   Sorter sorter = GetSorter("total");
108*288bf522SAndroid Build Coastguard Worker 
109*288bf522SAndroid Build Coastguard Worker   android::base::InitLogging(argv, android::base::StderrLogger);
110*288bf522SAndroid Build Coastguard Worker 
111*288bf522SAndroid Build Coastguard Worker   while (1) {
112*288bf522SAndroid Build Coastguard Worker     int c;
113*288bf522SAndroid Build Coastguard Worker     static const option longopts[] = {
114*288bf522SAndroid Build Coastguard Worker         {"accumulated", 0, 0, 'a'},
115*288bf522SAndroid Build Coastguard Worker         {"delay", required_argument, 0, 'd'},
116*288bf522SAndroid Build Coastguard Worker         {"help", 0, 0, 'h'},
117*288bf522SAndroid Build Coastguard Worker         {"limit", required_argument, 0, 'm'},
118*288bf522SAndroid Build Coastguard Worker         {"iter", required_argument, 0, 'n'},
119*288bf522SAndroid Build Coastguard Worker         {"sort", required_argument, 0, 's'},
120*288bf522SAndroid Build Coastguard Worker         {"processes", 0, 0, 'P'},
121*288bf522SAndroid Build Coastguard Worker         {0, 0, 0, 0},
122*288bf522SAndroid Build Coastguard Worker     };
123*288bf522SAndroid Build Coastguard Worker     c = getopt_long(argc, argv, "ad:hm:n:Ps:", longopts, NULL);
124*288bf522SAndroid Build Coastguard Worker     if (c < 0) {
125*288bf522SAndroid Build Coastguard Worker       break;
126*288bf522SAndroid Build Coastguard Worker     }
127*288bf522SAndroid Build Coastguard Worker     switch (c) {
128*288bf522SAndroid Build Coastguard Worker       case 'a':
129*288bf522SAndroid Build Coastguard Worker         accumulated = true;
130*288bf522SAndroid Build Coastguard Worker         break;
131*288bf522SAndroid Build Coastguard Worker       case 'd':
132*288bf522SAndroid Build Coastguard Worker         delay = atoi(optarg);
133*288bf522SAndroid Build Coastguard Worker         break;
134*288bf522SAndroid Build Coastguard Worker       case 'h':
135*288bf522SAndroid Build Coastguard Worker         usage(argv[0]);
136*288bf522SAndroid Build Coastguard Worker         return (EXIT_SUCCESS);
137*288bf522SAndroid Build Coastguard Worker       case 'm':
138*288bf522SAndroid Build Coastguard Worker         limit = atoi(optarg);
139*288bf522SAndroid Build Coastguard Worker         break;
140*288bf522SAndroid Build Coastguard Worker       case 'n':
141*288bf522SAndroid Build Coastguard Worker         cycles = atoi(optarg);
142*288bf522SAndroid Build Coastguard Worker         break;
143*288bf522SAndroid Build Coastguard Worker       case 's': {
144*288bf522SAndroid Build Coastguard Worker         sorter = GetSorter(optarg);
145*288bf522SAndroid Build Coastguard Worker         if (sorter == nullptr) {
146*288bf522SAndroid Build Coastguard Worker           LOG(ERROR) << "Invalid sort column \"" << optarg << "\"";
147*288bf522SAndroid Build Coastguard Worker           usage(argv[0]);
148*288bf522SAndroid Build Coastguard Worker           return EXIT_FAILURE;
149*288bf522SAndroid Build Coastguard Worker         }
150*288bf522SAndroid Build Coastguard Worker         break;
151*288bf522SAndroid Build Coastguard Worker       }
152*288bf522SAndroid Build Coastguard Worker       case 'P':
153*288bf522SAndroid Build Coastguard Worker         processes = true;
154*288bf522SAndroid Build Coastguard Worker         break;
155*288bf522SAndroid Build Coastguard Worker       case '?':
156*288bf522SAndroid Build Coastguard Worker         usage(argv[0]);
157*288bf522SAndroid Build Coastguard Worker         return EXIT_FAILURE;
158*288bf522SAndroid Build Coastguard Worker       default:
159*288bf522SAndroid Build Coastguard Worker         abort();
160*288bf522SAndroid Build Coastguard Worker     }
161*288bf522SAndroid Build Coastguard Worker   }
162*288bf522SAndroid Build Coastguard Worker 
163*288bf522SAndroid Build Coastguard Worker   std::map<pid_t, std::vector<pid_t>> tgid_map;
164*288bf522SAndroid Build Coastguard Worker 
165*288bf522SAndroid Build Coastguard Worker   TaskstatsSocket taskstats_socket;
166*288bf522SAndroid Build Coastguard Worker   if (!taskstats_socket.Open()) {
167*288bf522SAndroid Build Coastguard Worker     return EXIT_FAILURE;
168*288bf522SAndroid Build Coastguard Worker   }
169*288bf522SAndroid Build Coastguard Worker 
170*288bf522SAndroid Build Coastguard Worker   std::unordered_map<pid_t, TaskStatistics> pid_stats;
171*288bf522SAndroid Build Coastguard Worker   std::unordered_map<pid_t, TaskStatistics> tgid_stats;
172*288bf522SAndroid Build Coastguard Worker   std::vector<TaskStatistics> stats;
173*288bf522SAndroid Build Coastguard Worker 
174*288bf522SAndroid Build Coastguard Worker   bool first = true;
175*288bf522SAndroid Build Coastguard Worker   bool second = true;
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker   while (true) {
178*288bf522SAndroid Build Coastguard Worker     stats.clear();
179*288bf522SAndroid Build Coastguard Worker     if (!TaskList::Scan(tgid_map)) {
180*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to scan tasks";
181*288bf522SAndroid Build Coastguard Worker       return EXIT_FAILURE;
182*288bf522SAndroid Build Coastguard Worker     }
183*288bf522SAndroid Build Coastguard Worker     for (auto& tgid_it : tgid_map) {
184*288bf522SAndroid Build Coastguard Worker       pid_t tgid = tgid_it.first;
185*288bf522SAndroid Build Coastguard Worker       std::vector<pid_t>& pid_list = tgid_it.second;
186*288bf522SAndroid Build Coastguard Worker 
187*288bf522SAndroid Build Coastguard Worker       TaskStatistics tgid_stats_new;
188*288bf522SAndroid Build Coastguard Worker       TaskStatistics tgid_stats_delta;
189*288bf522SAndroid Build Coastguard Worker 
190*288bf522SAndroid Build Coastguard Worker       if (processes) {
191*288bf522SAndroid Build Coastguard Worker         // If printing processes, collect stats for the tgid which will
192*288bf522SAndroid Build Coastguard Worker         // hold delay accounting data across all threads, including
193*288bf522SAndroid Build Coastguard Worker         // ones that have exited.
194*288bf522SAndroid Build Coastguard Worker         if (!taskstats_socket.GetTgidStats(tgid, tgid_stats_new)) {
195*288bf522SAndroid Build Coastguard Worker           continue;
196*288bf522SAndroid Build Coastguard Worker         }
197*288bf522SAndroid Build Coastguard Worker         tgid_stats_delta = tgid_stats[tgid].Update(tgid_stats_new);
198*288bf522SAndroid Build Coastguard Worker       }
199*288bf522SAndroid Build Coastguard Worker 
200*288bf522SAndroid Build Coastguard Worker       // Collect per-thread stats
201*288bf522SAndroid Build Coastguard Worker       for (pid_t pid : pid_list) {
202*288bf522SAndroid Build Coastguard Worker         TaskStatistics pid_stats_new;
203*288bf522SAndroid Build Coastguard Worker         if (!taskstats_socket.GetPidStats(pid, pid_stats_new)) {
204*288bf522SAndroid Build Coastguard Worker           continue;
205*288bf522SAndroid Build Coastguard Worker         }
206*288bf522SAndroid Build Coastguard Worker 
207*288bf522SAndroid Build Coastguard Worker         TaskStatistics pid_stats_delta = pid_stats[pid].Update(pid_stats_new);
208*288bf522SAndroid Build Coastguard Worker 
209*288bf522SAndroid Build Coastguard Worker         if (processes) {
210*288bf522SAndroid Build Coastguard Worker           tgid_stats_delta.AddPidToTgid(pid_stats_delta);
211*288bf522SAndroid Build Coastguard Worker         } else {
212*288bf522SAndroid Build Coastguard Worker           stats.push_back(pid_stats_delta);
213*288bf522SAndroid Build Coastguard Worker         }
214*288bf522SAndroid Build Coastguard Worker       }
215*288bf522SAndroid Build Coastguard Worker 
216*288bf522SAndroid Build Coastguard Worker       if (processes) {
217*288bf522SAndroid Build Coastguard Worker         stats.push_back(tgid_stats_delta);
218*288bf522SAndroid Build Coastguard Worker       }
219*288bf522SAndroid Build Coastguard Worker     }
220*288bf522SAndroid Build Coastguard Worker 
221*288bf522SAndroid Build Coastguard Worker     if (!first) {
222*288bf522SAndroid Build Coastguard Worker       sorter(stats);
223*288bf522SAndroid Build Coastguard Worker       if (!second) {
224*288bf522SAndroid Build Coastguard Worker         printf("\n");
225*288bf522SAndroid Build Coastguard Worker       }
226*288bf522SAndroid Build Coastguard Worker       if (accumulated) {
227*288bf522SAndroid Build Coastguard Worker         printf("%6s %-16s %20s %14s %34s\n", "", "", "---- IO (KiB) ----", "--- faults ---",
228*288bf522SAndroid Build Coastguard Worker                "----------- delayed on ----------");
229*288bf522SAndroid Build Coastguard Worker       } else {
230*288bf522SAndroid Build Coastguard Worker         printf("%6s %-16s %20s %14s %34s\n", "", "", "--- IO (KiB/s) ---", "--- faults ---",
231*288bf522SAndroid Build Coastguard Worker                "----------- delayed on ----------");
232*288bf522SAndroid Build Coastguard Worker       }
233*288bf522SAndroid Build Coastguard Worker       printf("%6s %-16s %6s %6s %6s %6s %6s  %-5s  %-5s  %-5s  %-5s  %-5s\n", "PID", "Command",
234*288bf522SAndroid Build Coastguard Worker              "read", "write", "total", "major", "minor", "IO", "swap", "sched", "mem", "total");
235*288bf522SAndroid Build Coastguard Worker       int n = limit;
236*288bf522SAndroid Build Coastguard Worker       const int delay_div = accumulated ? 1 : delay;
237*288bf522SAndroid Build Coastguard Worker       uint64_t total_read = 0;
238*288bf522SAndroid Build Coastguard Worker       uint64_t total_write = 0;
239*288bf522SAndroid Build Coastguard Worker       uint64_t total_read_write = 0;
240*288bf522SAndroid Build Coastguard Worker       uint64_t total_minflt = 0;
241*288bf522SAndroid Build Coastguard Worker       uint64_t total_majflt = 0;
242*288bf522SAndroid Build Coastguard Worker       for (const TaskStatistics& statistics : stats) {
243*288bf522SAndroid Build Coastguard Worker         total_read += statistics.read();
244*288bf522SAndroid Build Coastguard Worker         total_write += statistics.write();
245*288bf522SAndroid Build Coastguard Worker         total_read_write += statistics.read_write();
246*288bf522SAndroid Build Coastguard Worker         total_minflt += statistics.minflt();
247*288bf522SAndroid Build Coastguard Worker         total_majflt += statistics.majflt();
248*288bf522SAndroid Build Coastguard Worker 
249*288bf522SAndroid Build Coastguard Worker         if (n == 0) {
250*288bf522SAndroid Build Coastguard Worker           continue;
251*288bf522SAndroid Build Coastguard Worker         } else if (n > 0) {
252*288bf522SAndroid Build Coastguard Worker           n--;
253*288bf522SAndroid Build Coastguard Worker         }
254*288bf522SAndroid Build Coastguard Worker 
255*288bf522SAndroid Build Coastguard Worker         printf("%6d %-16s %6" PRIu64 " %6" PRIu64 " %6" PRIu64 " %6" PRIu64 " %6" PRIu64
256*288bf522SAndroid Build Coastguard Worker                " %5.2f%% %5.2f%% %5.2f%% %5.2f%% %5.2f%%\n",
257*288bf522SAndroid Build Coastguard Worker                statistics.pid(), statistics.comm().c_str(),
258*288bf522SAndroid Build Coastguard Worker                BytesToKB(statistics.read()) / delay_div, BytesToKB(statistics.write()) / delay_div,
259*288bf522SAndroid Build Coastguard Worker                BytesToKB(statistics.read_write()) / delay_div, statistics.majflt(),
260*288bf522SAndroid Build Coastguard Worker                statistics.minflt(), TimeToTgidPercent(statistics.delay_io(), delay, statistics),
261*288bf522SAndroid Build Coastguard Worker                TimeToTgidPercent(statistics.delay_swap(), delay, statistics),
262*288bf522SAndroid Build Coastguard Worker                TimeToTgidPercent(statistics.delay_sched(), delay, statistics),
263*288bf522SAndroid Build Coastguard Worker                TimeToTgidPercent(statistics.delay_mem(), delay, statistics),
264*288bf522SAndroid Build Coastguard Worker                TimeToTgidPercent(statistics.delay_total(), delay, statistics));
265*288bf522SAndroid Build Coastguard Worker       }
266*288bf522SAndroid Build Coastguard Worker       printf("%6s %-16s %6" PRIu64 " %6" PRIu64 " %6" PRIu64 " %6" PRIu64 " %6" PRIu64 "\n", "",
267*288bf522SAndroid Build Coastguard Worker              "TOTAL", BytesToKB(total_read) / delay_div, BytesToKB(total_write) / delay_div,
268*288bf522SAndroid Build Coastguard Worker              BytesToKB(total_read_write) / delay_div, total_majflt / delay_div,
269*288bf522SAndroid Build Coastguard Worker              total_minflt / delay_div);
270*288bf522SAndroid Build Coastguard Worker 
271*288bf522SAndroid Build Coastguard Worker       second = false;
272*288bf522SAndroid Build Coastguard Worker 
273*288bf522SAndroid Build Coastguard Worker       if (cycles > 0 && --cycles == 0) break;
274*288bf522SAndroid Build Coastguard Worker     }
275*288bf522SAndroid Build Coastguard Worker     first = false;
276*288bf522SAndroid Build Coastguard Worker     sleep(delay);
277*288bf522SAndroid Build Coastguard Worker   }
278*288bf522SAndroid Build Coastguard Worker 
279*288bf522SAndroid Build Coastguard Worker   return 0;
280*288bf522SAndroid Build Coastguard Worker }
281