tools turbostat: harden against cpu online/offline
[firefly-linux-kernel-4.4.55.git] / tools / power / x86 / turbostat / turbostat.c
index 3c6f7808efae53b84cab8926f87b3a5f37ea60ee..ab2f682fd44c6cbc402b4a1ab8cbfd0fa9ce0f2e 100644 (file)
@@ -2,7 +2,7 @@
  * turbostat -- show CPU frequency and C-state residency
  * on modern Intel turbo-capable processors.
  *
- * Copyright (c) 2010, Intel Corporation.
+ * Copyright (c) 2012 Intel Corporation.
  * Len Brown <len.brown@intel.com>
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -19,6 +19,7 @@
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -32,6 +33,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <ctype.h>
+#include <sched.h>
 
 #define MSR_TSC        0x10
 #define MSR_NEHALEM_PLATFORM_INFO      0xCE
@@ -49,6 +51,7 @@
 char *proc_stat = "/proc/stat";
 unsigned int interval_sec = 5; /* set with -i interval_sec */
 unsigned int verbose;          /* set with -v */
+unsigned int summary_only;     /* set with -s */
 unsigned int skip_c0;
 unsigned int skip_c1;
 unsigned int do_nhm_cstates;
@@ -68,9 +71,10 @@ unsigned int show_cpu;
 int aperf_mperf_unstable;
 int backwards_count;
 char *progname;
-int need_reinitialize;
 
 int num_cpus;
+cpu_set_t *cpu_mask;
+size_t cpu_mask_size;
 
 struct counters {
        unsigned long long tsc;         /* per thread */
@@ -99,44 +103,76 @@ struct timeval tv_even;
 struct timeval tv_odd;
 struct timeval tv_delta;
 
-unsigned long long get_msr(int cpu, off_t offset)
+/*
+ * cpu_mask_init(ncpus)
+ *
+ * allocate and clear cpu_mask
+ * set cpu_mask_size
+ */
+void cpu_mask_init(int ncpus)
+{
+       cpu_mask = CPU_ALLOC(ncpus);
+       if (cpu_mask == NULL) {
+               perror("CPU_ALLOC");
+               exit(3);
+       }
+       cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
+       CPU_ZERO_S(cpu_mask_size, cpu_mask);
+}
+
+void cpu_mask_uninit()
+{
+       CPU_FREE(cpu_mask);
+       cpu_mask = NULL;
+       cpu_mask_size = 0;
+}
+
+int cpu_migrate(int cpu)
+{
+       CPU_ZERO_S(cpu_mask_size, cpu_mask);
+       CPU_SET_S(cpu, cpu_mask_size, cpu_mask);
+       if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1)
+               return -1;
+       else
+               return 0;
+}
+
+int get_msr(int cpu, off_t offset, unsigned long long *msr)
 {
        ssize_t retval;
-       unsigned long long msr;
        char pathname[32];
        int fd;
 
        sprintf(pathname, "/dev/cpu/%d/msr", cpu);
        fd = open(pathname, O_RDONLY);
-       if (fd < 0) {
-               perror(pathname);
-               need_reinitialize = 1;
-               return 0;
-       }
-
-       retval = pread(fd, &msr, sizeof msr, offset);
-       if (retval != sizeof msr) {
-               fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
-                       cpu, offset, retval);
-               exit(-2);
-       }
+       if (fd < 0)
+               return -1;
 
+       retval = pread(fd, msr, sizeof *msr, offset);
        close(fd);
