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