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(); |