-       return msr;
+
+       if (retval != sizeof *msr)
+               return -1;
+
+       return 0;
 }
 
 void print_header(void)
 {
        if (show_pkg)
                fprintf(stderr, "pk");
+       if (show_pkg)
+               fprintf(stderr, " ");
        if (show_core)
-               fprintf(stderr, " cr");
+               fprintf(stderr, "cor");
        if (show_cpu)
                fprintf(stderr, " CPU");
+       if (show_pkg || show_core || show_cpu)
+               fprintf(stderr, " ");
        if (do_nhm_cstates)
-               fprintf(stderr, "    %%c0 ");
+               fprintf(stderr, "   %%c0");
        if (has_aperf)
-               fprintf(stderr, " GHz");
+               fprintf(stderr, "  GHz");
        fprintf(stderr, "  TSC");
        if (do_nhm_cstates)
                fprintf(stderr, "    %%c1");
@@ -147,13 +183,13 @@ void print_header(void)
        if (do_snb_cstates)
                fprintf(stderr, "    %%c7");
        if (do_snb_cstates)
-               fprintf(stderr, "  %%pc2");
+               fprintf(stderr, "   %%pc2");
        if (do_nhm_cstates)
-               fprintf(stderr, "  %%pc3");
+               fprintf(stderr, "   %%pc3");
        if (do_nhm_cstates)
-               fprintf(stderr, "  %%pc6");
+               fprintf(stderr, "   %%pc6");
        if (do_snb_cstates)
-               fprintf(stderr, "  %%pc7");
+               fprintf(stderr, "   %%pc7");
        if (extra_msr_offset)
                fprintf(stderr, "        MSR 0x%x ", extra_msr_offset);
 
@@ -187,6 +223,15 @@ void dump_list(struct counters *cnt)
                dump_cnt(cnt);
 }
 
+/*
+ * column formatting convention & formats
+ * package: "pk" 2 columns %2d
+ * core: "cor" 3 columns %3d
+ * CPU: "CPU" 3 columns %3d
+ * GHz: "GHz" 3 columns %3.2
+ * TSC: "TSC" 3 columns %3.2
+ * percentage " %pc3" %6.2
+ */
 void print_cnt(struct counters *p)
 {
        double interval_float;
@@ -196,39 +241,45 @@ void print_cnt(struct counters *p)
        /* topology columns, print blanks on 1st (average) line */
        if (p == cnt_average) {
                if (show_pkg)
+                       fprintf(stderr, "  ");
+               if (show_pkg && show_core)
                        fprintf(stderr, " ");
                if (show_core)
-                       fprintf(stderr, "    ");
+                       fprintf(stderr, "   ");
                if (show_cpu)
-                       fprintf(stderr, "    ");
+                       fprintf(stderr, " " "   ");
        } else {
                if (show_pkg)
-                       fprintf(stderr, "%d", p->pkg);
+                       fprintf(stderr, "%2d", p->pkg);
+               if (show_pkg && show_core)
+                       fprintf(stderr, " ");
                if (show_core)
-                       fprintf(stderr, "%4d", p->core);
+                       fprintf(stderr, "%3d", p->core);
                if (show_cpu)
-                       fprintf(stderr, "%4d", p->cpu);
+                       fprintf(stderr, " %3d", p->cpu);
        }
 
        /* %c0 */
        if (do_nhm_cstates) {
+               if (show_pkg || show_core || show_cpu)
+                       fprintf(stderr, " ");
                if (!skip_c0)
-                       fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
+                       fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc);
                else
-                       fprintf(stderr, "   ****");
+                       fprintf(stderr, "  ****");
        }
 
        /* GHz */
        if (has_aperf) {
                if (!aperf_mperf_unstable) {
-                       fprintf(stderr, "%5.2f",
+                       fprintf(stderr, " %3.2f",
                                1.0 * p->tsc / units * p->aperf /
                                p->mperf / interval_float);
                } else {
                        if (p->aperf > p->tsc || p->mperf > p->tsc) {
-                               fprintf(stderr, " ****");
+                               fprintf(stderr, " ***");
                        } else {
-                               fprintf(stderr, "%4.1f*",
+                               fprintf(stderr, "%3.1f*",
                                        1.0 * p->tsc /
                                        units * p->aperf /
                                        p->mperf / interval_float);
@@ -241,7 +292,7 @@ void print_cnt(struct counters *p)
 
        if (do_nhm_cstates) {
                if (!skip_c1)
-                       fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
+                       fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc);
                else
                        fprintf(stderr, "  ****");
        }
@@ -252,13 +303,13 @@ void print_cnt(struct counters *p)
        if (do_snb_cstates)
                fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
        if (do_snb_cstates)
-               fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc);
        if (do_nhm_cstates)
-               fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc);
        if (do_nhm_cstates)
-               fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc);
        if (do_snb_cstates)
-               fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc);
+               fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc);
        if (extra_msr_offset)
                fprintf(stderr, "  0x%016llx", p->extra_msr);
        putc('\n', stderr);
