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