diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-26 12:39:36 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-26 12:39:36 +0200 |
commit | c3f1fa10d601eb5e1b92f55fb49bbd59cde71705 (patch) | |
tree | d9719971ab78299d8c54c6d09a52151a23969ce2 | |
parent | 373789e5675ffaeaab183dc3093664c737f2bd36 (diff) | |
download | busybox-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.c | 330 |
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 | ||
64 | struct globals { | 64 | struct 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 | ||
123 | static void NOINLINE clear_lines(void) | 122 | static 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 | ||
134 | static void update_lines_cumulative_count(void) | 134 | static 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 */ |
301 | static void process_irq_count_deltas(void) | 301 | static 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 | ||
405 | static 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 | ||
431 | static void NOINLINE print_intel_cstates(void) | 543 | static 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 | ||
528 | static 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 | |||
538 | static 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 | |||
547 | static void show_timerstats(void) | 640 | static 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(); |