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