diff options
| author | Len Brown <len.brown@intel.com> | 2016-02-26 23:48:05 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2016-03-13 03:55:40 -0400 |
| commit | 562a2d377bb9882c49debc9e1be7127a1717e242 (patch) | |
| tree | 78d5fe76290e7e46ae6e824d48bf412946204e9a /tools/power | |
| parent | 36229897ba966bb0dc9e060222ff17b198252367 (diff) | |
tools/power turbostat: show IRQs per CPU
The new IRQ column shows how many interrupts have occurred on each CPU
during the measurement inteval. This information comes from
the difference between /proc/interrupts shapshots made before
and after the measurement interval.
The first row, the system summary, shows the sum of the IRQS
for all CPUs during that interval.
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools/power')
| -rw-r--r-- | tools/power/x86/turbostat/turbostat.c | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 2e47c2bc3e27..c6793268d81f 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
| @@ -75,6 +75,7 @@ unsigned int extra_msr_offset64; | |||
| 75 | unsigned int extra_delta_offset32; | 75 | unsigned int extra_delta_offset32; |
| 76 | unsigned int extra_delta_offset64; | 76 | unsigned int extra_delta_offset64; |
| 77 | unsigned int aperf_mperf_multiplier = 1; | 77 | unsigned int aperf_mperf_multiplier = 1; |
| 78 | int do_irq = 1; | ||
| 78 | int do_smi; | 79 | int do_smi; |
| 79 | double bclk; | 80 | double bclk; |
| 80 | double base_hz; | 81 | double base_hz; |
| @@ -154,6 +155,7 @@ struct thread_data { | |||
| 154 | unsigned long long extra_delta64; | 155 | unsigned long long extra_delta64; |
| 155 | unsigned long long extra_msr32; | 156 | unsigned long long extra_msr32; |
| 156 | unsigned long long extra_delta32; | 157 | unsigned long long extra_delta32; |
| 158 | unsigned int irq_count; | ||
| 157 | unsigned int smi_count; | 159 | unsigned int smi_count; |
| 158 | unsigned int cpu_id; | 160 | unsigned int cpu_id; |
| 159 | unsigned int flags; | 161 | unsigned int flags; |
| @@ -221,6 +223,9 @@ struct topo_params { | |||
| 221 | 223 | ||
| 222 | struct timeval tv_even, tv_odd, tv_delta; | 224 | struct timeval tv_even, tv_odd, tv_delta; |
| 223 | 225 | ||
| 226 | int *irq_column_2_cpu; /* /proc/interrupts column numbers */ | ||
| 227 | int *irqs_per_cpu; /* indexed by cpu_num */ | ||
| 228 | |||
| 224 | void setup_all_buffers(void); | 229 | void setup_all_buffers(void); |
| 225 | 230 | ||
| 226 | int cpu_is_not_present(int cpu) | 231 | int cpu_is_not_present(int cpu) |
| @@ -306,8 +311,8 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) | |||
| 306 | /* | 311 | /* |
| 307 | * Example Format w/ field column widths: | 312 | * Example Format w/ field column widths: |
| 308 | * | 313 | * |
| 309 | * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt | 314 | * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz IRQ SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt |
| 310 | * 123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 | 315 | * 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 |
| 311 | */ | 316 | */ |
| 312 | 317 | ||
| 313 | void print_header(void) | 318 | void print_header(void) |
| @@ -338,6 +343,8 @@ void print_header(void) | |||
| 338 | if (!debug) | 343 | if (!debug) |
| 339 | goto done; | 344 | goto done; |
| 340 | 345 | ||
| 346 | if (do_irq) | ||
| 347 | outp += sprintf(outp, " IRQ"); | ||
| 341 | if (do_smi) | 348 | if (do_smi) |
| 342 | outp += sprintf(outp, " SMI"); | 349 | outp += sprintf(outp, " SMI"); |
| 343 | 350 | ||
| @@ -429,6 +436,8 @@ int dump_counters(struct thread_data *t, struct core_data *c, | |||
| 429 | extra_msr_offset32, t->extra_msr32); | 436 | extra_msr_offset32, t->extra_msr32); |
| 430 | outp += sprintf(outp, "msr0x%x: %016llX\n", | 437 | outp += sprintf(outp, "msr0x%x: %016llX\n", |
| 431 | extra_msr_offset64, t->extra_msr64); | 438 | extra_msr_offset64, t->extra_msr64); |
| 439 | if (do_irq) | ||
| 440 | outp += sprintf(outp, "IRQ: %08X\n", t->irq_count); | ||
| 432 | if (do_smi) | 441 | if (do_smi) |
| 433 | outp += sprintf(outp, "SMI: %08X\n", t->smi_count); | 442 | outp += sprintf(outp, "SMI: %08X\n", t->smi_count); |
| 434 | } | 443 | } |
| @@ -562,6 +571,10 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
| 562 | if (!debug) | 571 | if (!debug) |
| 563 | goto done; | 572 | goto done; |
| 564 | 573 | ||
| 574 | /* IRQ */ | ||
| 575 | if (do_irq) | ||
| 576 | outp += sprintf(outp, "%8d", t->irq_count); | ||
| 577 | |||
| 565 | /* SMI */ | 578 | /* SMI */ |
| 566 | if (do_smi) | 579 | if (do_smi) |
| 567 | outp += sprintf(outp, "%8d", t->smi_count); | 580 | outp += sprintf(outp, "%8d", t->smi_count); |
| @@ -827,6 +840,9 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
| 827 | old->extra_msr32 = new->extra_msr32; | 840 | old->extra_msr32 = new->extra_msr32; |
| 828 | old->extra_msr64 = new->extra_msr64; | 841 | old->extra_msr64 = new->extra_msr64; |
| 829 | 842 | ||
| 843 | if (do_irq) | ||
| 844 | old->irq_count = new->irq_count - old->irq_count; | ||
| 845 | |||
| 830 | if (do_smi) | 846 | if (do_smi) |
| 831 | old->smi_count = new->smi_count - old->smi_count; | 847 | old->smi_count = new->smi_count - old->smi_count; |
| 832 | } | 848 | } |
| @@ -856,10 +872,12 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data | |||
| 856 | t->mperf = 0; | 872 | t->mperf = 0; |
| 857 | t->c1 = 0; | 873 | t->c1 = 0; |
| 858 | 874 | ||
| 859 | t->smi_count = 0; | ||
| 860 | t->extra_delta32 = 0; | 875 | t->extra_delta32 = 0; |
| 861 | t->extra_delta64 = 0; | 876 | t->extra_delta64 = 0; |
| 862 | 877 | ||
| 878 | t->irq_count = 0; | ||
| 879 | t->smi_count = 0; | ||
| 880 | |||
| 863 | /* tells format_counters to dump all fields from this set */ | 881 | /* tells format_counters to dump all fields from this set */ |
| 864 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; | 882 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; |
| 865 | 883 | ||
| @@ -903,6 +921,9 @@ int sum_counters(struct thread_data *t, struct core_data *c, | |||
| 903 | average.threads.extra_delta32 += t->extra_delta32; | 921 | average.threads.extra_delta32 += t->extra_delta32; |
| 904 | average.threads.extra_delta64 += t->extra_delta64; | 922 | average.threads.extra_delta64 += t->extra_delta64; |
| 905 | 923 | ||
| 924 | average.threads.irq_count += t->irq_count; | ||
| 925 | average.threads.smi_count += t->smi_count; | ||
| 926 | |||
| 906 | /* sum per-core values only for 1st thread in core */ | 927 | /* sum per-core values only for 1st thread in core */ |
| 907 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) | 928 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) |
| 908 | return 0; | 929 | return 0; |
| @@ -1000,7 +1021,6 @@ static unsigned long long rdtsc(void) | |||
| 1000 | return low | ((unsigned long long)high) << 32; | 1021 | return low | ((unsigned long long)high) << 32; |
| 1001 | } | 1022 | } |
| 1002 | 1023 | ||
| 1003 | |||
| 1004 | /* | 1024 | /* |
| 1005 | * get_counters(...) | 1025 | * get_counters(...) |
| 1006 | * migrate to cpu | 1026 | * migrate to cpu |
| @@ -1027,6 +1047,8 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |||
| 1027 | t->mperf = t->mperf * aperf_mperf_multiplier; | 1047 | t->mperf = t->mperf * aperf_mperf_multiplier; |
| 1028 | } | 1048 | } |
| 1029 | 1049 | ||
| 1050 | if (do_irq) | ||
| 1051 | t->irq_count = irqs_per_cpu[cpu]; | ||
| 1030 | if (do_smi) { | 1052 | if (do_smi) { |
| 1031 | if (get_msr(cpu, MSR_SMI_COUNT, &msr)) | 1053 | if (get_msr(cpu, MSR_SMI_COUNT, &msr)) |
| 1032 | return -5; | 1054 | return -5; |
| @@ -1515,6 +1537,9 @@ void free_all_buffers(void) | |||
| 1515 | outp = NULL; | 1537 | outp = NULL; |
| 1516 | 1538 | ||
| 1517 | free_fd_percpu(); | 1539 | free_fd_percpu(); |
| 1540 | |||
| 1541 | free(irq_column_2_cpu); | ||
| 1542 | free(irqs_per_cpu); | ||
| 1518 | } | 1543 | } |
| 1519 | 1544 | ||
| 1520 | /* | 1545 | /* |
| @@ -1737,6 +1762,83 @@ int mark_cpu_present(int cpu) | |||
| 1737 | return 0; | 1762 | return 0; |
| 1738 | } | 1763 | } |
| 1739 | 1764 | ||
| 1765 | /* | ||
| 1766 | * snapshot_proc_interrupts() | ||
| 1767 | * | ||
| 1768 | * read and record summary of /proc/interrupts | ||
| 1769 | * | ||
| 1770 | * return 1 if config change requires a restart, else return 0 | ||
| 1771 | */ | ||
| 1772 | int snapshot_proc_interrupts(void) | ||
| 1773 | { | ||
| 1774 | static FILE *fp; | ||
| 1775 | int column, retval; | ||
| 1776 | |||
| 1777 | if (fp == NULL) | ||
| 1778 | fp = fopen_or_die("/proc/interrupts", "r"); | ||
| 1779 | else | ||
| 1780 | rewind(fp); | ||
| 1781 | |||
| 1782 | /* read 1st line of /proc/interrupts to get cpu* name for each column */ | ||
| 1783 | for (column = 0; column < topo.num_cpus; ++column) { | ||
| 1784 | int cpu_number; | ||
| 1785 | |||
| 1786 | retval = fscanf(fp, " CPU%d", &cpu_number); | ||
| 1787 | if (retval != 1) | ||
| 1788 | break; | ||
| 1789 | |||
| 1790 | if (cpu_number > topo.max_cpu_num) { | ||
| 1791 | warn("/proc/interrupts: cpu%d: > %d", cpu_number, topo.max_cpu_num); | ||
| 1792 | return 1; | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | irq_column_2_cpu[column] = cpu_number; | ||
| 1796 | irqs_per_cpu[cpu_number] = 0; | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | /* read /proc/interrupt count lines and sum up irqs per cpu */ | ||
| 1800 | while (1) { | ||
| 1801 | int column; | ||
| 1802 | char buf[64]; | ||
| 1803 | |||
| 1804 | retval = fscanf(fp, " %s:", buf); /* flush irq# "N:" */ | ||
| 1805 | if (retval != 1) | ||
| 1806 | break; | ||
| 1807 | |||
| 1808 | /* read the count per cpu */ | ||
| 1809 | for (column = 0; column < topo.num_cpus; ++column) { | ||
| 1810 | |||
| 1811 | int cpu_number, irq_count; | ||
| 1812 | |||
| 1813 | retval = fscanf(fp, " %d", &irq_count); | ||
| 1814 | if (retval != 1) | ||
| 1815 | break; | ||
| 1816 | |||
| 1817 | cpu_number = irq_column_2_cpu[column]; | ||
| 1818 | irqs_per_cpu[cpu_number] += irq_count; | ||
| 1819 | |||
| 1820 | } | ||
| 1821 | |||
| 1822 | while (getc(fp) != '\n') | ||
| 1823 | ; /* flush interrupt description */ | ||
| 1824 | |||
| 1825 | } | ||
| 1826 | return 0; | ||
| 1827 | } | ||
| 1828 | |||
| 1829 | /* | ||
| 1830 | * snapshot /proc and /sys files | ||
| 1831 | * | ||
| 1832 | * return 1 if configuration restart needed, else return 0 | ||
| 1833 | */ | ||
| 1834 | int snapshot_proc_sysfs_files(void) | ||
| 1835 | { | ||
| 1836 | if (snapshot_proc_interrupts()) | ||
| 1837 | return 1; | ||
| 1838 | |||
| 1839 | return 0; | ||
| 1840 | } | ||
| 1841 | |||
| 1740 | void turbostat_loop() | 1842 | void turbostat_loop() |
| 1741 | { | 1843 | { |
| 1742 | int retval; | 1844 | int retval; |
| @@ -1745,6 +1847,7 @@ void turbostat_loop() | |||
| 1745 | restart: | 1847 | restart: |
| 1746 | restarted++; | 1848 | restarted++; |
| 1747 | 1849 | ||
| 1850 | snapshot_proc_sysfs_files(); | ||
| 1748 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); | 1851 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); |
| 1749 | if (retval < -1) { | 1852 | if (retval < -1) { |
| 1750 | exit(retval); | 1853 | exit(retval); |
| @@ -1764,6 +1867,8 @@ restart: | |||
| 1764 | goto restart; | 1867 | goto restart; |
| 1765 | } | 1868 | } |
| 1766 | nanosleep(&interval_ts, NULL); | 1869 | nanosleep(&interval_ts, NULL); |
| 1870 | if (snapshot_proc_sysfs_files()) | ||
| 1871 | goto restart; | ||
| 1767 | retval = for_all_cpus(get_counters, ODD_COUNTERS); | 1872 | retval = for_all_cpus(get_counters, ODD_COUNTERS); |
| 1768 | if (retval < -1) { | 1873 | if (retval < -1) { |
| 1769 | exit(retval); | 1874 | exit(retval); |
| @@ -1778,6 +1883,8 @@ restart: | |||
| 1778 | format_all_counters(EVEN_COUNTERS); | 1883 | format_all_counters(EVEN_COUNTERS); |
| 1779 | flush_output_stdout(); | 1884 | flush_output_stdout(); |
| 1780 | nanosleep(&interval_ts, NULL); | 1885 | nanosleep(&interval_ts, NULL); |
| 1886 | if (snapshot_proc_sysfs_files()) | ||
| 1887 | goto restart; | ||
| 1781 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); | 1888 | retval = for_all_cpus(get_counters, EVEN_COUNTERS); |
| 1782 | if (retval < -1) { | 1889 | if (retval < -1) { |
| 1783 | exit(retval); | 1890 | exit(retval); |
| @@ -3233,9 +3340,20 @@ void allocate_fd_percpu(void) | |||
| 3233 | if (fd_percpu == NULL) | 3340 | if (fd_percpu == NULL) |
| 3234 | err(-1, "calloc fd_percpu"); | 3341 | err(-1, "calloc fd_percpu"); |
| 3235 | } | 3342 | } |
| 3343 | void allocate_irq_buffers(void) | ||
| 3344 | { | ||
| 3345 | irq_column_2_cpu = calloc(topo.num_cpus, sizeof(int)); | ||
| 3346 | if (irq_column_2_cpu == NULL) | ||
| 3347 | err(-1, "calloc %d", topo.num_cpus); | ||
| 3348 | |||
| 3349 | irqs_per_cpu = calloc(topo.max_cpu_num, sizeof(int)); | ||
| 3350 | if (irqs_per_cpu == NULL) | ||
| 3351 | err(-1, "calloc %d", topo.max_cpu_num); | ||
| 3352 | } | ||
| 3236 | void setup_all_buffers(void) | 3353 | void setup_all_buffers(void) |
| 3237 | { | 3354 | { |
| 3238 | topology_probe(); | 3355 | topology_probe(); |
| 3356 | allocate_irq_buffers(); | ||
| 3239 | allocate_fd_percpu(); | 3357 | allocate_fd_percpu(); |
| 3240 | allocate_counters(&thread_even, &core_even, &package_even); | 3358 | allocate_counters(&thread_even, &core_even, &package_even); |
| 3241 | allocate_counters(&thread_odd, &core_odd, &package_odd); | 3359 | allocate_counters(&thread_odd, &core_odd, &package_odd); |