@@ -267,12 +318,20 @@ void print_cnt(struct counters *p)
 void print_counters(struct counters *counters)
 {
        struct counters *cnt;
+       static int printed;
+
 
-       print_header();
+       if (!printed || !summary_only)
+               print_header();
 
        if (num_cpus > 1)
                print_cnt(cnt_average);
 
+       printed = 1;
+
+       if (summary_only)
+               return;
+
        for (cnt = counters; cnt != NULL; cnt = cnt->next)
                print_cnt(cnt);
 
@@ -440,31 +499,51 @@ void compute_average(struct counters *delta, struct counters *avg)
        free(sum);
 }
 
-void get_counters(struct counters *cnt)
+int get_counters(struct counters *cnt)
 {
        for ( ; cnt; cnt = cnt->next) {
-               cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
-               if (do_nhm_cstates)
-                       cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
-               if (do_nhm_cstates)
-                       cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
-               if (do_snb_cstates)
-                       cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
-               if (has_aperf)
-                       cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
-               if (has_aperf)
-                       cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
-               if (do_snb_cstates)
-                       cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
-               if (do_nhm_cstates)
-                       cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
-               if (do_nhm_cstates)
-                       cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
+
+               if (cpu_migrate(cnt->cpu))
+                       return -1;
+
+               if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc))
+                       return -1;
+
+               if (has_aperf) {
+                       if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf))
+                               return -1;
+                       if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf))
+                               return -1;
+               }
+
+               if (do_nhm_cstates) {
+                       if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3))
+                               return -1;
+                       if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6))
+                               return -1;
+               }
+
                if (do_snb_cstates)
-                       cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
+                       if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7))
+                               return -1;
+
+               if (do_nhm_cstates) {
+                       if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3))
+                               return -1;
+                       if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6))
+                               return -1;
+               }
+               if (do_snb_cstates) {
+                       if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2))
+                               return -1;
+                       if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7))
+                               return -1;
+               }
                if (extra_msr_offset)
-                       cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
+                       if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr))
+                               return -1;
        }
+       return 0;
 }
 
 void print_nehalem_info(void)
@@ -475,7 +554,7 @@ void print_nehalem_info(void)
        if (!do_nehalem_platform_info)
                return;
 
-       msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
+       get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
 
        ratio = (msr >> 40) & 0xFF;
        fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@@ -491,7 +570,7 @@ void print_nehalem_info(void)
        if (!do_nehalem_turbo_ratio_limit)
                return;
 
-       msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
+       get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
 
        ratio = (msr >> 24) & 0xFF;
        if (ratio)
@@ -557,7 +636,8 @@ void insert_counters(struct counters **list,
                return;
        }
 
