aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-10-26 12:39:36 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-10-26 12:39:36 +0200
commitc3f1fa10d601eb5e1b92f55fb49bbd59cde71705 (patch)
treed9719971ab78299d8c54c6d09a52151a23969ce2
parent373789e5675ffaeaab183dc3093664c737f2bd36 (diff)
downloadbusybox-w32-c3f1fa10d601eb5e1b92f55fb49bbd59cde71705.tar.gz
busybox-w32-c3f1fa10d601eb5e1b92f55fb49bbd59cde71705.tar.bz2
busybox-w32-c3f1fa10d601eb5e1b92f55fb49bbd59cde71705.zip
powertop: fixes to output format and code shrink
function old new delta process_timer_stats - 631 +631 clear_lines 72 74 +2 process_irq_counts 729 726 -3 .rodata 145699 145530 -169 powertop_main 2341 1510 -831 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 1/2 up/down: 1359/-1729) Total: -370 bytes Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r--procps/powertop.c330
1 files changed, 169 insertions, 161 deletions
diff --git a/procps/powertop.c b/procps/powertop.c
index 4b410540e..5792048dc 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -19,7 +19,7 @@
19//config: help 19//config: help
20//config: Analyze power consumption on Intel-based laptops 20//config: Analyze power consumption on Intel-based laptops
21 21
22// XXX This should de configurable 22// XXX This should be configurable
23#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 23#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1
24 24
25#include "libbb.h" 25#include "libbb.h"
@@ -39,7 +39,7 @@
39 39
40/* Frequency of the ACPI timer */ 40/* Frequency of the ACPI timer */
41#define FREQ_ACPI 3579.545 41#define FREQ_ACPI 3579.545
42#define FREQ_ACPI_1000 3579545 42#define FREQ_ACPI_1000 3579545
43 43
44/* Max filename length of entry in /sys/devices subsystem */ 44/* Max filename length of entry in /sys/devices subsystem */
45#define BIG_SYSNAME_LEN 16 45#define BIG_SYSNAME_LEN 16
@@ -62,12 +62,11 @@ struct irqdata {
62#endif 62#endif
63 63
64struct globals { 64struct globals {
65 struct line *lines; /* the most often used member */
65 int lines_cnt; 66 int lines_cnt;
66 int lines_cumulative_count; 67 int lines_cumulative_count;
67 int linesize;
68 int maxcstate; 68 int maxcstate;
69 unsigned total_cpus; 69 unsigned total_cpus;
70 struct line *lines;
71 smallint cant_enable_timer_stats; 70 smallint cant_enable_timer_stats;
72#if ENABLE_FEATURE_POWERTOP_PROCIRQ 71#if ENABLE_FEATURE_POWERTOP_PROCIRQ
73# if BLOATY_HPET_IRQ_NUM_DETECTION 72# if BLOATY_HPET_IRQ_NUM_DETECTION
@@ -120,15 +119,16 @@ static int write_str_to_file(const char *fname, const char *str)
120#define start_timer() write_str_to_file("/proc/timer_stats", "1\n") 119#define start_timer() write_str_to_file("/proc/timer_stats", "1\n")
121#define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") 120#define stop_timer() write_str_to_file("/proc/timer_stats", "0\n")
122 121
123static void NOINLINE clear_lines(void) 122static NOINLINE void clear_lines(void)
124{ 123{
125 int i; 124 int i;
126 for (i = 0; i < G.lines_cnt; i++) 125 if (G.lines) {
127 free(G.lines[i].string); 126 for (i = 0; i < G.lines_cnt; i++)
128 free(G.lines); 127 free(G.lines[i].string);
129 G.lines_cnt = 0; 128 free(G.lines);
130 G.linesize = 0; 129 G.lines_cnt = 0;
131 G.lines = NULL; 130 G.lines = NULL;
131 }
132} 132}
133 133
134static void update_lines_cumulative_count(void) 134static void update_lines_cumulative_count(void)
@@ -220,7 +220,7 @@ static void save_line(const char *string, int count)
220 } 220 }
221 221
222 /* Add new line */ 222 /* Add new line */
223 G.lines = xrealloc_vector(G.lines, 1, G.lines_cnt); 223 G.lines = xrealloc_vector(G.lines, 4, G.lines_cnt);
224 G.lines[G.lines_cnt].string = xstrdup(string); 224 G.lines[G.lines_cnt].string = xstrdup(string);
225 G.lines[G.lines_cnt].count = count; 225 G.lines[G.lines_cnt].count = count;
226 /*G.lines[G.lines_cnt].disk_count = 0;*/ 226 /*G.lines[G.lines_cnt].disk_count = 0;*/
@@ -298,7 +298,7 @@ static int save_irq_count(int irq, ullong count)
298} 298}
299 299
300/* Read /proc/interrupts, save IRQ counts and IRQ description */ 300/* Read /proc/interrupts, save IRQ counts and IRQ description */
301static void process_irq_count_deltas(void) 301static void process_irq_counts(void)
302{ 302{
303 FILE *fp; 303 FILE *fp;
304 char buf[128]; 304 char buf[128];
@@ -399,9 +399,121 @@ static void process_irq_count_deltas(void)
399 fclose(fp); 399 fclose(fp);
400} 400}
401#else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */ 401#else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */
402# define process_irq_count_deltas() ((void)0) 402# define process_irq_counts() ((void)0)
403#endif 403#endif
404 404
405static NOINLINE int process_timer_stats(void)
406{
407 char buf[128];
408 char line[15 + 3 + 128];
409 int n;
410 ullong totalticks;
411 FILE *fp;
412
413 buf[0] = '\0';
414 totalticks = 0;
415
416 fp = NULL;
417 if (!G.cant_enable_timer_stats)
418 fp = fopen_for_read("/proc/timer_stats");
419 if (fp) {
420// Example file contents:
421// Timer Stats Version: v0.2
422// Sample period: 1.329 s
423// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
424// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
425// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup)
426// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn)
427// ...
428// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup)
429// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup)
430// 331 total events, 249.059 events/sec
431 while (fgets(buf, sizeof(buf), fp)) {
432 const char *count, *process, *func;
433 char *p;
434 int cnt;
435
436 count = skip_whitespace(buf);
437 p = strchr(count, ',');
438 if (!p)
439 continue;
440 *p++ = '\0';
441 if (strcmp(strchrnul(count, ' '), " total events") == 0)
442 break;
443 p = skip_whitespace(p); /* points to pid */
444
445/* Find char ' ', then eat remaining spaces */
446#define ADVANCE(p) do { \
447 (p) = strchr((p), ' '); \
448 if (!(p)) \
449 continue; \
450 *(p) = '\0'; \
451 (p)++; \
452 (p) = skip_whitespace(p); \
453} while (0)
454 /* Get process name */
455 ADVANCE(p);
456 process = p;
457 /* Get function */
458 ADVANCE(p);
459 func = p;
460#undef ADVANCE
461 //if (strcmp(process, "swapper") == 0
462 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0
463 //) {
464 // process = "[kernel scheduler]";
465 // func = "Load balancing tick";
466 //}
467
468 if (strncmp(func, "tick_nohz_", 10) == 0)
469 continue;
470 if (strncmp(func, "tick_setup_sched_timer", 20) == 0)
471 continue;
472 //if (strcmp(process, "powertop") == 0)
473 // continue;
474
475 if (strcmp(process, "insmod") == 0)
476 process = "[kernel module]";
477 if (strcmp(process, "modprobe") == 0)
478 process = "[kernel module]";
479 if (strcmp(process, "swapper") == 0)
480 process = "<kernel core>";
481
482 strchrnul(p, '\n')[0] = '\0';
483
484 {
485 char *tmp;
486 cnt = bb_strtoull(count, &tmp, 10);
487 p = tmp;
488 }
489 while (*p != '\0') {
490 if (*p++ == 'D') /* deferred */
491 goto skip;
492 }
493
494 //if (strchr(process, '['))
495 sprintf(line, "%15.15s : %s", process, func);
496 //else
497 // sprintf(line, "%s", process);
498 save_line(line, cnt);
499 skip: ;
500 }
501 fclose(fp);
502 }
503
504 n = 0;
505#if ENABLE_FEATURE_POWERTOP_PROCIRQ
506 if (strstr(buf, "total events")) {
507 n = bb_strtoull(buf, NULL, 10) / G.total_cpus;
508 if (n > 0 && n < G.interrupt_0) {
509 sprintf(line, " <interrupt> : %s", "extra timer interrupt");
510 save_line(line, G.interrupt_0 - n);
511 }
512 }
513#endif
514 return n;
515}
516
405#ifdef __i386__ 517#ifdef __i386__
406/* 518/*
407 * Get information about CPU using CPUID opcode. 519 * Get information about CPU using CPUID opcode.
@@ -428,7 +540,7 @@ static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
428} 540}
429#endif 541#endif
430 542
431static void NOINLINE print_intel_cstates(void) 543static NOINLINE void print_intel_cstates(void)
432{ 544{
433#ifdef __i386__ 545#ifdef __i386__
434 int bios_table[8] = { 0 }; 546 int bios_table[8] = { 0 };
@@ -462,7 +574,7 @@ static void NOINLINE print_intel_cstates(void)
462 574
463 /* 575 /*
464 * Every C-state has its own stateN directory, that 576 * Every C-state has its own stateN directory, that
465 * contains a `time' and a `usage' file. 577 * contains a 'time' and a 'usage' file.
466 */ 578 */
467 while ((d = readdir(dir)) != NULL) { 579 while ((d = readdir(dir)) != NULL) {
468 FILE *fp; 580 FILE *fp;
@@ -525,25 +637,6 @@ static void NOINLINE print_intel_cstates(void)
525#endif 637#endif
526} 638}
527 639
528static void print_header(void)
529{
530 printf(
531 /* Clear the screen */
532 "\033[H\033[J"
533 /* Print the header */
534 "\033[7m%.*s\033[0m", 79, "PowerTOP (C) 2007 Intel Corporation\n"
535 );
536}
537
538static void show_cstates(char cstate_lines[][64])
539{
540 int i;
541
542 for (i = 0; i < 10; i++)
543 if ((cstate_lines[i][0]))
544 printf("%s", cstate_lines[i]);
545}
546
547static void show_timerstats(void) 640static void show_timerstats(void)
548{ 641{
549 unsigned lines; 642 unsigned lines;
@@ -556,19 +649,26 @@ static void show_timerstats(void)
556 649
557 if (!G.cant_enable_timer_stats) { 650 if (!G.cant_enable_timer_stats) {
558 int i, n = 0; 651 int i, n = 0;
652 char strbuf6[6];
559 653
654 strbuf6[5] = '\0';
560 puts("\nTop causes for wakeups:"); 655 puts("\nTop causes for wakeups:");
561 for (i = 0; i < G.lines_cnt; i++) { 656 for (i = 0; i < G.lines_cnt; i++) {
562 if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) 657 if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/)
563 && n++ < lines 658 && n++ < lines
564 ) { 659 ) {
565 char c = ' '; 660 /* NB: upstream powertop prints "(wakeups/sec)",
566 /*if (G.lines[i].disk_count) 661 * we print just "(wakeup counts)".
662 */
663 /*char c = ' ';
664 if (G.lines[i].disk_count)
567 c = 'D';*/ 665 c = 'D';*/
568 printf(" %5.1f%% (%5.1f)%c %s\n", 666 smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY");
569 G.lines[i].count * 100.0 / G.lines_cumulative_count, 667 printf(/*" %5.1f%% (%s)%c %s\n"*/
570 G.lines[i].count * 1.0 / DEFAULT_SLEEP, c, 668 " %5.1f%% (%s) %s\n",
571 G.lines[i].string); 669 G.lines[i].count * 100.0 / G.lines_cumulative_count,
670 strbuf6, /*c,*/
671 G.lines[i].string);
572 } 672 }
573 } 673 }
574 } else { 674 } else {
@@ -606,8 +706,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
606{ 706{
607 ullong cur_usage[MAX_CSTATE_COUNT]; 707 ullong cur_usage[MAX_CSTATE_COUNT];
608 ullong cur_duration[MAX_CSTATE_COUNT]; 708 ullong cur_duration[MAX_CSTATE_COUNT];
609 char cstate_lines[12][64]; 709 char cstate_lines[MAX_CSTATE_COUNT + 2][64];
610 char buf[128];
611#if ENABLE_FEATURE_USE_TERMIOS 710#if ENABLE_FEATURE_USE_TERMIOS
612 struct termios new_settings; 711 struct termios new_settings;
613 struct pollfd pfd[1]; 712 struct pollfd pfd[1];
@@ -644,7 +743,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
644#endif 743#endif
645 744
646 /* Collect initial data */ 745 /* Collect initial data */
647 process_irq_count_deltas(); 746 process_irq_counts();
648 747
649 /* Read initial usage and duration */ 748 /* Read initial usage and duration */
650 read_cstate_counts(G.start_usage, G.start_duration); 749 read_cstate_counts(G.start_usage, G.start_duration);
@@ -660,10 +759,9 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
660 759
661 /* The main loop */ 760 /* The main loop */
662 for (;;) { 761 for (;;) {
663 /*double maxsleep = 0.0;*/ 762 //double maxsleep = 0.0;
664 ullong totalticks, totalevents; 763 ullong totalticks, totalevents;
665 int i; 764 int i;
666 FILE *fp;
667 765
668 G.cant_enable_timer_stats |= start_timer(); /* 1 on error */ 766 G.cant_enable_timer_stats |= start_timer(); /* 1 on error */
669#if !ENABLE_FEATURE_USE_TERMIOS 767#if !ENABLE_FEATURE_USE_TERMIOS
@@ -682,7 +780,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
682 G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ 780 G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */
683 781
684 clear_lines(); 782 clear_lines();
685 process_irq_count_deltas(); 783 process_irq_counts();
686 784
687 /* Clear the stats */ 785 /* Clear the stats */
688 memset(cur_duration, 0, sizeof(cur_duration)); 786 memset(cur_duration, 0, sizeof(cur_duration));
@@ -700,8 +798,8 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
700 } 798 }
701 } 799 }
702 800
703 /* Show title bar */ 801 /* Clear the screen */
704 print_header(); 802 printf("\033[H\033[J");
705 803
706 /* Clear C-state lines */ 804 /* Clear C-state lines */
707 memset(&cstate_lines, 0, sizeof(cstate_lines)); 805 memset(&cstate_lines, 0, sizeof(cstate_lines));
@@ -711,7 +809,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
711 sprintf(cstate_lines[5], "< Detailed C-state information is not " 809 sprintf(cstate_lines[5], "< Detailed C-state information is not "
712 "available.>\n"); 810 "available.>\n");
713 } else { 811 } else {
714 double slept;
715 double percentage; 812 double percentage;
716 double newticks; 813 double newticks;
717 814
@@ -721,7 +818,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
721 if (newticks < 0) 818 if (newticks < 0)
722 newticks = 0; 819 newticks = 0;
723 820
724 sprintf(cstate_lines[0], "Cn\t Avg residency\n"); 821 sprintf(cstate_lines[0], "Cn\t\t Avg residency\n");
725 percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); 822 percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000);
726 sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", 823 sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n",
727 percentage); 824 percentage);
@@ -729,6 +826,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
729 /* Compute values for individual C-states */ 826 /* Compute values for individual C-states */
730 for (i = 0; i < MAX_CSTATE_COUNT; i++) { 827 for (i = 0; i < MAX_CSTATE_COUNT; i++) {
731 if (cur_usage[i] != 0) { 828 if (cur_usage[i] != 0) {
829 double slept;
732 slept = (cur_duration[i] - G.last_duration[i]) 830 slept = (cur_duration[i] - G.last_duration[i])
733 / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; 831 / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI;
734 percentage = (cur_duration[i] - G.last_duration[i]) * 100 832 percentage = (cur_duration[i] - G.last_duration[i]) * 100
@@ -736,125 +834,35 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
736 834
737 if (!G.cstate_names[i][0]) 835 if (!G.cstate_names[i][0])
738 sprintf(G.cstate_names[i], "C%u", i + 1); 836 sprintf(G.cstate_names[i], "C%u", i + 1);
739 sprintf(cstate_lines[i + 2], "%s\t%5.1fms (%4.1f%%)\n", 837 sprintf(cstate_lines[i + 2], "%s\t\t%5.1fms (%4.1f%%)\n",
740 G.cstate_names[i], slept, percentage); 838 G.cstate_names[i], slept, percentage);
741 /*if (maxsleep < slept) 839 //if (maxsleep < slept)
742 maxsleep = slept;*/ 840 // maxsleep = slept;
743 } 841 }
744 } 842 }
745 } 843 }
746 844
747 /* Display C-states */ 845 for (i = 0; i < MAX_CSTATE_COUNT + 2; i++)
748 show_cstates(cstate_lines); 846 if (cstate_lines[i][0])
749 847 printf("%s", cstate_lines[i]);
750 /* Do timer_stats info */
751 buf[0] = '\0';
752 totalticks = 0;
753
754 fp = NULL;
755 if (!G.cant_enable_timer_stats)
756 fp = fopen_for_read("/proc/timer_stats");
757 if (fp) {
758// Examlpe file contents:
759// Timer Stats Version: v0.2
760// Sample period: 1.329 s
761// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
762// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
763// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup)
764// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn)
765// ...
766// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup)
767// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup)
768// 331 total events, 249.059 events/sec
769 while (fgets(buf, sizeof(buf), fp)) {
770 const char *count, *process, *func;
771 char *p;
772 char line[512];
773 int cnt = 0;
774// TODO: optimize
775 if (strstr(buf, "total events"))
776 break;
777 count = skip_whitespace(buf);
778 p = strchr(count, ',');
779 if (!p)
780 continue;
781 *p++ = '\0';
782 p = skip_whitespace(p); /* points to pid */
783
784/* Find char ' ', then eat remaining spaces */
785#define ADVANCE(p) do { \
786 (p) = strchr((p), ' '); \
787 if (!(p)) \
788 continue; \
789 *(p) = '\0'; \
790 (p)++; \
791 (p) = skip_whitespace(p); \
792} while (0)
793 /* Get process name */
794 ADVANCE(p);
795 process = p;
796
797 /* Get function */
798 ADVANCE(p);
799 func = p;
800
801 if (strcmp(process, "swapper") == 0
802 && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0
803 ) {
804 process = "[kernel scheduler]";
805 func = "Load balancing tick";
806 }
807
808 if (strcmp(process, "insmod") == 0)
809 process = "[kernel module]";
810 if (strcmp(process, "modprobe") == 0)
811 process = "[kernel module]";
812 if (strcmp(process, "swapper") == 0)
813 process = "[kernel core]";
814
815 if (strncmp(func, "tick_nohz_", 10) == 0)
816 continue;
817 if (strncmp(func, "tick_setup_sched_timer", 20) == 0)
818 continue;
819 if (strcmp(process, "powertop") == 0)
820 continue;
821
822 strchrnul(p, '\n')[0] = '\0';
823
824 cnt = bb_strtoull(count, &p, 10);
825 while (*p != '\0') {
826 if (*p++ == 'D')
827 goto skip;
828 }
829
830 if (strchr(process, '['))
831 sprintf(line, "%s %s", process, func);
832 else
833 sprintf(line, "%s", process);
834 save_line(line, cnt);
835 skip: ;
836 }
837 fclose(fp);
838 }
839 848
849 i = process_timer_stats();
840#if ENABLE_FEATURE_POWERTOP_PROCIRQ 850#if ENABLE_FEATURE_POWERTOP_PROCIRQ
841 if (strstr(buf, "total events")) { 851 if (totalevents == 0) {
842 int n = bb_strtoull(buf, NULL, 10) / G.total_cpus; 852 /* No C-state info available, use timerstats */
843 853 totalevents = i * G.total_cpus + G.total_interrupt;
844 if (totalevents == 0) { 854 if (i < 0)
845 /* No C-state info available, use timerstats */ 855 totalevents += G.interrupt_0 - i;
846 totalevents = n * G.total_cpus + G.total_interrupt;
847 if (n < 0)
848 totalevents += G.interrupt_0 - n;
849 }
850 if (n > 0 && n < G.interrupt_0)
851 save_line("[extra timer interrupt]", G.interrupt_0 - n);
852 } 856 }
853#endif 857#endif
854 if (totalevents != 0) 858 /* Upstream powertop prints wakeups per sec per CPU,
855 printf("\n\033[1mWakeups-from-idle per second : %4.1f\tinterval:" 859 * we print just raw wakeup counts.
856 "%ds\n\033[0m", 860 */
857 (double)totalevents / DEFAULT_SLEEP / G.total_cpus, DEFAULT_SLEEP); 861//TODO: show real seconds (think about manual refresh)
862 printf("\nWakeups-from-idle in %u seconds: %llu\n",
863 DEFAULT_SLEEP,
864 totalevents
865 );
858 866
859 update_lines_cumulative_count(); 867 update_lines_cumulative_count();
860 sort_lines(); 868 sort_lines();