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
44uint64_t start_usage[8], start_duration[8];
45uint64_t last_usage[8], last_duration[8];
46char cnames[8][16];
47
48double ticktime = 15.0;
49
50int interrupt_0, total_interrupt;
51
52int showpids = 0;
53
54static int maxcstate = 0;
55int topcstate = 0;
56
57int dump = 0;
58
59#define IRQCOUNT 150
60
61struct irqdata {
62	int active;
63	int number;
64	uint64_t count;
65	char description[256];
66};
67
68struct irqdata interrupts[IRQCOUNT];
69
70#define FREQ_ACPI 3579.545
71static unsigned long FREQ;
72
73int nostats;
74
75
76struct line	*lines;
77int		linehead;
78int		linesize;
79int		linectotal;
80
81
82double last_bat_cap = 0;
83double prev_bat_cap = 0;
84time_t last_bat_time = 0;
85time_t prev_bat_time = 0;
86
87double displaytime = 0.0;
88
89void 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
107void 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
127void 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
137void 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
146int 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
174static 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
266static 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
316static 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
423static 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
449void 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}
460void 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
472int 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
478void sort_lines(void)
479{
480	qsort (lines, linehead, sizeof (struct line), line_compare);
481}
482
483
484
485int 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
572int 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
645void 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
760char cstate_lines[12][200];
761
762void 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
772void version()
773{
774	printf(_("powertop version %s\n"), VERSION);
775	exit(0);
776}
777
778int 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