-       show_cpu = 1;   /* there is more than one CPU */
+       if (!summary_only)
+               show_cpu = 1;   /* there is more than one CPU */
 
        /*
         * insert on front of list.
@@ -575,13 +655,15 @@ void insert_counters(struct counters **list,
 
        while (prev->next && (prev->next->pkg < new->pkg)) {
                prev = prev->next;
-               show_pkg = 1;   /* there is more than 1 package */
+               if (!summary_only)
+                       show_pkg = 1;   /* there is more than 1 package */
        }
 
        while (prev->next && (prev->next->pkg == new->pkg)
                && (prev->next->core < new->core)) {
                prev = prev->next;
-               show_core = 1;  /* there is more than 1 core */
+               if (!summary_only)
+                       show_core = 1;  /* there is more than 1 core */
        }
 
        while (prev->next && (prev->next->pkg == new->pkg)
@@ -681,7 +763,7 @@ int get_core_id(int cpu)
 }
 
 /*
- * run func(index, cpu) on every cpu in /proc/stat
+ * run func(pkg, core, cpu) on every cpu in /proc/stat
  */
 
 int for_all_cpus(void (func)(int, int, int))
@@ -717,18 +799,18 @@ int for_all_cpus(void (func)(int, int, int))
 
 void re_initialize(void)
 {
-       printf("turbostat: topology changed, re-initializing.\n");
        free_all_counters();
        num_cpus = for_all_cpus(alloc_new_counters);
-       need_reinitialize = 0;
-       printf("num_cpus is now %d\n", num_cpus);
+       cpu_mask_uninit();
+       cpu_mask_init(num_cpus);
+       printf("turbostat: re-initialized with num_cpus %d\n", num_cpus);
 }
 
 void dummy(int pkg, int core, int cpu) { return; }
 /*
  * check to see if a cpu came on-line
  */
-void verify_num_cpus(void)
+int verify_num_cpus(void)
 {
        int new_num_cpus;
 
@@ -738,8 +820,9 @@ void verify_num_cpus(void)
                if (verbose)
                        printf("num_cpus was %d, is now  %d\n",
                                num_cpus, new_num_cpus);
-               need_reinitialize = 1;
+               return -1;
        }
+       return 0;
 }
 
 void turbostat_loop()
@@ -749,25 +832,25 @@ restart:
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        while (1) {
-               verify_num_cpus();
-               if (need_reinitialize) {
+               if (verify_num_cpus()) {
                        re_initialize();
                        goto restart;
                }
                sleep(interval_sec);
-               get_counters(cnt_odd);
+               if (get_counters(cnt_odd)) {
+                       re_initialize();
+                       goto restart;
+               }
                gettimeofday(&tv_odd, (struct timezone *)NULL);
-
                compute_delta(cnt_odd, cnt_even, cnt_delta);
                timersub(&tv_odd, &tv_even, &tv_delta);
                compute_average(cnt_delta, cnt_average);
                print_counters(cnt_delta);
-               if (need_reinitialize) {
+               sleep(interval_sec);
+               if (get_counters(cnt_even)) {
                        re_initialize();
                        goto restart;
                }
-               sleep(interval_sec);
-               get_counters(cnt_even);
                gettimeofday(&tv_even, (struct timezone *)NULL);
                compute_delta(cnt_even, cnt_odd, cnt_delta);
                timersub(&tv_even, &tv_odd, &tv_delta);
@@ -811,6 +894,8 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
        case 0x2C:      /* Westmere EP - Gulftown */
        case 0x2A:      /* SNB */
        case 0x2D:      /* SNB Xeon */
+       case 0x3A:      /* IVB */
+       case 0x3D:      /* IVB Xeon */
                return 1;
        case 0x2E:      /* Nehalem-EX Xeon - Beckton */
        case 0x2F:      /* Westmere-EX Xeon - Eagleton */
@@ -951,6 +1036,7 @@ void turbostat_init()
        check_super_user();
 
        num_cpus = for_all_cpus(alloc_new_counters);
+       cpu_mask_init(num_cpus);
 
        if (verbose)
                print_nehalem_info();
@@ -1003,8 +1089,11 @@ void cmdline(int argc, char **argv)
 
        progname = argv[0];
 
-       while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
+       while ((opt = getopt(argc, argv, "+svi:M:")) != -1) {
                switch (opt) {
+               case 's':
+                       summary_only++;
+                       break;
                case 'v':
                        verbose++;
                        break;