xref: /aosp_15_r20/external/autotest/client/profilers/powertop/src/powertop.c (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li /*
2*9c5db199SXin Li  * Copyright 2007, Intel Corporation
3*9c5db199SXin Li  *
4*9c5db199SXin Li  * This file is part of PowerTOP
5*9c5db199SXin Li  *
6*9c5db199SXin Li  * This program file is free software; you can redistribute it and/or modify it
7*9c5db199SXin Li  * under the terms of the GNU General Public License as published by the
8*9c5db199SXin Li  * Free Software Foundation; version 2 of the License.
9*9c5db199SXin Li  *
10*9c5db199SXin Li  * This program is distributed in the hope that it will be useful, but WITHOUT
11*9c5db199SXin Li  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*9c5db199SXin Li  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13*9c5db199SXin Li  * for more details.
14*9c5db199SXin Li  *
15*9c5db199SXin Li  * You should have received a copy of the GNU General Public License
16*9c5db199SXin Li  * along with this program in a file named COPYING; if not, write to the
17*9c5db199SXin Li  * Free Software Foundation, Inc.,
18*9c5db199SXin Li  * 51 Franklin Street, Fifth Floor,
19*9c5db199SXin Li  * Boston, MA 02110-1301 USA
20*9c5db199SXin Li  *
21*9c5db199SXin Li  * Authors:
22*9c5db199SXin Li  * 	Arjan van de Ven <[email protected]>
23*9c5db199SXin Li  */
24*9c5db199SXin Li 
25*9c5db199SXin Li #include <getopt.h>
26*9c5db199SXin Li #include <unistd.h>
27*9c5db199SXin Li #include <stdio.h>
28*9c5db199SXin Li #include <stdlib.h>
29*9c5db199SXin Li #include <string.h>
30*9c5db199SXin Li #include <stdint.h>
31*9c5db199SXin Li #include <sys/types.h>
32*9c5db199SXin Li #include <dirent.h>
33*9c5db199SXin Li #include <libintl.h>
34*9c5db199SXin Li #include <ctype.h>
35*9c5db199SXin Li #include <assert.h>
36*9c5db199SXin Li #include <locale.h>
37*9c5db199SXin Li #include <time.h>
38*9c5db199SXin Li #include <sys/stat.h>
39*9c5db199SXin Li 
40*9c5db199SXin Li #include "powertop.h"
41*9c5db199SXin Li 
42*9c5db199SXin Li #define VERSION "1.11"
43*9c5db199SXin Li 
44*9c5db199SXin Li uint64_t start_usage[8], start_duration[8];
45*9c5db199SXin Li uint64_t last_usage[8], last_duration[8];
46*9c5db199SXin Li char cnames[8][16];
47*9c5db199SXin Li 
48*9c5db199SXin Li double ticktime = 15.0;
49*9c5db199SXin Li 
50*9c5db199SXin Li int interrupt_0, total_interrupt;
51*9c5db199SXin Li 
52*9c5db199SXin Li int showpids = 0;
53*9c5db199SXin Li 
54*9c5db199SXin Li static int maxcstate = 0;
55*9c5db199SXin Li int topcstate = 0;
56*9c5db199SXin Li 
57*9c5db199SXin Li int dump = 0;
58*9c5db199SXin Li 
59*9c5db199SXin Li #define IRQCOUNT 150
60*9c5db199SXin Li 
61*9c5db199SXin Li struct irqdata {
62*9c5db199SXin Li 	int active;
63*9c5db199SXin Li 	int number;
64*9c5db199SXin Li 	uint64_t count;
65*9c5db199SXin Li 	char description[256];
66*9c5db199SXin Li };
67*9c5db199SXin Li 
68*9c5db199SXin Li struct irqdata interrupts[IRQCOUNT];
69*9c5db199SXin Li 
70*9c5db199SXin Li #define FREQ_ACPI 3579.545
71*9c5db199SXin Li static unsigned long FREQ;
72*9c5db199SXin Li 
73*9c5db199SXin Li int nostats;
74*9c5db199SXin Li 
75*9c5db199SXin Li 
76*9c5db199SXin Li struct line	*lines;
77*9c5db199SXin Li int		linehead;
78*9c5db199SXin Li int		linesize;
79*9c5db199SXin Li int		linectotal;
80*9c5db199SXin Li 
81*9c5db199SXin Li 
82*9c5db199SXin Li double last_bat_cap = 0;
83*9c5db199SXin Li double prev_bat_cap = 0;
84*9c5db199SXin Li time_t last_bat_time = 0;
85*9c5db199SXin Li time_t prev_bat_time = 0;
86*9c5db199SXin Li 
87*9c5db199SXin Li double displaytime = 0.0;
88*9c5db199SXin Li 
push_line(char * string,int count)89*9c5db199SXin Li void push_line(char *string, int count)
90*9c5db199SXin Li {
91*9c5db199SXin Li 	int i;
92*9c5db199SXin Li 
93*9c5db199SXin Li 	assert(string != NULL);
94*9c5db199SXin Li 	for (i = 0; i < linehead; i++)
95*9c5db199SXin Li 		if (strcmp(string, lines[i].string) == 0) {
96*9c5db199SXin Li 			lines[i].count += count;
97*9c5db199SXin Li 			return;
98*9c5db199SXin Li 		}
99*9c5db199SXin Li 	if (linehead == linesize)
100*9c5db199SXin Li 		lines = realloc (lines, (linesize ? (linesize *= 2) : (linesize = 64)) * sizeof (struct line));
101*9c5db199SXin Li 	lines[linehead].string = strdup (string);
102*9c5db199SXin Li 	lines[linehead].count = count;
103*9c5db199SXin Li 	lines[linehead].pid[0] = 0;
104*9c5db199SXin Li 	linehead++;
105*9c5db199SXin Li }
106*9c5db199SXin Li 
push_line_pid(char * string,int count,char * pid)107*9c5db199SXin Li void push_line_pid(char *string, int count, char *pid)
108*9c5db199SXin Li {
109*9c5db199SXin Li 	int i;
110*9c5db199SXin Li 	assert(string != NULL);
111*9c5db199SXin Li 	for (i = 0; i < linehead; i++)
112*9c5db199SXin Li 		if (strcmp(string, lines[i].string) == 0) {
113*9c5db199SXin Li 			lines[i].count += count;
114*9c5db199SXin Li 			if (pid && strcmp(lines[i].pid, pid)!=0)
115*9c5db199SXin Li 				lines[i].pid[0] = 0;
116*9c5db199SXin Li 			return;
117*9c5db199SXin Li 		}
118*9c5db199SXin Li 	if (linehead == linesize)
119*9c5db199SXin Li 		lines = realloc (lines, (linesize ? (linesize *= 2) : (linesize = 64)) * sizeof (struct line));
120*9c5db199SXin Li 	lines[linehead].string = strdup (string);
121*9c5db199SXin Li 	lines[linehead].count = count;
122*9c5db199SXin Li 	if (pid)
123*9c5db199SXin Li 		strcpy(lines[linehead].pid, pid);
124*9c5db199SXin Li 	linehead++;
125*9c5db199SXin Li }
126*9c5db199SXin Li 
clear_lines(void)127*9c5db199SXin Li void clear_lines(void)
128*9c5db199SXin Li {
129*9c5db199SXin Li 	int i;
130*9c5db199SXin Li 	for (i = 0; i < linehead; i++)
131*9c5db199SXin Li 		free (lines[i].string);
132*9c5db199SXin Li 	free (lines);
133*9c5db199SXin Li 	linehead = linesize = 0;
134*9c5db199SXin Li 	lines = NULL;
135*9c5db199SXin Li }
136*9c5db199SXin Li 
count_lines(void)137*9c5db199SXin Li void count_lines(void)
138*9c5db199SXin Li {
139*9c5db199SXin Li 	uint64_t q = 0;
140*9c5db199SXin Li 	int i;
141*9c5db199SXin Li 	for (i = 0; i < linehead; i++)
142*9c5db199SXin Li 		q += lines[i].count;
143*9c5db199SXin Li 	linectotal = q;
144*9c5db199SXin Li }
145*9c5db199SXin Li 
update_irq(int irq,uint64_t count,char * name)146*9c5db199SXin Li int update_irq(int irq, uint64_t count, char *name)
147*9c5db199SXin Li {
148*9c5db199SXin Li 	int i;
149*9c5db199SXin Li 	int firstfree = IRQCOUNT;
150*9c5db199SXin Li 
151*9c5db199SXin Li 	if (!name)
152*9c5db199SXin Li 		return 0;
153*9c5db199SXin Li 
154*9c5db199SXin Li 	for (i = 0; i < IRQCOUNT; i++) {
155*9c5db199SXin Li 		if (interrupts[i].active && interrupts[i].number == irq) {
156*9c5db199SXin Li 			uint64_t oldcount;
157*9c5db199SXin Li 			oldcount = interrupts[i].count;
158*9c5db199SXin Li 			interrupts[i].count = count;
159*9c5db199SXin Li 			return count - oldcount;
160*9c5db199SXin Li 		}
161*9c5db199SXin Li 		if (!interrupts[i].active && firstfree > i)
162*9c5db199SXin Li 			firstfree = i;
163*9c5db199SXin Li 	}
164*9c5db199SXin Li 
165*9c5db199SXin Li 	interrupts[firstfree].active = 1;
166*9c5db199SXin Li 	interrupts[firstfree].count = count;
167*9c5db199SXin Li 	interrupts[firstfree].number = irq;
168*9c5db199SXin Li 	strcpy(interrupts[firstfree].description, name);
169*9c5db199SXin Li 	if (strcmp(name,"i8042\n")==0)
170*9c5db199SXin Li 		strcpy(interrupts[firstfree].description, _("PS/2 keyboard/mouse/touchpad"));
171*9c5db199SXin Li 	return count;
172*9c5db199SXin Li }
173*9c5db199SXin Li 
do_proc_irq(void)174*9c5db199SXin Li static void do_proc_irq(void)
175*9c5db199SXin Li {
176*9c5db199SXin Li 	FILE *file;
177*9c5db199SXin Li 	char line[1024];
178*9c5db199SXin Li 	char line2[1024];
179*9c5db199SXin Li 	char *name;
180*9c5db199SXin Li 	uint64_t delta;
181*9c5db199SXin Li 
182*9c5db199SXin Li 	interrupt_0 = 0;
183*9c5db199SXin Li 	total_interrupt  = 0;
184*9c5db199SXin Li 
185*9c5db199SXin Li 	file = fopen("/proc/interrupts", "r");
186*9c5db199SXin Li 	if (!file)
187*9c5db199SXin Li 		return;
188*9c5db199SXin Li 	while (!feof(file)) {
189*9c5db199SXin Li 		char *c;
190*9c5db199SXin Li 		int nr = -1;
191*9c5db199SXin Li 		uint64_t count = 0;
192*9c5db199SXin Li 		int special = 0;
193*9c5db199SXin Li 		memset(line, 0, sizeof(line));
194*9c5db199SXin Li 		if (fgets(line, 1024, file) == NULL)
195*9c5db199SXin Li 			break;
196*9c5db199SXin Li 		c = strchr(line, ':');
197*9c5db199SXin Li 		if (!c)
198*9c5db199SXin Li 			continue;
199*9c5db199SXin Li 		/* deal with NMI and the like.. make up fake nrs */
200*9c5db199SXin Li 		if (line[0] != ' ' && (line[0] < '0' || line[0] > '9')) {
201*9c5db199SXin Li 			if (strncmp(line,"NMI:", 4)==0)
202*9c5db199SXin Li 				nr=20000;
203*9c5db199SXin Li 			if (strncmp(line,"RES:", 4)==0)
204*9c5db199SXin Li 				nr=20001;
205*9c5db199SXin Li 			if (strncmp(line,"CAL:", 4)==0)
206*9c5db199SXin Li 				nr=20002;
207*9c5db199SXin Li 			if (strncmp(line,"TLB:", 4)==0)
208*9c5db199SXin Li 				nr=20003;
209*9c5db199SXin Li 			if (strncmp(line,"TRM:", 4)==0)
210*9c5db199SXin Li 				nr=20004;
211*9c5db199SXin Li 			if (strncmp(line,"THR:", 4)==0)
212*9c5db199SXin Li 				nr=20005;
213*9c5db199SXin Li 			if (strncmp(line,"SPU:", 4)==0)
214*9c5db199SXin Li 				nr=20006;
215*9c5db199SXin Li 			special = 1;
216*9c5db199SXin Li 		} else
217*9c5db199SXin Li 			nr = strtoull(line, NULL, 10);
218*9c5db199SXin Li 
219*9c5db199SXin Li 		if (nr==-1)
220*9c5db199SXin Li 			continue;
221*9c5db199SXin Li 		*c = 0;
222*9c5db199SXin Li 		c++;
223*9c5db199SXin Li 		while (c && strlen(c)) {
224*9c5db199SXin Li 			char *newc;
225*9c5db199SXin Li 			count += strtoull(c, &newc, 10);
226*9c5db199SXin Li 			if (newc == c)
227*9c5db199SXin Li 				break;
228*9c5db199SXin Li 			c = newc;
229*9c5db199SXin Li 		}
230*9c5db199SXin Li 		c = strchr(c, ' ');
231*9c5db199SXin Li 		if (!c)
232*9c5db199SXin Li 			continue;
233*9c5db199SXin Li 		while (c && *c == ' ')
234*9c5db199SXin Li 			c++;
235*9c5db199SXin Li 		if (!special) {
236*9c5db199SXin Li 			c = strchr(c, ' ');
237*9c5db199SXin Li 			if (!c)
238*9c5db199SXin Li 				continue;
239*9c5db199SXin Li 			while (c && *c == ' ')
240*9c5db199SXin Li 				c++;
241*9c5db199SXin Li 		}
242*9c5db199SXin Li 		name = c;
243*9c5db199SXin Li 		delta = update_irq(nr, count, name);
244*9c5db199SXin Li 		c = strchr(name, '\n');
245*9c5db199SXin Li 		if (c)
246*9c5db199SXin Li 			*c = 0;
247*9c5db199SXin Li 		if (strcmp(name, "i8042")) {
248*9c5db199SXin Li 			if (special)
249*9c5db199SXin Li 				sprintf(line2, _("   <kernel IPI> : %s"), name);
250*9c5db199SXin Li 			else
251*9c5db199SXin Li 				sprintf(line2, _("    <interrupt> : %s"), name);
252*9c5db199SXin Li 		}
253*9c5db199SXin Li 		else
254*9c5db199SXin Li 			sprintf(line2, _("    <interrupt> : %s"), _("PS/2 keyboard/mouse/touchpad"));
255*9c5db199SXin Li 
256*9c5db199SXin Li 		if (nr > 0 && delta > 0)
257*9c5db199SXin Li 			push_line(line2, delta);
258*9c5db199SXin Li 		if (nr==0)
259*9c5db199SXin Li 			interrupt_0 = delta;
260*9c5db199SXin Li 		else
261*9c5db199SXin Li 			total_interrupt += delta;
262*9c5db199SXin Li 	}
263*9c5db199SXin Li 	fclose(file);
264*9c5db199SXin Li }
265*9c5db199SXin Li 
read_data_acpi(uint64_t * usage,uint64_t * duration)266*9c5db199SXin Li static void read_data_acpi(uint64_t * usage, uint64_t * duration)
267*9c5db199SXin Li {
268*9c5db199SXin Li 	DIR *dir;
269*9c5db199SXin Li 	struct dirent *entry;
270*9c5db199SXin Li 	FILE *file = NULL;
271*9c5db199SXin Li 	char line[4096];
272*9c5db199SXin Li 	char *c;
273*9c5db199SXin Li 	int clevel = 0;
274*9c5db199SXin Li 
275*9c5db199SXin Li 	memset(usage, 0, 64);
276*9c5db199SXin Li 	memset(duration, 0, 64);
277*9c5db199SXin Li 
278*9c5db199SXin Li 	dir = opendir("/proc/acpi/processor");
279*9c5db199SXin Li 	if (!dir)
280*9c5db199SXin Li 		return;
281*9c5db199SXin Li 	while ((entry = readdir(dir))) {
282*9c5db199SXin Li 		if (strlen(entry->d_name) < 3)
283*9c5db199SXin Li 			continue;
284*9c5db199SXin Li 		sprintf(line, "/proc/acpi/processor/%s/power", entry->d_name);
285*9c5db199SXin Li 		file = fopen(line, "r");
286*9c5db199SXin Li 		if (!file)
287*9c5db199SXin Li 			continue;
288*9c5db199SXin Li 
289*9c5db199SXin Li 		clevel = 0;
290*9c5db199SXin Li 
291*9c5db199SXin Li 		while (!feof(file)) {
292*9c5db199SXin Li 			memset(line, 0, 4096);
293*9c5db199SXin Li 			if (fgets(line, 4096, file) == NULL)
294*9c5db199SXin Li 				break;
295*9c5db199SXin Li 			c = strstr(line, "age[");
296*9c5db199SXin Li 			if (!c)
297*9c5db199SXin Li 				continue;
298*9c5db199SXin Li 			c += 4;
299*9c5db199SXin Li 			usage[clevel] += 1+strtoull(c, NULL, 10);
300*9c5db199SXin Li 			c = strstr(line, "ation[");
301*9c5db199SXin Li 			if (!c)
302*9c5db199SXin Li 				continue;
303*9c5db199SXin Li 			c += 6;
304*9c5db199SXin Li 			duration[clevel] += strtoull(c, NULL, 10);
305*9c5db199SXin Li 
306*9c5db199SXin Li 			clevel++;
307*9c5db199SXin Li 			if (clevel > maxcstate)
308*9c5db199SXin Li 				maxcstate = clevel;
309*9c5db199SXin Li 
310*9c5db199SXin Li 		}
311*9c5db199SXin Li 		fclose(file);
312*9c5db199SXin Li 	}
313*9c5db199SXin Li 	closedir(dir);
314*9c5db199SXin Li }
315*9c5db199SXin Li 
read_data_cpuidle(uint64_t * usage,uint64_t * duration)316*9c5db199SXin Li static void read_data_cpuidle(uint64_t * usage, uint64_t * duration)
317*9c5db199SXin Li {
318*9c5db199SXin Li 	DIR *cpudir;
319*9c5db199SXin Li 	DIR *dir;
320*9c5db199SXin Li 	struct dirent *entry;
321*9c5db199SXin Li 	FILE *file = NULL;
322*9c5db199SXin Li 	char line[4096];
323*9c5db199SXin Li 	char filename[128], *f;
324*9c5db199SXin Li 	int len, clevel = 0;
325*9c5db199SXin Li 
326*9c5db199SXin Li 	memset(usage, 0, 64);
327*9c5db199SXin Li 	memset(duration, 0, 64);
328*9c5db199SXin Li 
329*9c5db199SXin Li 	cpudir = opendir("/sys/devices/system/cpu");
330*9c5db199SXin Li 	if (!cpudir)
331*9c5db199SXin Li 		return;
332*9c5db199SXin Li 
333*9c5db199SXin Li 	/* Loop over cpuN entries */
334*9c5db199SXin Li 	while ((entry = readdir(cpudir))) {
335*9c5db199SXin Li 		if (strlen(entry->d_name) < 3)
336*9c5db199SXin Li 			continue;
337*9c5db199SXin Li 
338*9c5db199SXin Li 		if (!isdigit(entry->d_name[3]))
339*9c5db199SXin Li 			continue;
340*9c5db199SXin Li 
341*9c5db199SXin Li 		len = sprintf(filename, "/sys/devices/system/cpu/%s/cpuidle",
342*9c5db199SXin Li 			      entry->d_name);
343*9c5db199SXin Li 
344*9c5db199SXin Li 		dir = opendir(filename);
345*9c5db199SXin Li 		if (!dir)
346*9c5db199SXin Li 			return;
347*9c5db199SXin Li 
348*9c5db199SXin Li 		clevel = 0;
349*9c5db199SXin Li 
350*9c5db199SXin Li 		/* For each C-state, there is a stateX directory which
351*9c5db199SXin Li 		 * contains a 'usage' and a 'time' (duration) file */
352*9c5db199SXin Li 		while ((entry = readdir(dir))) {
353*9c5db199SXin Li 			if (strlen(entry->d_name) < 3)
354*9c5db199SXin Li 				continue;
355*9c5db199SXin Li 			sprintf(filename + len, "/%s/desc", entry->d_name);
356*9c5db199SXin Li 			file = fopen(filename, "r");
357*9c5db199SXin Li 			if (file) {
358*9c5db199SXin Li 
359*9c5db199SXin Li 				memset(line, 0, 4096);
360*9c5db199SXin Li 				f = fgets(line, 4096, file);
361*9c5db199SXin Li 				fclose(file);
362*9c5db199SXin Li 				if (f == NULL)
363*9c5db199SXin Li 					break;
364*9c5db199SXin Li 
365*9c5db199SXin Li 
366*9c5db199SXin Li 				f = strstr(line, "MWAIT ");
367*9c5db199SXin Li 				if (f) {
368*9c5db199SXin Li 					f += 6;
369*9c5db199SXin Li 					clevel = (strtoull(f, NULL, 16)>>4) + 1;
370*9c5db199SXin Li 					sprintf(cnames[clevel], "C%i mwait", clevel);
371*9c5db199SXin Li 				} else
372*9c5db199SXin Li 					sprintf(cnames[clevel], "C%i\t", clevel);
373*9c5db199SXin Li 
374*9c5db199SXin Li 				f = strstr(line, "POLL IDLE");
375*9c5db199SXin Li 				if (f) {
376*9c5db199SXin Li 					clevel = 0;
377*9c5db199SXin Li 					sprintf(cnames[clevel], "%s\t", _("polling"));
378*9c5db199SXin Li 				}
379*9c5db199SXin Li 
380*9c5db199SXin Li 				f = strstr(line, "ACPI HLT");
381*9c5db199SXin Li 				if (f) {
382*9c5db199SXin Li 					clevel = 1;
383*9c5db199SXin Li 					sprintf(cnames[clevel], "%s\t", "C1 halt");
384*9c5db199SXin Li 				}
385*9c5db199SXin Li 			}
386*9c5db199SXin Li 			sprintf(filename + len, "/%s/usage", entry->d_name);
387*9c5db199SXin Li 			file = fopen(filename, "r");
388*9c5db199SXin Li 			if (!file)
389*9c5db199SXin Li 				continue;
390*9c5db199SXin Li 
391*9c5db199SXin Li 			memset(line, 0, 4096);
392*9c5db199SXin Li 			f = fgets(line, 4096, file);
393*9c5db199SXin Li 			fclose(file);
394*9c5db199SXin Li 			if (f == NULL)
395*9c5db199SXin Li 				break;
396*9c5db199SXin Li 
397*9c5db199SXin Li 			usage[clevel] += 1+strtoull(line, NULL, 10);
398*9c5db199SXin Li 
399*9c5db199SXin Li 			sprintf(filename + len, "/%s/time", entry->d_name);
400*9c5db199SXin Li 			file = fopen(filename, "r");
401*9c5db199SXin Li 			if (!file)
402*9c5db199SXin Li 				continue;
403*9c5db199SXin Li 
404*9c5db199SXin Li 			memset(line, 0, 4096);
405*9c5db199SXin Li 			f = fgets(line, 4096, file);
406*9c5db199SXin Li 			fclose(file);
407*9c5db199SXin Li 			if (f == NULL)
408*9c5db199SXin Li 				break;
409*9c5db199SXin Li 
410*9c5db199SXin Li 			duration[clevel] += 1+strtoull(line, NULL, 10);
411*9c5db199SXin Li 
412*9c5db199SXin Li 			clevel++;
413*9c5db199SXin Li 			if (clevel > maxcstate)
414*9c5db199SXin Li 				maxcstate = clevel;
415*9c5db199SXin Li 
416*9c5db199SXin Li 		}
417*9c5db199SXin Li 		closedir(dir);
418*9c5db199SXin Li 
419*9c5db199SXin Li 	}
420*9c5db199SXin Li 	closedir(cpudir);
421*9c5db199SXin Li }
422*9c5db199SXin Li 
read_data(uint64_t * usage,uint64_t * duration)423*9c5db199SXin Li static void read_data(uint64_t * usage, uint64_t * duration)
424*9c5db199SXin Li {
425*9c5db199SXin Li 	int r;
426*9c5db199SXin Li 	struct stat s;
427*9c5db199SXin Li 
428*9c5db199SXin Li 	/* Then check for CPUidle */
429*9c5db199SXin Li 	r = stat("/sys/devices/system/cpu/cpu0/cpuidle", &s);
430*9c5db199SXin Li 	if (!r) {
431*9c5db199SXin Li 		read_data_cpuidle(usage, duration);
432*9c5db199SXin Li 
433*9c5db199SXin Li 		/* perform residency calculations based on usecs */
434*9c5db199SXin Li 		FREQ = 1000;
435*9c5db199SXin Li 		return;
436*9c5db199SXin Li 	}
437*9c5db199SXin Li 
438*9c5db199SXin Li 	/* First, check for ACPI */
439*9c5db199SXin Li 	r = stat("/proc/acpi/processor", &s);
440*9c5db199SXin Li 	if (!r) {
441*9c5db199SXin Li 		read_data_acpi(usage, duration);
442*9c5db199SXin Li 
443*9c5db199SXin Li 		/* perform residency calculations based on ACPI timer */
444*9c5db199SXin Li 		FREQ = FREQ_ACPI;
445*9c5db199SXin Li 		return;
446*9c5db199SXin Li 	}
447*9c5db199SXin Li }
448*9c5db199SXin Li 
stop_timerstats(void)449*9c5db199SXin Li void stop_timerstats(void)
450*9c5db199SXin Li {
451*9c5db199SXin Li 	FILE *file;
452*9c5db199SXin Li 	file = fopen("/proc/timer_stats", "w");
453*9c5db199SXin Li 	if (!file) {
454*9c5db199SXin Li 		nostats = 1;
455*9c5db199SXin Li 		return;
456*9c5db199SXin Li 	}
457*9c5db199SXin Li 	fprintf(file, "0\n");
458*9c5db199SXin Li 	fclose(file);
459*9c5db199SXin Li }
start_timerstats(void)460*9c5db199SXin Li void start_timerstats(void)
461*9c5db199SXin Li {
462*9c5db199SXin Li 	FILE *file;
463*9c5db199SXin Li 	file = fopen("/proc/timer_stats", "w");
464*9c5db199SXin Li 	if (!file) {
465*9c5db199SXin Li 		nostats = 1;
466*9c5db199SXin Li 		return;
467*9c5db199SXin Li 	}
468*9c5db199SXin Li 	fprintf(file, "1\n");
469*9c5db199SXin Li 	fclose(file);
470*9c5db199SXin Li }
471*9c5db199SXin Li 
line_compare(const void * av,const void * bv)472*9c5db199SXin Li int line_compare (const void *av, const void *bv)
473*9c5db199SXin Li {
474*9c5db199SXin Li 	const struct line	*a = av, *b = bv;
475*9c5db199SXin Li 	return b->count - a->count;
476*9c5db199SXin Li }
477*9c5db199SXin Li 
sort_lines(void)478*9c5db199SXin Li void sort_lines(void)
479*9c5db199SXin Li {
480*9c5db199SXin Li 	qsort (lines, linehead, sizeof (struct line), line_compare);
481*9c5db199SXin Li }
482*9c5db199SXin Li 
483*9c5db199SXin Li 
484*9c5db199SXin Li 
print_battery_proc_acpi(void)485*9c5db199SXin Li int print_battery_proc_acpi(void)
486*9c5db199SXin Li {
487*9c5db199SXin Li 	DIR *dir;
488*9c5db199SXin Li 	struct dirent *dirent;
489*9c5db199SXin Li 	FILE *file;
490*9c5db199SXin Li 	double rate = 0;
491*9c5db199SXin Li 	double cap = 0;
492*9c5db199SXin Li 
493*9c5db199SXin Li 	char filename[256];
494*9c5db199SXin Li 
495*9c5db199SXin Li 	dir = opendir("/proc/acpi/battery");
496*9c5db199SXin Li 	if (!dir)
497*9c5db199SXin Li 		return 0;
498*9c5db199SXin Li 
499*9c5db199SXin Li 	while ((dirent = readdir(dir))) {
500*9c5db199SXin Li 		int dontcount = 0;
501*9c5db199SXin Li 		double voltage = 0.0;
502*9c5db199SXin Li 		double amperes_drawn = 0.0;
503*9c5db199SXin Li 		double watts_drawn = 0.0;
504*9c5db199SXin Li 		double amperes_left = 0.0;
505*9c5db199SXin Li 		double watts_left = 0.0;
506*9c5db199SXin Li 		char line[1024];
507*9c5db199SXin Li 
508*9c5db199SXin Li 		if (strlen(dirent->d_name) < 3)
509*9c5db199SXin Li 			continue;
510*9c5db199SXin Li 
511*9c5db199SXin Li 		sprintf(filename, "/proc/acpi/battery/%s/state", dirent->d_name);
512*9c5db199SXin Li 		file = fopen(filename, "r");
513*9c5db199SXin Li 		if (!file)
514*9c5db199SXin Li 			continue;
515*9c5db199SXin Li 		memset(line, 0, 1024);
516*9c5db199SXin Li 		while (fgets(line, 1024, file) != NULL) {
517*9c5db199SXin Li 			char *c;
518*9c5db199SXin Li 			if (strstr(line, "present:") && strstr(line, "no"))
519*9c5db199SXin Li 				break;
520*9c5db199SXin Li 
521*9c5db199SXin Li 			if (strstr(line, "charging state:")
522*9c5db199SXin Li 			    && !strstr(line, "discharging"))
523*9c5db199SXin Li 				dontcount = 1;
524*9c5db199SXin Li 			c = strchr(line, ':');
525*9c5db199SXin Li 			if (!c)
526*9c5db199SXin Li 				continue;
527*9c5db199SXin Li 			c++;
528*9c5db199SXin Li 
529*9c5db199SXin Li 			if (strstr(line, "present voltage"))
530*9c5db199SXin Li 				voltage = strtoull(c, NULL, 10) / 1000.0;
531*9c5db199SXin Li 
532*9c5db199SXin Li 			if (strstr(line, "remaining capacity") && strstr(c, "mW"))
533*9c5db199SXin Li 				watts_left = strtoull(c, NULL, 10) / 1000.0;
534*9c5db199SXin Li 
535*9c5db199SXin Li 			if (strstr(line, "remaining capacity") && strstr(c, "mAh"))
536*9c5db199SXin Li 				amperes_left = strtoull(c, NULL, 10) / 1000.0;
537*9c5db199SXin Li 
538*9c5db199SXin Li 			if (strstr(line, "present rate") && strstr(c, "mW"))
539*9c5db199SXin Li 				watts_drawn = strtoull(c, NULL, 10) / 1000.0 ;
540*9c5db199SXin Li 
541*9c5db199SXin Li 			if (strstr(line, "present rate") && strstr(c, "mA"))
542*9c5db199SXin Li 				amperes_drawn = strtoull(c, NULL, 10) / 1000.0;
543*9c5db199SXin Li 
544*9c5db199SXin Li 		}
545*9c5db199SXin Li 		fclose(file);
546*9c5db199SXin Li 
547*9c5db199SXin Li 		if (!dontcount) {
548*9c5db199SXin Li 			rate += watts_drawn + voltage * amperes_drawn;
549*9c5db199SXin Li 		}
550*9c5db199SXin Li 		cap += watts_left + voltage * amperes_left;
551*9c5db199SXin Li 
552*9c5db199SXin Li 
553*9c5db199SXin Li 	}
554*9c5db199SXin Li 	closedir(dir);
555*9c5db199SXin Li 	if (prev_bat_cap - cap < 0.001 && rate < 0.001)
556*9c5db199SXin Li 		last_bat_time = 0;
557*9c5db199SXin Li 	if (!last_bat_time) {
558*9c5db199SXin Li 		last_bat_time = prev_bat_time = time(NULL);
559*9c5db199SXin Li 		last_bat_cap = prev_bat_cap = cap;
560*9c5db199SXin Li 	}
561*9c5db199SXin Li 	if (time(NULL) - last_bat_time >= 400) {
562*9c5db199SXin Li 		prev_bat_cap = last_bat_cap;
563*9c5db199SXin Li 		prev_bat_time = last_bat_time;
564*9c5db199SXin Li 		last_bat_time = time(NULL);
565*9c5db199SXin Li 		last_bat_cap = cap;
566*9c5db199SXin Li 	}
567*9c5db199SXin Li 
568*9c5db199SXin Li 	show_acpi_power_line(rate, cap, prev_bat_cap - cap, time(NULL) - prev_bat_time);
569*9c5db199SXin Li 	return 1;
570*9c5db199SXin Li }
571*9c5db199SXin Li 
print_battery_proc_pmu(void)572*9c5db199SXin Li int print_battery_proc_pmu(void)
573*9c5db199SXin Li {
574*9c5db199SXin Li 	char line[80];
575*9c5db199SXin Li 	int i;
576*9c5db199SXin Li 	int power_present = 0;
577*9c5db199SXin Li 	int num_batteries = 0;
578*9c5db199SXin Li 	/* unsigned rem_time_sec = 0; */
579*9c5db199SXin Li 	unsigned charge_mAh = 0, max_charge_mAh = 0, voltage_mV = 0;
580*9c5db199SXin Li 	int discharge_mA = 0;
581*9c5db199SXin Li 	FILE *fd;
582*9c5db199SXin Li 
583*9c5db199SXin Li 	fd = fopen("/proc/pmu/info", "r");
584*9c5db199SXin Li 	if (fd == NULL)
585*9c5db199SXin Li 		return 0;
586*9c5db199SXin Li 
587*9c5db199SXin Li 	while ( fgets(line, sizeof(line), fd) != NULL )
588*9c5db199SXin Li 	{
589*9c5db199SXin Li 		if (strncmp("AC Power", line, strlen("AC Power")) == 0)
590*9c5db199SXin Li 			sscanf(strchr(line, ':')+2, "%d", &power_present);
591*9c5db199SXin Li 		else if (strncmp("Battery count", line, strlen("Battery count")) == 0)
592*9c5db199SXin Li 			sscanf(strchr(line, ':')+2, "%d", &num_batteries);
593*9c5db199SXin Li 	}
594*9c5db199SXin Li 	fclose(fd);
595*9c5db199SXin Li 
596*9c5db199SXin Li 	for (i = 0; i < num_batteries; ++i)
597*9c5db199SXin Li 	{
598*9c5db199SXin Li 		char file_name[20];
599*9c5db199SXin Li 		int flags = 0;
600*9c5db199SXin Li 		/* int battery_charging, battery_full; */
601*9c5db199SXin Li 		/* unsigned this_rem_time_sec = 0; */
602*9c5db199SXin Li 		unsigned this_charge_mAh = 0, this_max_charge_mAh = 0;
603*9c5db199SXin Li 		unsigned this_voltage_mV = 0, this_discharge_mA = 0;
604*9c5db199SXin Li 
605*9c5db199SXin Li 		snprintf(file_name, sizeof(file_name), "/proc/pmu/battery_%d", i);
606*9c5db199SXin Li 		fd = fopen(file_name, "r");
607*9c5db199SXin Li 		if (fd == NULL)
608*9c5db199SXin Li 			continue;
609*9c5db199SXin Li 
610*9c5db199SXin Li 		while (fgets(line, sizeof(line), fd) != NULL)
611*9c5db199SXin Li 		{
612*9c5db199SXin Li 			if (strncmp("flags", line, strlen("flags")) == 0)
613*9c5db199SXin Li 				sscanf(strchr(line, ':')+2, "%x", &flags);
614*9c5db199SXin Li 			else if (strncmp("charge", line, strlen("charge")) == 0)
615*9c5db199SXin Li 				sscanf(strchr(line, ':')+2, "%d", &this_charge_mAh);
616*9c5db199SXin Li 			else if (strncmp("max_charge", line, strlen("max_charge")) == 0)
617*9c5db199SXin Li 				sscanf(strchr(line, ':')+2, "%d", &this_max_charge_mAh);
618*9c5db199SXin Li 			else if (strncmp("voltage", line, strlen("voltage")) == 0)
619*9c5db199SXin Li 				sscanf(strchr(line, ':')+2, "%d", &this_voltage_mV);
620*9c5db199SXin Li 			else if (strncmp("current", line, strlen("current")) == 0)
621*9c5db199SXin Li 				sscanf(strchr(line, ':')+2, "%d", &this_discharge_mA);
622*9c5db199SXin Li 			/* else if (strncmp("time rem.", line, strlen("time rem.")) == 0) */
623*9c5db199SXin Li 			/*   sscanf(strchr(line, ':')+2, "%d", &this_rem_time_sec); */
624*9c5db199SXin Li 		}
625*9c5db199SXin Li 		fclose(fd);
626*9c5db199SXin Li 
627*9c5db199SXin Li 		if ( !(flags & 0x1) )
628*9c5db199SXin Li 			/* battery isn't present */
629*9c5db199SXin Li 			continue;
630*9c5db199SXin Li 
631*9c5db199SXin Li 		/* battery_charging = flags & 0x2; */
632*9c5db199SXin Li 		/* battery_full = !battery_charging && power_present; */
633*9c5db199SXin Li 
634*9c5db199SXin Li 		charge_mAh += this_charge_mAh;
635*9c5db199SXin Li 		max_charge_mAh += this_max_charge_mAh;
636*9c5db199SXin Li 		voltage_mV += this_voltage_mV;
637*9c5db199SXin Li 		discharge_mA += this_discharge_mA;
638*9c5db199SXin Li 		/* rem_time_sec += this_rem_time_sec; */
639*9c5db199SXin Li 	}
640*9c5db199SXin Li 	show_pmu_power_line(voltage_mV, charge_mAh, max_charge_mAh,
641*9c5db199SXin Li 	                    discharge_mA);
642*9c5db199SXin Li 	return 1;
643*9c5db199SXin Li }
644*9c5db199SXin Li 
print_battery_sysfs(void)645*9c5db199SXin Li void print_battery_sysfs(void)
646*9c5db199SXin Li {
647*9c5db199SXin Li 	DIR *dir;
648*9c5db199SXin Li 	struct dirent *dirent;
649*9c5db199SXin Li 	FILE *file;
650*9c5db199SXin Li 	double rate = 0;
651*9c5db199SXin Li 	double cap = 0;
652*9c5db199SXin Li 
653*9c5db199SXin Li 	char filename[256];
654*9c5db199SXin Li 
655*9c5db199SXin Li 	if (print_battery_proc_acpi())
656*9c5db199SXin Li 		return;
657*9c5db199SXin Li 
658*9c5db199SXin Li 	if (print_battery_proc_pmu())
659*9c5db199SXin Li 		return;
660*9c5db199SXin Li 
661*9c5db199SXin Li 	dir = opendir("/sys/class/power_supply");
662*9c5db199SXin Li 	if (!dir) {
663*9c5db199SXin Li 		return;
664*9c5db199SXin Li 	}
665*9c5db199SXin Li 
666*9c5db199SXin Li 	while ((dirent = readdir(dir))) {
667*9c5db199SXin Li 		int dontcount = 0;
668*9c5db199SXin Li 		double voltage = 0.0;
669*9c5db199SXin Li 		double amperes_drawn = 0.0;
670*9c5db199SXin Li 		double watts_drawn = 0.0;
671*9c5db199SXin Li 		double watts_left = 0.0;
672*9c5db199SXin Li 		char line[1024];
673*9c5db199SXin Li 
674*9c5db199SXin Li 		if (strstr(dirent->d_name, "AC"))
675*9c5db199SXin Li 			continue;
676*9c5db199SXin Li 
677*9c5db199SXin Li 		sprintf(filename, "/sys/class/power_supply/%s/present", dirent->d_name);
678*9c5db199SXin Li 		file = fopen(filename, "r");
679*9c5db199SXin Li 		if (!file)
680*9c5db199SXin Li 			continue;
681*9c5db199SXin Li 		int s;
682*9c5db199SXin Li 		if ((s = getc(file)) != EOF) {
683*9c5db199SXin Li 			if (s == 0)
684*9c5db199SXin Li 				break;
685*9c5db199SXin Li 		}
686*9c5db199SXin Li 		fclose(file);
687*9c5db199SXin Li 
688*9c5db199SXin Li 		sprintf(filename, "/sys/class/power_supply/%s/status", dirent->d_name);
689*9c5db199SXin Li 		file = fopen(filename, "r");
690*9c5db199SXin Li 		if (!file)
691*9c5db199SXin Li 			continue;
692*9c5db199SXin Li 		memset(line, 0, 1024);
693*9c5db199SXin Li 		if (fgets(line, 1024, file) != NULL) {
694*9c5db199SXin Li 			if (!strstr(line, "Discharging"))
695*9c5db199SXin Li 				dontcount = 1;
696*9c5db199SXin Li 		}
697*9c5db199SXin Li 		fclose(file);
698*9c5db199SXin Li 
699*9c5db199SXin Li 		sprintf(filename, "/sys/class/power_supply/%s/voltage_now", dirent->d_name);
700*9c5db199SXin Li 		file = fopen(filename, "r");
701*9c5db199SXin Li 		if (!file)
702*9c5db199SXin Li 			continue;
703*9c5db199SXin Li 		memset(line, 0, 1024);
704*9c5db199SXin Li 		if (fgets(line, 1024, file) != NULL) {
705*9c5db199SXin Li 			voltage = strtoull(line, NULL, 10) / 1000000.0;
706*9c5db199SXin Li 		}
707*9c5db199SXin Li 		fclose(file);
708*9c5db199SXin Li 
709*9c5db199SXin Li 		sprintf(filename, "/sys/class/power_supply/%s/energy_now", dirent->d_name);
710*9c5db199SXin Li 		file = fopen(filename, "r");
711*9c5db199SXin Li 		watts_left = 1;
712*9c5db199SXin Li 		if (!file) {
713*9c5db199SXin Li 			sprintf(filename, "/sys/class/power_supply/%s/charge_now", dirent->d_name);
714*9c5db199SXin Li 			file = fopen(filename, "r");
715*9c5db199SXin Li 			if (!file)
716*9c5db199SXin Li 				continue;
717*9c5db199SXin Li 
718*9c5db199SXin Li 			/* W = A * V */
719*9c5db199SXin Li 			watts_left = voltage;
720*9c5db199SXin Li 		}
721*9c5db199SXin Li 		memset(line, 0, 1024);
722*9c5db199SXin Li 		if (fgets(line, 1024, file) != NULL)
723*9c5db199SXin Li 			watts_left *= strtoull(line, NULL, 10) / 1000000.0;
724*9c5db199SXin Li 		fclose(file);
725*9c5db199SXin Li 
726*9c5db199SXin Li 		sprintf(filename, "/sys/class/power_supply/%s/current_now", dirent->d_name);
727*9c5db199SXin Li 		file = fopen(filename, "r");
728*9c5db199SXin Li 		if (!file)
729*9c5db199SXin Li 			continue;
730*9c5db199SXin Li 		memset(line, 0, 1024);
731*9c5db199SXin Li 		if (fgets(line, 1024, file) != NULL) {
732*9c5db199SXin Li 			amperes_drawn = strtoull(line, NULL, 10) / 1000000.0;
733*9c5db199SXin Li 		}
734*9c5db199SXin Li 		fclose(file);
735*9c5db199SXin Li 
736*9c5db199SXin Li 		if (!dontcount) {
737*9c5db199SXin Li 			rate += watts_drawn + voltage * amperes_drawn;
738*9c5db199SXin Li 		}
739*9c5db199SXin Li 		cap += watts_left;
740*9c5db199SXin Li 
741*9c5db199SXin Li 
742*9c5db199SXin Li 	}
743*9c5db199SXin Li 	closedir(dir);
744*9c5db199SXin Li 	if (prev_bat_cap - cap < 0.001 && rate < 0.001)
745*9c5db199SXin Li 		last_bat_time = 0;
746*9c5db199SXin Li 	if (!last_bat_time) {
747*9c5db199SXin Li 		last_bat_time = prev_bat_time = time(NULL);
748*9c5db199SXin Li 		last_bat_cap = prev_bat_cap = cap;
749*9c5db199SXin Li 	}
750*9c5db199SXin Li 	if (time(NULL) - last_bat_time >= 400) {
751*9c5db199SXin Li 		prev_bat_cap = last_bat_cap;
752*9c5db199SXin Li 		prev_bat_time = last_bat_time;
753*9c5db199SXin Li 		last_bat_time = time(NULL);
754*9c5db199SXin Li 		last_bat_cap = cap;
755*9c5db199SXin Li 	}
756*9c5db199SXin Li 
757*9c5db199SXin Li 	show_acpi_power_line(rate, cap, prev_bat_cap - cap, time(NULL) - prev_bat_time);
758*9c5db199SXin Li }
759*9c5db199SXin Li 
760*9c5db199SXin Li char cstate_lines[12][200];
761*9c5db199SXin Li 
usage()762*9c5db199SXin Li void usage()
763*9c5db199SXin Li {
764*9c5db199SXin Li 	printf(_("Usage: powertop [OPTION...]\n"));
765*9c5db199SXin Li 	printf(_("  -d, --dump            read wakeups once and print list of top offenders\n"));
766*9c5db199SXin Li 	printf(_("  -t, --time=DOUBLE     default time to gather data in seconds\n"));
767*9c5db199SXin Li 	printf(_("  -h, --help            Show this help message\n"));
768*9c5db199SXin Li 	printf(_("  -v, --version         Show version information and exit\n"));
769*9c5db199SXin Li 	exit(0);
770*9c5db199SXin Li }
771*9c5db199SXin Li 
version()772*9c5db199SXin Li void version()
773*9c5db199SXin Li {
774*9c5db199SXin Li 	printf(_("powertop version %s\n"), VERSION);
775*9c5db199SXin Li 	exit(0);
776*9c5db199SXin Li }
777*9c5db199SXin Li 
main(int argc,char ** argv)778*9c5db199SXin Li int main(int argc, char **argv)
779*9c5db199SXin Li {
780*9c5db199SXin Li 	char line[1024];
781*9c5db199SXin Li 	int ncursesinited=0;
782*9c5db199SXin Li 	FILE *file = NULL;
783*9c5db199SXin Li 	uint64_t cur_usage[8], cur_duration[8];
784*9c5db199SXin Li 	double wakeups_per_second = 0;
785*9c5db199SXin Li 
786*9c5db199SXin Li 	setlocale (LC_ALL, "");
787*9c5db199SXin Li 	bindtextdomain ("powertop", "/usr/share/locale");
788*9c5db199SXin Li 	textdomain ("powertop");
789*9c5db199SXin Li 
790*9c5db199SXin Li  	while (1) {
791*9c5db199SXin Li  		static struct option opts[] = {
792*9c5db199SXin Li  			{ "dump", 0, NULL, 'd' },
793*9c5db199SXin Li  			{ "time", 1, NULL, 't' },
794*9c5db199SXin Li  			{ "help", 0, NULL, 'h' },
795*9c5db199SXin Li  			{ "version", 0, NULL, 'v' },
796*9c5db199SXin Li  			{ 0, 0, NULL, 0 }
797*9c5db199SXin Li  		};
798*9c5db199SXin Li  		int index2 = 0, c;
799*9c5db199SXin Li 
800*9c5db199SXin Li  		c = getopt_long(argc, argv, "dt:hv", opts, &index2);
801*9c5db199SXin Li  		if (c == -1)
802*9c5db199SXin Li  			break;
803*9c5db199SXin Li  		switch (c) {
804*9c5db199SXin Li  		case 'd':
805*9c5db199SXin Li  			dump = 1;
806*9c5db199SXin Li  			break;
807*9c5db199SXin Li  		case 't':
808*9c5db199SXin Li  			ticktime = strtod(optarg, NULL);
809*9c5db199SXin Li  			break;
810*9c5db199SXin Li  		case 'h':
811*9c5db199SXin Li  			usage();
812*9c5db199SXin Li  			break;
813*9c5db199SXin Li  		case 'v':
814*9c5db199SXin Li  			version();
815*9c5db199SXin Li  			break;
816*9c5db199SXin Li  		default:
817*9c5db199SXin Li  			;
818*9c5db199SXin Li  		}
819*9c5db199SXin Li  	}
820*9c5db199SXin Li 
821*9c5db199SXin Li 	if (!dump)
822*9c5db199SXin Li 		ticktime = 5.0;
823*9c5db199SXin Li 
824*9c5db199SXin Li 	system("/sbin/modprobe cpufreq_stats &> /dev/null");
825*9c5db199SXin Li 	read_data(&start_usage[0], &start_duration[0]);
826*9c5db199SXin Li 
827*9c5db199SXin Li 
828*9c5db199SXin Li 	memcpy(last_usage, start_usage, sizeof(last_usage));
829*9c5db199SXin Li 	memcpy(last_duration, start_duration, sizeof(last_duration));
830*9c5db199SXin Li 
831*9c5db199SXin Li 	do_proc_irq();
832*9c5db199SXin Li 	do_proc_irq();
833*9c5db199SXin Li 	do_cpufreq_stats();
834*9c5db199SXin Li 	count_usb_urbs();
835*9c5db199SXin Li 	count_usb_urbs();
836*9c5db199SXin Li 
837*9c5db199SXin Li 	memset(cur_usage, 0, sizeof(cur_usage));
838*9c5db199SXin Li 	memset(cur_duration, 0, sizeof(cur_duration));
839*9c5db199SXin Li 	printf("PowerTOP " VERSION "   (C) 2007, 2008 Intel Corporation \n\n");
840*9c5db199SXin Li 	if (geteuid() != 0)
841*9c5db199SXin Li 		printf(_("PowerTOP needs to be run as root to collect enough information\n"));
842*9c5db199SXin Li 	printf(_("Collecting data for %i seconds \n"), (int)ticktime);
843*9c5db199SXin Li 	printf("\n\n");
844*9c5db199SXin Li 	print_intel_cstates();
845*9c5db199SXin Li 	stop_timerstats();
846*9c5db199SXin Li 
847*9c5db199SXin Li 	while (1) {
848*9c5db199SXin Li 		double maxsleep = 0.0;
849*9c5db199SXin Li 		int64_t totalticks;
850*9c5db199SXin Li 		int64_t totalevents;
851*9c5db199SXin Li 		fd_set rfds;
852*9c5db199SXin Li 		struct timeval tv;
853*9c5db199SXin Li 		int key;
854*9c5db199SXin Li 
855*9c5db199SXin Li 		int i = 0;
856*9c5db199SXin Li 		double c0 = 0;
857*9c5db199SXin Li 		char *c;
858*9c5db199SXin Li 
859*9c5db199SXin Li 
860*9c5db199SXin Li 		FD_ZERO(&rfds);
861*9c5db199SXin Li 		FD_SET(0, &rfds);
862*9c5db199SXin Li 		tv.tv_sec = ticktime;
863*9c5db199SXin Li 		tv.tv_usec = (ticktime - tv.tv_sec) * 1000000;;
864*9c5db199SXin Li 		do_proc_irq();
865*9c5db199SXin Li 		start_timerstats();
866*9c5db199SXin Li 
867*9c5db199SXin Li 
868*9c5db199SXin Li 		key = select(1, &rfds, NULL, NULL, &tv);
869*9c5db199SXin Li 
870*9c5db199SXin Li 		if (key && tv.tv_sec) ticktime = ticktime - tv.tv_sec - tv.tv_usec/1000000.0;
871*9c5db199SXin Li 
872*9c5db199SXin Li 
873*9c5db199SXin Li 		stop_timerstats();
874*9c5db199SXin Li 		clear_lines();
875*9c5db199SXin Li 		do_proc_irq();
876*9c5db199SXin Li 		read_data(&cur_usage[0], &cur_duration[0]);
877*9c5db199SXin Li 
878*9c5db199SXin Li 		totalticks = 0;
879*9c5db199SXin Li 		totalevents = 0;
880*9c5db199SXin Li 		for (i = 0; i < 8; i++)
881*9c5db199SXin Li 			if (cur_usage[i]) {
882*9c5db199SXin Li 				totalticks += cur_duration[i] - last_duration[i];
883*9c5db199SXin Li 				totalevents += cur_usage[i] - last_usage[i];
884*9c5db199SXin Li 			}
885*9c5db199SXin Li 
886*9c5db199SXin Li 		if (!dump) {
887*9c5db199SXin Li 			if (!ncursesinited) {
888*9c5db199SXin Li 				initialize_curses();
889*9c5db199SXin Li 				ncursesinited++;
890*9c5db199SXin Li 			}
891*9c5db199SXin Li 			setup_windows();
892*9c5db199SXin Li 			show_title_bar();
893*9c5db199SXin Li 		}
894*9c5db199SXin Li 
895*9c5db199SXin Li 		memset(&cstate_lines, 0, sizeof(cstate_lines));
896*9c5db199SXin Li 		topcstate = -4;
897*9c5db199SXin Li 		if (totalevents == 0 && maxcstate <= 1) {
898*9c5db199SXin Li 			sprintf(cstate_lines[5],_("< Detailed C-state information is not available.>\n"));
899*9c5db199SXin Li 		} else {
900*9c5db199SXin Li 			double sleept, percentage;;
901*9c5db199SXin Li 			c0 = sysconf(_SC_NPROCESSORS_ONLN) * ticktime * 1000 * FREQ - totalticks;
902*9c5db199SXin Li 			if (c0 < 0)
903*9c5db199SXin Li 				c0 = 0;	/* rounding errors in measurement might make c0 go slightly negative.. this is confusing */
904*9c5db199SXin Li 			sprintf(cstate_lines[0], _("Cn\t          Avg residency\n"));
905*9c5db199SXin Li 
906*9c5db199SXin Li 			percentage = c0 * 100.0 / (sysconf(_SC_NPROCESSORS_ONLN) * ticktime * 1000 * FREQ);
907*9c5db199SXin Li 			sprintf(cstate_lines[1], _("C0 (cpu running)        (%4.1f%%)\n"), percentage);
908*9c5db199SXin Li 			if (percentage > 50)
909*9c5db199SXin Li 				topcstate = 0;
910*9c5db199SXin Li 			for (i = 0; i < 8; i++)
911*9c5db199SXin Li 				if (cur_usage[i]) {
912*9c5db199SXin Li 					sleept = (cur_duration[i] - last_duration[i]) / (cur_usage[i] - last_usage[i]
913*9c5db199SXin Li 											+ 0.1) / FREQ;
914*9c5db199SXin Li 					percentage = (cur_duration[i] -
915*9c5db199SXin Li 					      last_duration[i]) * 100 /
916*9c5db199SXin Li 					     (sysconf(_SC_NPROCESSORS_ONLN) * ticktime * 1000 * FREQ);
917*9c5db199SXin Li 
918*9c5db199SXin Li 					if (cnames[i][0]==0)
919*9c5db199SXin Li 						sprintf(cnames[i],"C%i",i+1);
920*9c5db199SXin Li 					sprintf
921*9c5db199SXin Li 					    (cstate_lines[2+i], _("%s\t%5.1fms (%4.1f%%)\n"),
922*9c5db199SXin Li 					     cnames[i], sleept, percentage);
923*9c5db199SXin Li 					if (maxsleep < sleept)
924*9c5db199SXin Li 						maxsleep = sleept;
925*9c5db199SXin Li 					if (percentage > 50)
926*9c5db199SXin Li 						topcstate = i+1;
927*9c5db199SXin Li 
928*9c5db199SXin Li 				}
929*9c5db199SXin Li 		}
930*9c5db199SXin Li 		do_cpufreq_stats();
931*9c5db199SXin Li 		show_cstates();
932*9c5db199SXin Li 		/* now the timer_stats info */
933*9c5db199SXin Li 		memset(line, 0, sizeof(line));
934*9c5db199SXin Li 		totalticks = 0;
935*9c5db199SXin Li 		file = NULL;
936*9c5db199SXin Li 		if (!nostats)
937*9c5db199SXin Li 			file = fopen("/proc/timer_stats", "r");
938*9c5db199SXin Li 		while (file && !feof(file)) {
939*9c5db199SXin Li 			char *count, *pid, *process, *func;
940*9c5db199SXin Li 			char line2[1024];
941*9c5db199SXin Li 			int cnt;
942*9c5db199SXin Li 			int deferrable = 0;
943*9c5db199SXin Li 			memset(line, 0, 1024);
944*9c5db199SXin Li 			if (fgets(line, 1024, file) == NULL)
945*9c5db199SXin Li 				break;
946*9c5db199SXin Li 			if (strstr(line, "total events"))
947*9c5db199SXin Li 				break;
948*9c5db199SXin Li 			c = count = &line[0];
949*9c5db199SXin Li 			c = strchr(c, ',');
950*9c5db199SXin Li 			if (!c)
951*9c5db199SXin Li 				continue;
952*9c5db199SXin Li 			*c = 0;
953*9c5db199SXin Li 			c++;
954*9c5db199SXin Li 			while (*c != 0 && *c == ' ')
955*9c5db199SXin Li 				c++;
956*9c5db199SXin Li 			pid = c;
957*9c5db199SXin Li 			c = strchr(c, ' ');
958*9c5db199SXin Li 			if (!c)
959*9c5db199SXin Li 				continue;
960*9c5db199SXin Li 			*c = 0;
961*9c5db199SXin Li 			c++;
962*9c5db199SXin Li 			while (*c != 0 && *c == ' ')
963*9c5db199SXin Li 				c++;
964*9c5db199SXin Li 			process = c;
965*9c5db199SXin Li 			c = strchr(c, ' ');
966*9c5db199SXin Li 			if (!c)
967*9c5db199SXin Li 				continue;
968*9c5db199SXin Li 			*c = 0;
969*9c5db199SXin Li 			c++;
970*9c5db199SXin Li 			while (*c != 0 && *c == ' ')
971*9c5db199SXin Li 				c++;
972*9c5db199SXin Li 			func = c;
973*9c5db199SXin Li 			if (strcmp(process, "insmod") == 0)
974*9c5db199SXin Li 				process = _("<kernel module>");
975*9c5db199SXin Li 			if (strcmp(process, "modprobe") == 0)
976*9c5db199SXin Li 				process = _("<kernel module>");
977*9c5db199SXin Li 			if (strcmp(process, "swapper") == 0)
978*9c5db199SXin Li 				process = _("<kernel core>");
979*9c5db199SXin Li 			c = strchr(c, '\n');
980*9c5db199SXin Li 			if (strncmp(func, "tick_nohz_", 10) == 0)
981*9c5db199SXin Li 				continue;
982*9c5db199SXin Li 			if (strncmp(func, "tick_setup_sched_timer", 20) == 0)
983*9c5db199SXin Li 				continue;
984*9c5db199SXin Li 			if (strcmp(process, "powertop") == 0)
985*9c5db199SXin Li 				continue;
986*9c5db199SXin Li 			if (c)
987*9c5db199SXin Li 				*c = 0;
988*9c5db199SXin Li 			cnt = strtoull(count, &c, 10);
989*9c5db199SXin Li 			while (*c != 0) {
990*9c5db199SXin Li 				if (*c++ == 'D')
991*9c5db199SXin Li 					deferrable = 1;
992*9c5db199SXin Li 			}
993*9c5db199SXin Li 			if (deferrable)
994*9c5db199SXin Li 				continue;
995*9c5db199SXin Li 			sprintf(line2, "%15s : %s", process, func);
996*9c5db199SXin Li 			push_line_pid(line2, cnt, pid);
997*9c5db199SXin Li 		}
998*9c5db199SXin Li 		if (file)
999*9c5db199SXin Li 			pclose(file);
1000*9c5db199SXin Li 
1001*9c5db199SXin Li 		if (strstr(line, "total events")) {
1002*9c5db199SXin Li 			int d;
1003*9c5db199SXin Li 			d = strtoull(line, NULL, 10) / sysconf(_SC_NPROCESSORS_ONLN);
1004*9c5db199SXin Li 			if (totalevents == 0) { /* No c-state info available, use timerstats instead */
1005*9c5db199SXin Li 				totalevents = d * sysconf(_SC_NPROCESSORS_ONLN) + total_interrupt;
1006*9c5db199SXin Li 				if (d < interrupt_0)
1007*9c5db199SXin Li 					totalevents += interrupt_0 - d;
1008*9c5db199SXin Li 			}
1009*9c5db199SXin Li 			if (d>0 && d < interrupt_0)
1010*9c5db199SXin Li 				push_line(_("    <interrupt> : extra timer interrupt"), interrupt_0 - d);
1011*9c5db199SXin Li 		}
1012*9c5db199SXin Li 
1013*9c5db199SXin Li 
1014*9c5db199SXin Li 		if (totalevents && ticktime) {
1015*9c5db199SXin Li 			wakeups_per_second = totalevents * 1.0 / ticktime / sysconf(_SC_NPROCESSORS_ONLN);
1016*9c5db199SXin Li 			show_wakeups(wakeups_per_second, ticktime, c0 * 100.0 / (sysconf(_SC_NPROCESSORS_ONLN) * ticktime * 1000 * FREQ) );
1017*9c5db199SXin Li 		}
1018*9c5db199SXin Li 		count_usb_urbs();
1019*9c5db199SXin Li 		print_battery_sysfs();
1020*9c5db199SXin Li 		count_lines();
1021*9c5db199SXin Li 		sort_lines();
1022*9c5db199SXin Li 
1023*9c5db199SXin Li 		displaytime = displaytime - ticktime;
1024*9c5db199SXin Li 
1025*9c5db199SXin Li 		show_timerstats(nostats, ticktime);
1026*9c5db199SXin Li 
1027*9c5db199SXin Li 		if (maxsleep < 5.0)
1028*9c5db199SXin Li 			ticktime = 10;
1029*9c5db199SXin Li 		else if (maxsleep < 30.0)
1030*9c5db199SXin Li 			ticktime = 15;
1031*9c5db199SXin Li 		else if (maxsleep < 100.0)
1032*9c5db199SXin Li 			ticktime = 20;
1033*9c5db199SXin Li 		else if (maxsleep < 400.0)
1034*9c5db199SXin Li 			ticktime = 30;
1035*9c5db199SXin Li 		else
1036*9c5db199SXin Li 			ticktime = 45;
1037*9c5db199SXin Li 
1038*9c5db199SXin Li 		if (key) {
1039*9c5db199SXin Li 			char keychar;
1040*9c5db199SXin Li 			int keystroke = fgetc(stdin);
1041*9c5db199SXin Li 			if (keystroke == EOF)
1042*9c5db199SXin Li 				exit(EXIT_SUCCESS);
1043*9c5db199SXin Li 
1044*9c5db199SXin Li 			keychar = toupper(keystroke);
1045*9c5db199SXin Li 			if (keychar == 'Q')
1046*9c5db199SXin Li 				exit(EXIT_SUCCESS);
1047*9c5db199SXin Li 			if (keychar == 'R')
1048*9c5db199SXin Li 				ticktime = 3;
1049*9c5db199SXin Li 			if (keychar == suggestion_key && suggestion_activate) {
1050*9c5db199SXin Li 				suggestion_activate();
1051*9c5db199SXin Li 				ticktime = 2;
1052*9c5db199SXin Li 				displaytime = -1.0;
1053*9c5db199SXin Li 			} else
1054*9c5db199SXin Li 			if (keychar == 'P')
1055*9c5db199SXin Li 				showpids = !showpids;
1056*9c5db199SXin Li 		}
1057*9c5db199SXin Li 
1058*9c5db199SXin Li 		if (wakeups_per_second < 0)
1059*9c5db199SXin Li 			ticktime = 2;
1060*9c5db199SXin Li 
1061*9c5db199SXin Li 		reset_suggestions();
1062*9c5db199SXin Li 
1063*9c5db199SXin Li 		suggest_kernel_config("CONFIG_USB_SUSPEND", 1,
1064*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_USB_SUSPEND kernel configuration option.\nThis option will automatically disable UHCI USB when not in use, and may\nsave approximately 1 Watt of power."), 20);
1065*9c5db199SXin Li 		suggest_kernel_config("CONFIG_CPU_FREQ_GOV_ONDEMAND", 1,
1066*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_CPU_FREQ_GOV_ONDEMAND kernel configuration option.\n"
1067*9c5db199SXin Li 				      "The 'ondemand' CPU speed governor will minimize the CPU power usage while\n" "giving you performance when it is needed."), 5);
1068*9c5db199SXin Li 		suggest_kernel_config("CONFIG_NO_HZ", 1, _("Suggestion: Enable the CONFIG_NO_HZ kernel configuration option.\nThis option is required to get any kind of longer sleep times in the CPU."), 50);
1069*9c5db199SXin Li 		suggest_kernel_config("CONFIG_ACPI_BATTERY", 1, _("Suggestion: Enable the CONFIG_ACPI_BATTERY kernel configuration option.\n "
1070*9c5db199SXin Li 				      "This option is required to get power estimages from PowerTOP"), 5);
1071*9c5db199SXin Li 		suggest_kernel_config("CONFIG_HPET_TIMER", 1,
1072*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_HPET_TIMER kernel configuration option.\n"
1073*9c5db199SXin Li 				      "Without HPET support the kernel needs to wake up every 20 milliseconds for \n" "some housekeeping tasks."), 10);
1074*9c5db199SXin Li 		if (!access("/sys/module/snd_ac97_codec", F_OK) &&
1075*9c5db199SXin Li 			access("/sys/module/snd_ac97_codec/parameters/power_save", F_OK))
1076*9c5db199SXin Li 			suggest_kernel_config("CONFIG_SND_AC97_POWER_SAVE", 1,
1077*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_SND_AC97_POWER_SAVE kernel configuration option.\n"
1078*9c5db199SXin Li 				      "This option will automatically power down your sound codec when not in use,\n"
1079*9c5db199SXin Li 				      "and can save approximately half a Watt of power."), 20);
1080*9c5db199SXin Li 		suggest_kernel_config("CONFIG_IRQBALANCE", 0,
1081*9c5db199SXin Li 				      _("Suggestion: Disable the CONFIG_IRQBALANCE kernel configuration option.\n" "The in-kernel irq balancer is obsolete and wakes the CPU up far more than needed."), 3);
1082*9c5db199SXin Li 		suggest_kernel_config("CONFIG_CPU_FREQ_STAT", 1,
1083*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_CPU_FREQ_STAT kernel configuration option.\n"
1084*9c5db199SXin Li 				      "This option allows PowerTOP to show P-state percentages \n" "P-states correspond to CPU frequencies."), 2);
1085*9c5db199SXin Li 		suggest_kernel_config("CONFIG_INOTIFY", 1,
1086*9c5db199SXin Li 				    _("Suggestion: Enable the CONFIG_INOTIFY kernel configuration option.\n"
1087*9c5db199SXin Li 				      "This option allows programs to wait for changes in files and directories\n"
1088*9c5db199SXin Li 				      "instead of having to poll for these changes"), 5);
1089*9c5db199SXin Li 
1090*9c5db199SXin Li 
1091*9c5db199SXin Li 		/* suggest to stop beagle if it shows up in the top 20 and wakes up more than 10 times in the measurement */
1092*9c5db199SXin Li 		suggest_process_death("beagled : schedule_timeout", "beagled", lines, min(linehead,20), 10.0,
1093*9c5db199SXin Li 				    _("Suggestion: Disable or remove 'beagle' from your system. \n"
1094*9c5db199SXin Li 				      "Beagle is the program that indexes for easy desktop search, however it's \n"
1095*9c5db199SXin Li 				      "not very efficient and costs a significant amount of battery life."), 30);
1096*9c5db199SXin Li 		suggest_process_death("beagled : futex_wait (hrtimer_wakeup)", "beagled", lines, min(linehead,20), 10.0,
1097*9c5db199SXin Li 				    _("Suggestion: Disable or remove 'beagle' from your system. \n"
1098*9c5db199SXin Li 				      "Beagle is the program that indexes for easy desktop search, however it's \n"
1099*9c5db199SXin Li 				      "not very efficient and costs a significant amount of battery life."), 30);
1100*9c5db199SXin Li 
1101*9c5db199SXin Li 		/* suggest to stop gnome-power-manager *only* if it shows up in the top 10 and wakes up more than 10 times in the measurement */
1102*9c5db199SXin Li 		/* note to distribution makers: There is no need to patch this out! */
1103*9c5db199SXin Li 		/* If you ship a recent enough g-p-m, the warning will not be there, */
1104*9c5db199SXin Li 		/* and if you ship a really old one the warning is really justified. */
1105*9c5db199SXin Li 		suggest_process_death("gnome-power-man : schedule_timeout (process_timeout)", "gnome-power-manager", lines, min(linehead,10), 10.0,
1106*9c5db199SXin Li 				    _("Suggestion: Disable or remove 'gnome-power-manager' from your system. \n"
1107*9c5db199SXin Li 				      "Older versions of gnome-power-manager wake up far more often than \n"
1108*9c5db199SXin Li 				      "needed costing you some power."), 5);
1109*9c5db199SXin Li 
1110*9c5db199SXin Li 		/* suggest to stop pcscd if it shows up in the top 50 and wakes up at all*/
1111*9c5db199SXin Li 		suggest_process_death("pcscd : ", "pcscd", lines, min(linehead,50), 1.0,
1112*9c5db199SXin Li 				    _("Suggestion: Disable or remove 'pcscd' from your system. \n"
1113*9c5db199SXin Li 				      "pcscd tends to keep the USB subsystem out of power save mode\n"
1114*9c5db199SXin Li 				      "and your processor out of deeper powersave states."), 30);
1115*9c5db199SXin Li 
1116*9c5db199SXin Li 
1117*9c5db199SXin Li 		/* suggest to stop hal polilng if it shows up in the top 50 and wakes up too much*/
1118*9c5db199SXin Li 		suggest_process_death("hald-addon-stor : ", "hald-addon-storage", lines, min(linehead,50), 2.0,
1119*9c5db199SXin Li 				    _( "Suggestion: Disable 'hal' from polling your cdrom with:  \n"
1120*9c5db199SXin Li 				       "hal-disable-polling --device /dev/cdrom 'hal' is the component that auto-opens a\n"
1121*9c5db199SXin Li 				       "window if you plug in a CD but disables SATA power saving from kicking in."), 30);
1122*9c5db199SXin Li 
1123*9c5db199SXin Li 		/* suggest to kill sealert; it wakes up 10 times/second on a default F7 install*/
1124*9c5db199SXin Li 		suggest_process_death("/usr/bin/sealer : schedule_timeout (process_timeout)", "-/usr/bin/sealert", lines, min(linehead,20), 20.0,
1125*9c5db199SXin Li 				    _("Disable the SE-Alert software by removing the 'setroubleshoot-server' rpm\n"
1126*9c5db199SXin Li 				      "SE-Alert alerts you about SELinux policy violations, but also\n"
1127*9c5db199SXin Li 				      "has a bug that wakes it up 10 times per second."), 20);
1128*9c5db199SXin Li 
1129*9c5db199SXin Li 
1130*9c5db199SXin Li 		suggest_bluetooth_off();
1131*9c5db199SXin Li 		suggest_nmi_watchdog();
1132*9c5db199SXin Li 		suggest_laptop_mode();
1133*9c5db199SXin Li 		if (maxsleep > 15.0)
1134*9c5db199SXin Li 			suggest_hpet();
1135*9c5db199SXin Li 		suggest_ac97_powersave();
1136*9c5db199SXin Li 		suggest_wireless_powersave();
1137*9c5db199SXin Li 		suggest_ondemand_governor();
1138*9c5db199SXin Li 		suggest_noatime();
1139*9c5db199SXin Li 		suggest_sata_alpm();
1140*9c5db199SXin Li 		suggest_powersched();
1141*9c5db199SXin Li 		suggest_xrandr_TV_off();
1142*9c5db199SXin Li 		suggest_WOL_off();
1143*9c5db199SXin Li 		suggest_writeback_time();
1144*9c5db199SXin Li 		suggest_usb_autosuspend();
1145*9c5db199SXin Li 		usb_activity_hint();
1146*9c5db199SXin Li 
1147*9c5db199SXin Li 		if (dump) {
1148*9c5db199SXin Li 			print_all_suggestions();
1149*9c5db199SXin Li 			display_usb_activity();
1150*9c5db199SXin Li 			exit(EXIT_SUCCESS);
1151*9c5db199SXin Li 		}
1152*9c5db199SXin Li 
1153*9c5db199SXin Li 		if (!key)
1154*9c5db199SXin Li 			pick_suggestion();
1155*9c5db199SXin Li 		show_title_bar();
1156*9c5db199SXin Li 
1157*9c5db199SXin Li 		fflush(stdout);
1158*9c5db199SXin Li 		if (!key && ticktime >= 4.8) {	/* quiet down the effects of any IO to xterms */
1159*9c5db199SXin Li 			FD_ZERO(&rfds);
1160*9c5db199SXin Li 			FD_SET(0, &rfds);
1161*9c5db199SXin Li 			tv.tv_sec = 3;
1162*9c5db199SXin Li 			tv.tv_usec = 0;
1163*9c5db199SXin Li 			key = select(1, &rfds, NULL, NULL, &tv);
1164*9c5db199SXin Li 		}
1165*9c5db199SXin Li 
1166*9c5db199SXin Li 		read_data(&cur_usage[0], &cur_duration[0]);
1167*9c5db199SXin Li 		memcpy(last_usage, cur_usage, sizeof(last_usage));
1168*9c5db199SXin Li 		memcpy(last_duration, cur_duration, sizeof(last_duration));
1169*9c5db199SXin Li 
1170*9c5db199SXin Li 
1171*9c5db199SXin Li 
1172*9c5db199SXin Li 	}
1173*9c5db199SXin Li 
1174*9c5db199SXin Li 	return 0;
1175*9c5db199SXin Li }
1176