xref: /aosp_15_r20/system/extras/latencytop/latencytop.c (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <ctype.h>
18*288bf522SAndroid Build Coastguard Worker #include <dirent.h>
19*288bf522SAndroid Build Coastguard Worker #include <errno.h>
20*288bf522SAndroid Build Coastguard Worker #include <signal.h>
21*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
22*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
23*288bf522SAndroid Build Coastguard Worker #include <string.h>
24*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
25*288bf522SAndroid Build Coastguard Worker 
26*288bf522SAndroid Build Coastguard Worker #define MAX_LINE 512
27*288bf522SAndroid Build Coastguard Worker #define MAX_FILENAME 64
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker const char* EXPECTED_VERSION = "Latency Top version : v0.1\n";
30*288bf522SAndroid Build Coastguard Worker const char* SYSCTL_FILE = "/proc/sys/kernel/latencytop";
31*288bf522SAndroid Build Coastguard Worker const char* GLOBAL_STATS_FILE = "/proc/latency_stats";
32*288bf522SAndroid Build Coastguard Worker const char* THREAD_STATS_FILE_FORMAT = "/proc/%d/task/%d/latency";
33*288bf522SAndroid Build Coastguard Worker 
34*288bf522SAndroid Build Coastguard Worker struct latency_entry {
35*288bf522SAndroid Build Coastguard Worker     struct latency_entry* next;
36*288bf522SAndroid Build Coastguard Worker     unsigned long count;
37*288bf522SAndroid Build Coastguard Worker     unsigned long max;
38*288bf522SAndroid Build Coastguard Worker     unsigned long total;
39*288bf522SAndroid Build Coastguard Worker     char reason[MAX_LINE];
40*288bf522SAndroid Build Coastguard Worker };
41*288bf522SAndroid Build Coastguard Worker 
check_latencytop()42*288bf522SAndroid Build Coastguard Worker static inline void check_latencytop() {}
43*288bf522SAndroid Build Coastguard Worker 
44*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_global_stats(struct latency_entry* list, int erase);
45*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_process_stats(struct latency_entry* list, int erase, int pid);
46*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_thread_stats(struct latency_entry* list, int erase, int pid,
47*288bf522SAndroid Build Coastguard Worker                                                int tid, int fatal);
48*288bf522SAndroid Build Coastguard Worker 
49*288bf522SAndroid Build Coastguard Worker static struct latency_entry* alloc_latency_entry(void);
50*288bf522SAndroid Build Coastguard Worker 
51*288bf522SAndroid Build Coastguard Worker static void set_latencytop(int on);
52*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_latency_file(FILE* f, struct latency_entry* list);
53*288bf522SAndroid Build Coastguard Worker 
54*288bf522SAndroid Build Coastguard Worker static struct latency_entry* find_latency_entry(struct latency_entry* e, char* reason);
55*288bf522SAndroid Build Coastguard Worker static void print_latency_entries(struct latency_entry* head);
56*288bf522SAndroid Build Coastguard Worker 
57*288bf522SAndroid Build Coastguard Worker static void signal_handler(int sig);
58*288bf522SAndroid Build Coastguard Worker static void disable_latencytop(void);
59*288bf522SAndroid Build Coastguard Worker 
60*288bf522SAndroid Build Coastguard Worker static int numcmp(const long long a, const long long b);
61*288bf522SAndroid Build Coastguard Worker static int lat_cmp(const void* a, const void* b);
62*288bf522SAndroid Build Coastguard Worker 
63*288bf522SAndroid Build Coastguard Worker static void clear_screen(void);
64*288bf522SAndroid Build Coastguard Worker static void usage(const char* cmd);
65*288bf522SAndroid Build Coastguard Worker 
66*288bf522SAndroid Build Coastguard Worker struct latency_entry* free_entries;
67*288bf522SAndroid Build Coastguard Worker 
main(int argc,char * argv[])68*288bf522SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
69*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
70*288bf522SAndroid Build Coastguard Worker     int delay, iterations;
71*288bf522SAndroid Build Coastguard Worker     int pid, tid;
72*288bf522SAndroid Build Coastguard Worker     int count, erase;
73*288bf522SAndroid Build Coastguard Worker     int i;
74*288bf522SAndroid Build Coastguard Worker 
75*288bf522SAndroid Build Coastguard Worker     delay = 1;
76*288bf522SAndroid Build Coastguard Worker     iterations = 0;
77*288bf522SAndroid Build Coastguard Worker     pid = tid = 0;
78*288bf522SAndroid Build Coastguard Worker 
79*288bf522SAndroid Build Coastguard Worker     for (i = 1; i < argc; i++) {
80*288bf522SAndroid Build Coastguard Worker         if (!strcmp(argv[i], "-d")) {
81*288bf522SAndroid Build Coastguard Worker             if (i >= argc - 1) {
82*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Option -d expects an argument.\n");
83*288bf522SAndroid Build Coastguard Worker                 exit(EXIT_FAILURE);
84*288bf522SAndroid Build Coastguard Worker             }
85*288bf522SAndroid Build Coastguard Worker             delay = atoi(argv[++i]);
86*288bf522SAndroid Build Coastguard Worker             continue;
87*288bf522SAndroid Build Coastguard Worker         }
88*288bf522SAndroid Build Coastguard Worker         if (!strcmp(argv[i], "-n")) {
89*288bf522SAndroid Build Coastguard Worker             if (i >= argc - 1) {
90*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Option -n expects an argument.\n");
91*288bf522SAndroid Build Coastguard Worker                 exit(EXIT_FAILURE);
92*288bf522SAndroid Build Coastguard Worker             }
93*288bf522SAndroid Build Coastguard Worker             iterations = atoi(argv[++i]);
94*288bf522SAndroid Build Coastguard Worker             continue;
95*288bf522SAndroid Build Coastguard Worker         }
96*288bf522SAndroid Build Coastguard Worker         if (!strcmp(argv[i], "-h")) {
97*288bf522SAndroid Build Coastguard Worker             usage(argv[0]);
98*288bf522SAndroid Build Coastguard Worker             exit(EXIT_SUCCESS);
99*288bf522SAndroid Build Coastguard Worker         }
100*288bf522SAndroid Build Coastguard Worker         if (!strcmp(argv[i], "-p")) {
101*288bf522SAndroid Build Coastguard Worker             if (i >= argc - 1) {
102*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Option -p expects an argument.\n");
103*288bf522SAndroid Build Coastguard Worker                 exit(EXIT_FAILURE);
104*288bf522SAndroid Build Coastguard Worker             }
105*288bf522SAndroid Build Coastguard Worker             pid = atoi(argv[++i]);
106*288bf522SAndroid Build Coastguard Worker             continue;
107*288bf522SAndroid Build Coastguard Worker         }
108*288bf522SAndroid Build Coastguard Worker         if (!strcmp(argv[i], "-t")) {
109*288bf522SAndroid Build Coastguard Worker             if (i >= argc - 1) {
110*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Option -t expects an argument.\n");
111*288bf522SAndroid Build Coastguard Worker                 exit(EXIT_FAILURE);
112*288bf522SAndroid Build Coastguard Worker             }
113*288bf522SAndroid Build Coastguard Worker             tid = atoi(argv[++i]);
114*288bf522SAndroid Build Coastguard Worker             continue;
115*288bf522SAndroid Build Coastguard Worker         }
116*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
117*288bf522SAndroid Build Coastguard Worker         usage(argv[0]);
118*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
119*288bf522SAndroid Build Coastguard Worker     }
120*288bf522SAndroid Build Coastguard Worker 
121*288bf522SAndroid Build Coastguard Worker     if (tid && !pid) {
122*288bf522SAndroid Build Coastguard Worker         fprintf(stderr,
123*288bf522SAndroid Build Coastguard Worker                 "If you provide a thread ID with -t, you must provide a process ID with -p.\n");
124*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
125*288bf522SAndroid Build Coastguard Worker     }
126*288bf522SAndroid Build Coastguard Worker 
127*288bf522SAndroid Build Coastguard Worker     check_latencytop();
128*288bf522SAndroid Build Coastguard Worker 
129*288bf522SAndroid Build Coastguard Worker     free_entries = NULL;
130*288bf522SAndroid Build Coastguard Worker 
131*288bf522SAndroid Build Coastguard Worker     signal(SIGINT, &signal_handler);
132*288bf522SAndroid Build Coastguard Worker     signal(SIGTERM, &signal_handler);
133*288bf522SAndroid Build Coastguard Worker 
134*288bf522SAndroid Build Coastguard Worker     atexit(&disable_latencytop);
135*288bf522SAndroid Build Coastguard Worker 
136*288bf522SAndroid Build Coastguard Worker     set_latencytop(1);
137*288bf522SAndroid Build Coastguard Worker 
138*288bf522SAndroid Build Coastguard Worker     count = 0;
139*288bf522SAndroid Build Coastguard Worker     erase = 1;
140*288bf522SAndroid Build Coastguard Worker 
141*288bf522SAndroid Build Coastguard Worker     while ((iterations == 0) || (count++ < iterations)) {
142*288bf522SAndroid Build Coastguard Worker         sleep(delay);
143*288bf522SAndroid Build Coastguard Worker 
144*288bf522SAndroid Build Coastguard Worker         e = NULL;
145*288bf522SAndroid Build Coastguard Worker         if (pid) {
146*288bf522SAndroid Build Coastguard Worker             if (tid) {
147*288bf522SAndroid Build Coastguard Worker                 e = read_thread_stats(e, erase, pid, tid, 1);
148*288bf522SAndroid Build Coastguard Worker             } else {
149*288bf522SAndroid Build Coastguard Worker                 e = read_process_stats(e, erase, pid);
150*288bf522SAndroid Build Coastguard Worker             }
151*288bf522SAndroid Build Coastguard Worker         } else {
152*288bf522SAndroid Build Coastguard Worker             e = read_global_stats(e, erase);
153*288bf522SAndroid Build Coastguard Worker         }
154*288bf522SAndroid Build Coastguard Worker         erase = 0;
155*288bf522SAndroid Build Coastguard Worker 
156*288bf522SAndroid Build Coastguard Worker         clear_screen();
157*288bf522SAndroid Build Coastguard Worker         if (pid) {
158*288bf522SAndroid Build Coastguard Worker             if (tid) {
159*288bf522SAndroid Build Coastguard Worker                 printf("Latencies for thread %d in process %d:\n", tid, pid);
160*288bf522SAndroid Build Coastguard Worker             } else {
161*288bf522SAndroid Build Coastguard Worker                 printf("Latencies for process %d:\n", pid);
162*288bf522SAndroid Build Coastguard Worker             }
163*288bf522SAndroid Build Coastguard Worker         } else {
164*288bf522SAndroid Build Coastguard Worker             printf("Latencies across all processes:\n");
165*288bf522SAndroid Build Coastguard Worker         }
166*288bf522SAndroid Build Coastguard Worker         print_latency_entries(e);
167*288bf522SAndroid Build Coastguard Worker     }
168*288bf522SAndroid Build Coastguard Worker 
169*288bf522SAndroid Build Coastguard Worker     set_latencytop(0);
170*288bf522SAndroid Build Coastguard Worker 
171*288bf522SAndroid Build Coastguard Worker     return 0;
172*288bf522SAndroid Build Coastguard Worker }
173*288bf522SAndroid Build Coastguard Worker 
read_global_stats(struct latency_entry * list,int erase)174*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_global_stats(struct latency_entry* list, int erase) {
175*288bf522SAndroid Build Coastguard Worker     FILE* f;
176*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
177*288bf522SAndroid Build Coastguard Worker 
178*288bf522SAndroid Build Coastguard Worker     if (erase) {
179*288bf522SAndroid Build Coastguard Worker         f = fopen(GLOBAL_STATS_FILE, "w");
180*288bf522SAndroid Build Coastguard Worker         if (!f) {
181*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
182*288bf522SAndroid Build Coastguard Worker             exit(EXIT_FAILURE);
183*288bf522SAndroid Build Coastguard Worker         }
184*288bf522SAndroid Build Coastguard Worker         fprintf(f, "erase\n");
185*288bf522SAndroid Build Coastguard Worker         fclose(f);
186*288bf522SAndroid Build Coastguard Worker     }
187*288bf522SAndroid Build Coastguard Worker 
188*288bf522SAndroid Build Coastguard Worker     f = fopen(GLOBAL_STATS_FILE, "r");
189*288bf522SAndroid Build Coastguard Worker     if (!f) {
190*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
191*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
192*288bf522SAndroid Build Coastguard Worker     }
193*288bf522SAndroid Build Coastguard Worker 
194*288bf522SAndroid Build Coastguard Worker     e = read_latency_file(f, list);
195*288bf522SAndroid Build Coastguard Worker 
196*288bf522SAndroid Build Coastguard Worker     fclose(f);
197*288bf522SAndroid Build Coastguard Worker 
198*288bf522SAndroid Build Coastguard Worker     return e;
199*288bf522SAndroid Build Coastguard Worker }
200*288bf522SAndroid Build Coastguard Worker 
read_process_stats(struct latency_entry * list,int erase,int pid)201*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_process_stats(struct latency_entry* list, int erase, int pid) {
202*288bf522SAndroid Build Coastguard Worker     char dirname[MAX_FILENAME];
203*288bf522SAndroid Build Coastguard Worker     DIR* dir;
204*288bf522SAndroid Build Coastguard Worker     struct dirent* ent;
205*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
206*288bf522SAndroid Build Coastguard Worker     int tid;
207*288bf522SAndroid Build Coastguard Worker 
208*288bf522SAndroid Build Coastguard Worker     sprintf(dirname, "/proc/%d/task", pid);
209*288bf522SAndroid Build Coastguard Worker     dir = opendir(dirname);
210*288bf522SAndroid Build Coastguard Worker     if (!dir) {
211*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Could not open task dir for process %d.\n", pid);
212*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Perhaps the process has terminated?\n");
213*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
214*288bf522SAndroid Build Coastguard Worker     }
215*288bf522SAndroid Build Coastguard Worker 
216*288bf522SAndroid Build Coastguard Worker     e = list;
217*288bf522SAndroid Build Coastguard Worker     while ((ent = readdir(dir))) {
218*288bf522SAndroid Build Coastguard Worker         if (!isdigit(ent->d_name[0])) continue;
219*288bf522SAndroid Build Coastguard Worker 
220*288bf522SAndroid Build Coastguard Worker         tid = atoi(ent->d_name);
221*288bf522SAndroid Build Coastguard Worker 
222*288bf522SAndroid Build Coastguard Worker         e = read_thread_stats(e, erase, pid, tid, 0);
223*288bf522SAndroid Build Coastguard Worker     }
224*288bf522SAndroid Build Coastguard Worker 
225*288bf522SAndroid Build Coastguard Worker     closedir(dir);
226*288bf522SAndroid Build Coastguard Worker 
227*288bf522SAndroid Build Coastguard Worker     return e;
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker 
read_thread_stats(struct latency_entry * list,int erase,int pid,int tid,int fatal)230*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_thread_stats(struct latency_entry* list, int erase, int pid,
231*288bf522SAndroid Build Coastguard Worker                                                int tid, int fatal) {
232*288bf522SAndroid Build Coastguard Worker     char filename[MAX_FILENAME];
233*288bf522SAndroid Build Coastguard Worker     FILE* f;
234*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
235*288bf522SAndroid Build Coastguard Worker 
236*288bf522SAndroid Build Coastguard Worker     sprintf(filename, THREAD_STATS_FILE_FORMAT, pid, tid);
237*288bf522SAndroid Build Coastguard Worker 
238*288bf522SAndroid Build Coastguard Worker     if (erase) {
239*288bf522SAndroid Build Coastguard Worker         f = fopen(filename, "w");
240*288bf522SAndroid Build Coastguard Worker         if (!f) {
241*288bf522SAndroid Build Coastguard Worker             if (fatal) {
242*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
243*288bf522SAndroid Build Coastguard Worker                 fprintf(stderr, "Perhaps the process or thread has terminated?\n");
244*288bf522SAndroid Build Coastguard Worker                 exit(EXIT_FAILURE);
245*288bf522SAndroid Build Coastguard Worker             } else {
246*288bf522SAndroid Build Coastguard Worker                 return list;
247*288bf522SAndroid Build Coastguard Worker             }
248*288bf522SAndroid Build Coastguard Worker         }
249*288bf522SAndroid Build Coastguard Worker         fprintf(f, "erase\n");
250*288bf522SAndroid Build Coastguard Worker         fclose(f);
251*288bf522SAndroid Build Coastguard Worker     }
252*288bf522SAndroid Build Coastguard Worker 
253*288bf522SAndroid Build Coastguard Worker     f = fopen(GLOBAL_STATS_FILE, "r");
254*288bf522SAndroid Build Coastguard Worker     if (!f) {
255*288bf522SAndroid Build Coastguard Worker         if (fatal) {
256*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
257*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Perhaps the process or thread has terminated?\n");
258*288bf522SAndroid Build Coastguard Worker             exit(EXIT_FAILURE);
259*288bf522SAndroid Build Coastguard Worker         } else {
260*288bf522SAndroid Build Coastguard Worker             return list;
261*288bf522SAndroid Build Coastguard Worker         }
262*288bf522SAndroid Build Coastguard Worker     }
263*288bf522SAndroid Build Coastguard Worker 
264*288bf522SAndroid Build Coastguard Worker     e = read_latency_file(f, list);
265*288bf522SAndroid Build Coastguard Worker 
266*288bf522SAndroid Build Coastguard Worker     fclose(f);
267*288bf522SAndroid Build Coastguard Worker 
268*288bf522SAndroid Build Coastguard Worker     return e;
269*288bf522SAndroid Build Coastguard Worker }
270*288bf522SAndroid Build Coastguard Worker 
alloc_latency_entry(void)271*288bf522SAndroid Build Coastguard Worker static struct latency_entry* alloc_latency_entry(void) {
272*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
273*288bf522SAndroid Build Coastguard Worker 
274*288bf522SAndroid Build Coastguard Worker     if (free_entries) {
275*288bf522SAndroid Build Coastguard Worker         e = free_entries;
276*288bf522SAndroid Build Coastguard Worker         free_entries = free_entries->next;
277*288bf522SAndroid Build Coastguard Worker     } else {
278*288bf522SAndroid Build Coastguard Worker         e = calloc(1, sizeof(struct latency_entry));
279*288bf522SAndroid Build Coastguard Worker         if (!e) {
280*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Could not allocate latency entry: %s\n", strerror(errno));
281*288bf522SAndroid Build Coastguard Worker             exit(EXIT_FAILURE);
282*288bf522SAndroid Build Coastguard Worker         }
283*288bf522SAndroid Build Coastguard Worker     }
284*288bf522SAndroid Build Coastguard Worker 
285*288bf522SAndroid Build Coastguard Worker     return e;
286*288bf522SAndroid Build Coastguard Worker }
287*288bf522SAndroid Build Coastguard Worker 
find_latency_entry(struct latency_entry * head,char * reason)288*288bf522SAndroid Build Coastguard Worker static struct latency_entry* find_latency_entry(struct latency_entry* head, char* reason) {
289*288bf522SAndroid Build Coastguard Worker     struct latency_entry* e;
290*288bf522SAndroid Build Coastguard Worker 
291*288bf522SAndroid Build Coastguard Worker     e = head;
292*288bf522SAndroid Build Coastguard Worker 
293*288bf522SAndroid Build Coastguard Worker     while (e) {
294*288bf522SAndroid Build Coastguard Worker         if (!strcmp(e->reason, reason)) return e;
295*288bf522SAndroid Build Coastguard Worker         e = e->next;
296*288bf522SAndroid Build Coastguard Worker     }
297*288bf522SAndroid Build Coastguard Worker 
298*288bf522SAndroid Build Coastguard Worker     return NULL;
299*288bf522SAndroid Build Coastguard Worker }
300*288bf522SAndroid Build Coastguard Worker 
set_latencytop(int on)301*288bf522SAndroid Build Coastguard Worker static void set_latencytop(int on) {
302*288bf522SAndroid Build Coastguard Worker     FILE* f;
303*288bf522SAndroid Build Coastguard Worker 
304*288bf522SAndroid Build Coastguard Worker     f = fopen(SYSCTL_FILE, "w");
305*288bf522SAndroid Build Coastguard Worker     if (!f) {
306*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Could not open %s: %s\n", SYSCTL_FILE, strerror(errno));
307*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
308*288bf522SAndroid Build Coastguard Worker     }
309*288bf522SAndroid Build Coastguard Worker 
310*288bf522SAndroid Build Coastguard Worker     fprintf(f, "%d\n", on);
311*288bf522SAndroid Build Coastguard Worker 
312*288bf522SAndroid Build Coastguard Worker     fclose(f);
313*288bf522SAndroid Build Coastguard Worker }
314*288bf522SAndroid Build Coastguard Worker 
read_latency_file(FILE * f,struct latency_entry * list)315*288bf522SAndroid Build Coastguard Worker static struct latency_entry* read_latency_file(FILE* f, struct latency_entry* list) {
316*288bf522SAndroid Build Coastguard Worker     struct latency_entry *e, *head;
317*288bf522SAndroid Build Coastguard Worker     char line[MAX_LINE];
318*288bf522SAndroid Build Coastguard Worker     unsigned long count, max, total;
319*288bf522SAndroid Build Coastguard Worker     char reason[MAX_LINE];
320*288bf522SAndroid Build Coastguard Worker 
321*288bf522SAndroid Build Coastguard Worker     head = list;
322*288bf522SAndroid Build Coastguard Worker 
323*288bf522SAndroid Build Coastguard Worker     if (!fgets(line, MAX_LINE, f)) {
324*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Could not read latency file version: %s\n", strerror(errno));
325*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
326*288bf522SAndroid Build Coastguard Worker     }
327*288bf522SAndroid Build Coastguard Worker 
328*288bf522SAndroid Build Coastguard Worker     if (strcmp(line, EXPECTED_VERSION) != 0) {
329*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Expected version: %s\n", EXPECTED_VERSION);
330*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "But got version: %s", line);
331*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
332*288bf522SAndroid Build Coastguard Worker     }
333*288bf522SAndroid Build Coastguard Worker 
334*288bf522SAndroid Build Coastguard Worker     while (fgets(line, MAX_LINE, f)) {
335*288bf522SAndroid Build Coastguard Worker         sscanf(line, "%ld %ld %ld %s", &count, &total, &max, reason);
336*288bf522SAndroid Build Coastguard Worker         if (max > 0 || total > 0) {
337*288bf522SAndroid Build Coastguard Worker             e = find_latency_entry(head, reason);
338*288bf522SAndroid Build Coastguard Worker             if (e) {
339*288bf522SAndroid Build Coastguard Worker                 e->count += count;
340*288bf522SAndroid Build Coastguard Worker                 if (max > e->max) e->max = max;
341*288bf522SAndroid Build Coastguard Worker                 e->total += total;
342*288bf522SAndroid Build Coastguard Worker             } else {
343*288bf522SAndroid Build Coastguard Worker                 e = alloc_latency_entry();
344*288bf522SAndroid Build Coastguard Worker                 e->count = count;
345*288bf522SAndroid Build Coastguard Worker                 e->max = max;
346*288bf522SAndroid Build Coastguard Worker                 e->total = total;
347*288bf522SAndroid Build Coastguard Worker                 strcpy(e->reason, reason);
348*288bf522SAndroid Build Coastguard Worker                 e->next = head;
349*288bf522SAndroid Build Coastguard Worker                 head = e;
350*288bf522SAndroid Build Coastguard Worker             }
351*288bf522SAndroid Build Coastguard Worker         }
352*288bf522SAndroid Build Coastguard Worker     }
353*288bf522SAndroid Build Coastguard Worker 
354*288bf522SAndroid Build Coastguard Worker     return head;
355*288bf522SAndroid Build Coastguard Worker }
356*288bf522SAndroid Build Coastguard Worker 
print_latency_entries(struct latency_entry * head)357*288bf522SAndroid Build Coastguard Worker static void print_latency_entries(struct latency_entry* head) {
358*288bf522SAndroid Build Coastguard Worker     struct latency_entry *e, **array;
359*288bf522SAndroid Build Coastguard Worker     unsigned long average;
360*288bf522SAndroid Build Coastguard Worker     int i, count;
361*288bf522SAndroid Build Coastguard Worker 
362*288bf522SAndroid Build Coastguard Worker     e = head;
363*288bf522SAndroid Build Coastguard Worker     count = 0;
364*288bf522SAndroid Build Coastguard Worker     while (e) {
365*288bf522SAndroid Build Coastguard Worker         count++;
366*288bf522SAndroid Build Coastguard Worker         e = e->next;
367*288bf522SAndroid Build Coastguard Worker     }
368*288bf522SAndroid Build Coastguard Worker 
369*288bf522SAndroid Build Coastguard Worker     e = head;
370*288bf522SAndroid Build Coastguard Worker     array = calloc(count, sizeof(struct latency_entry*));
371*288bf522SAndroid Build Coastguard Worker     if (!array) {
372*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Error allocating array: %s\n", strerror(errno));
373*288bf522SAndroid Build Coastguard Worker         exit(EXIT_FAILURE);
374*288bf522SAndroid Build Coastguard Worker     }
375*288bf522SAndroid Build Coastguard Worker     for (i = 0; i < count; i++) {
376*288bf522SAndroid Build Coastguard Worker         array[i] = e;
377*288bf522SAndroid Build Coastguard Worker         e = e->next;
378*288bf522SAndroid Build Coastguard Worker     }
379*288bf522SAndroid Build Coastguard Worker 
380*288bf522SAndroid Build Coastguard Worker     qsort(array, count, sizeof(struct latency_entry*), &lat_cmp);
381*288bf522SAndroid Build Coastguard Worker 
382*288bf522SAndroid Build Coastguard Worker     printf("%10s  %10s  %7s  %s\n", "Maximum", "Average", "Count", "Reason");
383*288bf522SAndroid Build Coastguard Worker     for (i = 0; i < count; i++) {
384*288bf522SAndroid Build Coastguard Worker         e = array[i];
385*288bf522SAndroid Build Coastguard Worker         average = e->total / e->count;
386*288bf522SAndroid Build Coastguard Worker         printf("%4lu.%02lu ms  %4lu.%02lu ms  %7ld  %s\n", e->max / 1000, (e->max % 1000) / 10,
387*288bf522SAndroid Build Coastguard Worker                average / 1000, (average % 1000) / 10, e->count, e->reason);
388*288bf522SAndroid Build Coastguard Worker     }
389*288bf522SAndroid Build Coastguard Worker 
390*288bf522SAndroid Build Coastguard Worker     free(array);
391*288bf522SAndroid Build Coastguard Worker }
392*288bf522SAndroid Build Coastguard Worker 
signal_handler(int sig)393*288bf522SAndroid Build Coastguard Worker static void signal_handler(int sig) {
394*288bf522SAndroid Build Coastguard Worker     exit(EXIT_SUCCESS);
395*288bf522SAndroid Build Coastguard Worker }
396*288bf522SAndroid Build Coastguard Worker 
disable_latencytop(void)397*288bf522SAndroid Build Coastguard Worker static void disable_latencytop(void) {
398*288bf522SAndroid Build Coastguard Worker     set_latencytop(0);
399*288bf522SAndroid Build Coastguard Worker }
400*288bf522SAndroid Build Coastguard Worker 
clear_screen(void)401*288bf522SAndroid Build Coastguard Worker static void clear_screen(void) {
402*288bf522SAndroid Build Coastguard Worker     printf("\n\n");
403*288bf522SAndroid Build Coastguard Worker }
404*288bf522SAndroid Build Coastguard Worker 
usage(const char * cmd)405*288bf522SAndroid Build Coastguard Worker static void usage(const char* cmd) {
406*288bf522SAndroid Build Coastguard Worker     fprintf(stderr,
407*288bf522SAndroid Build Coastguard Worker             "Usage: %s [ -d delay ] [ -n iterations ] [ -p pid [ -t tid ] ] [ -h ]\n"
408*288bf522SAndroid Build Coastguard Worker             "    -d delay       Time to sleep between updates.\n"
409*288bf522SAndroid Build Coastguard Worker             "    -n iterations  Number of updates to show (0 = infinite).\n"
410*288bf522SAndroid Build Coastguard Worker             "    -p pid         Process to monitor (default is all).\n"
411*288bf522SAndroid Build Coastguard Worker             "    -t tid         Thread (within specified process) to monitor (default is all).\n"
412*288bf522SAndroid Build Coastguard Worker             "    -h             Display this help screen.\n",
413*288bf522SAndroid Build Coastguard Worker             cmd);
414*288bf522SAndroid Build Coastguard Worker }
415*288bf522SAndroid Build Coastguard Worker 
numcmp(const long long a,const long long b)416*288bf522SAndroid Build Coastguard Worker static int numcmp(const long long a, const long long b) {
417*288bf522SAndroid Build Coastguard Worker     if (a < b) return -1;
418*288bf522SAndroid Build Coastguard Worker     if (a > b) return 1;
419*288bf522SAndroid Build Coastguard Worker     return 0;
420*288bf522SAndroid Build Coastguard Worker }
421*288bf522SAndroid Build Coastguard Worker 
lat_cmp(const void * a,const void * b)422*288bf522SAndroid Build Coastguard Worker static int lat_cmp(const void* a, const void* b) {
423*288bf522SAndroid Build Coastguard Worker     const struct latency_entry *pa, *pb;
424*288bf522SAndroid Build Coastguard Worker 
425*288bf522SAndroid Build Coastguard Worker     pa = (*((struct latency_entry**)a));
426*288bf522SAndroid Build Coastguard Worker     pb = (*((struct latency_entry**)b));
427*288bf522SAndroid Build Coastguard Worker 
428*288bf522SAndroid Build Coastguard Worker     return numcmp(pb->max, pa->max);
429*288bf522SAndroid Build Coastguard Worker }
430