tools/power turbostat: add --out option for saving output in a file
authorLen Brown <len.brown@intel.com>
Sun, 14 Feb 2016 04:36:17 +0000 (23:36 -0500)
committerLen Brown <len.brown@intel.com>
Sun, 13 Mar 2016 07:55:39 +0000 (03:55 -0400)
By default...

Turbostat --debug gconfiguration info goes to stderr.

In FORK mode, turbostat statistics go to stderr.

In PERIODIC mode, turbostat statistics go to stdout.

These defaults do not change, but an option "--out file"
will send all output above only to the specified file.

Signed-off-by: Len Brown <len.brown@intel.com>
tools/power/x86/turbostat/turbostat.8
tools/power/x86/turbostat/turbostat.c

index 7771eea3cdecff32511adf785d5e4bcb0e5c722c..89a55d5e32f301e13751101f3f6b9cf7c5c07450 100644 (file)
@@ -36,6 +36,9 @@ more than once may also enable internal turbostat debug information.
 .PP
 \fB--interval seconds\fP overrides the default 5.0 second measurement interval.
 .PP
+\fB--out output_file\fP turbostat output is written to the specified output_file.
+The file is truncated if it already exists, and it is created if it does not exist.
+.PP
 \fB--help\fP displays usage for the most common parameters.
 .PP
 \fB--Joules\fP displays energy in Joules, rather than dividing Joules by time to print power in Watts.
@@ -83,10 +86,11 @@ Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading T
 \fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM.
 .fi
 .PP
-.SH EXAMPLE
+.SH PERIODIC EXAMPLE
 Without any parameters, turbostat displays statistics ever 5 seconds.
-(override interval with "-i sec" option, or specify a command
-for turbostat to fork).
+Periodic output goes to stdout, by default, unless --out is used to specify an output file.
+The 5-second interval can be changed with th "-i sec" option.
+Or a command may be specified as in "FORK EXAMPLE" below.
 .nf
 [root@hsw]# ./turbostat
      CPU Avg_MHz   Busy% Bzy_MHz TSC_MHz
@@ -171,7 +175,9 @@ The --debug option adds additional columns to the measurement ouput, including C
 See the field definitions above.
 .SH FORK EXAMPLE
 If turbostat is invoked with a command, it will fork that command
-and output the statistics gathered when the command exits.
+and output the statistics gathered after the command exits.
+In this case, turbostat output goes to stderr, by default.
+Output can instead be saved to a file using the --out option.
 eg. Here a cycle soaker is run on 1 CPU (see %c0) for a few seconds
 until ^C while the other CPUs are mostly idle:
 
index 947239b53e17bca9a917ef45c6b946c84026220a..5f9f41a3bf91ceb0648308823918289fa2a3ad29 100644 (file)
@@ -44,6 +44,7 @@
 #include <errno.h>
 
 char *proc_stat = "/proc/stat";
+FILE *outf;
 struct timespec interval_ts = {5, 0};
 unsigned int debug;
 unsigned int rapl_joules;
@@ -652,15 +653,24 @@ done:
        return 0;
 }
 
-void flush_stdout()
+void flush_output_stdout(void)
 {
-       fputs(output_buffer, stdout);
-       fflush(stdout);
+       FILE *filep;
+
+       if (outf == stderr)
+               filep = stdout;
+       else
+               filep = outf;
+
+       fputs(output_buffer, filep);
+       fflush(filep);
+
        outp = output_buffer;
 }
-void flush_stderr()
+void flush_output_stderr(void)
 {
-       fputs(output_buffer, stderr);
+       fputs(output_buffer, outf);
+       fflush(outf);
        outp = output_buffer;
 }
 void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
@@ -752,9 +762,9 @@ delta_thread(struct thread_data *new, struct thread_data *old,
                } else {
 
                        if (!aperf_mperf_unstable) {
-                               fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
-                               fprintf(stderr, "* Frequency results do not cover entire interval *\n");
-                               fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
+                               fprintf(outf, "%s: APERF or MPERF went backwards *\n", progname);
+                               fprintf(outf, "* Frequency results do not cover entire interval *\n");
+                               fprintf(outf, "* fix this by running Linux-2.6.30 or later *\n");
 
                                aperf_mperf_unstable = 1;
                        }
@@ -789,7 +799,8 @@ delta_thread(struct thread_data *new, struct thread_data *old,
        }
 
        if (old->mperf == 0) {
-               if (debug > 1) fprintf(stderr, "cpu%d MPERF 0!\n", old->cpu_id);
+               if (debug > 1)
+                       fprintf(outf, "cpu%d MPERF 0!\n", old->cpu_id);
                old->mperf = 1; /* divide by 0 protection */
        }
 
@@ -989,7 +1000,7 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        unsigned long long msr;
 
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
@@ -1182,18 +1193,18 @@ dump_nhm_platform_info(void)
 
        get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
 
        ratio = (msr >> 40) & 0xFF;
-       fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n",
+       fprintf(outf, "%d * %.0f = %.0f MHz max efficiency frequency\n",
                ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 8) & 0xFF;
-       fprintf(stderr, "%d * %.0f = %.0f MHz base frequency\n",
+       fprintf(outf, "%d * %.0f = %.0f MHz base frequency\n",
                ratio, bclk, ratio * bclk);
 
        get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr);
-       fprintf(stderr, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
+       fprintf(outf, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
                base_cpu, msr, msr & 0x2 ? "EN" : "DIS");
 
        return;
@@ -1207,16 +1218,16 @@ dump_hsw_turbo_ratio_limits(void)
 
        get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr);
 
        ratio = (msr >> 8) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 18 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 18 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 0) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 17 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 17 active cores\n",
                        ratio, bclk, ratio * bclk);
        return;
 }
@@ -1229,46 +1240,46 @@ dump_ivt_turbo_ratio_limits(void)
 
        get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr);
 
        ratio = (msr >> 56) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 48) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 40) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 32) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 24) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 12 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 16) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 11 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 8) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 10 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 0) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 9 active cores\n",
                        ratio, bclk, ratio * bclk);
        return;
 }
@@ -1281,46 +1292,46 @@ dump_nhm_turbo_ratio_limits(void)
 
        get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr);
 
        ratio = (msr >> 56) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 8 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 48) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 40) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 6 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 32) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 24) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 16) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 8) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
                        ratio, bclk, ratio * bclk);
 
        ratio = (msr >> 0) & 0xFF;
        if (ratio)
-               fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
+               fprintf(outf, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
                        ratio, bclk, ratio * bclk);
        return;
 }
@@ -1338,7 +1349,7 @@ dump_knl_turbo_ratio_limits(void)
 
        get_msr(base_cpu, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
 
-       fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n",
+       fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n",
                base_cpu, msr);
 
        /**
@@ -1379,7 +1390,7 @@ dump_knl_turbo_ratio_limits(void)
 
        for (i = buckets_no - 1; i >= 0; i--)
                if (i > 0 ? ratio[i] != ratio[i - 1] : 1)
-                       fprintf(stderr,
+                       fprintf(outf,
                                "%d * %.0f = %.0f MHz max turbo %d active cores\n",
                                ratio[i], bclk, ratio[i] * bclk, cores[i]);
 }
@@ -1394,9 +1405,9 @@ dump_nhm_cst_cfg(void)
 #define SNB_C1_AUTO_UNDEMOTE              (1UL << 27)
 #define SNB_C3_AUTO_UNDEMOTE              (1UL << 28)
 
-       fprintf(stderr, "cpu%d: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", base_cpu, msr);
 
-       fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: %s)\n",
+       fprintf(outf, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: %s)\n",
                (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
                (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
                (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
@@ -1413,41 +1424,41 @@ dump_config_tdp(void)
        unsigned long long msr;
 
        get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr);
-       fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr);
-       fprintf(stderr, " (base_ratio=%d)\n", (unsigned int)msr & 0xEF);
+       fprintf(outf, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr);
+       fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xEF);
 
        get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr);
-       fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr);
        if (msr) {
-               fprintf(stderr, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
-               fprintf(stderr, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
-               fprintf(stderr, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
-               fprintf(stderr, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0xEFFF);
+               fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
+               fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
+               fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
+               fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0xEFFF);
        }
-       fprintf(stderr, ")\n");
+       fprintf(outf, ")\n");
 
        get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr);
-       fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr);
        if (msr) {
-               fprintf(stderr, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
-               fprintf(stderr, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
-               fprintf(stderr, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
-               fprintf(stderr, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0xEFFF);
+               fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
+               fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
+               fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
+               fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0xEFFF);
        }
-       fprintf(stderr, ")\n");
+       fprintf(outf, ")\n");
 
        get_msr(base_cpu, MSR_CONFIG_TDP_CONTROL, &msr);
-       fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr);
        if ((msr) & 0x3)
-               fprintf(stderr, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3);
-       fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1);
-       fprintf(stderr, ")\n");
+               fprintf(outf, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3);
+       fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
+       fprintf(outf, ")\n");
        
        get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr);
-       fprintf(stderr, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
-       fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0x7F);
-       fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1);
-       fprintf(stderr, ")\n");
+       fprintf(outf, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0x7F);
+       fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
+       fprintf(outf, ")\n");
 }
 
 void free_all_buffers(void)
@@ -1486,7 +1497,7 @@ void free_all_buffers(void)
  */
 FILE *fopen_or_die(const char *path, const char *mode)
 {
-       FILE *filep = fopen(path, "r");
+       FILE *filep = fopen(path, mode);
        if (!filep)
                err(1, "%s: open failed", path);
        return filep;
@@ -1740,7 +1751,7 @@ restart:
                for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
                compute_average(EVEN_COUNTERS);
                format_all_counters(EVEN_COUNTERS);
-               flush_stdout();
+               flush_output_stdout();
                nanosleep(&interval_ts, NULL);
                retval = for_all_cpus(get_counters, EVEN_COUNTERS);
                if (retval < -1) {
@@ -1754,7 +1765,7 @@ restart:
                for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS);
                compute_average(ODD_COUNTERS);
                format_all_counters(ODD_COUNTERS);
-               flush_stdout();
+               flush_output_stdout();
        }
 }
 
@@ -2022,7 +2033,7 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                return 0;
 
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
@@ -2043,7 +2054,7 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                epb_string = "custom";
                break;
        }
-       fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
+       fprintf(outf, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
 
        return 0;
 }
@@ -2066,14 +2077,14 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                return 0;
 
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
        if (get_msr(cpu, MSR_PM_ENABLE, &msr))
                return 0;
 
-       fprintf(stderr, "cpu%d: MSR_PM_ENABLE: 0x%08llx (%sHWP)\n",
+       fprintf(outf, "cpu%d: MSR_PM_ENABLE: 0x%08llx (%sHWP)\n",
                cpu, msr, (msr & (1 << 0)) ? "" : "No-");
 
        /* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */
@@ -2083,7 +2094,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (get_msr(cpu, MSR_HWP_CAPABILITIES, &msr))
                return 0;
 
-       fprintf(stderr, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx "
+       fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx "
                        "(high 0x%x guar 0x%x eff 0x%x low 0x%x)\n",
                        cpu, msr,
                        (unsigned int)HWP_HIGHEST_PERF(msr),
@@ -2094,7 +2105,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (get_msr(cpu, MSR_HWP_REQUEST, &msr))
                return 0;
 
-       fprintf(stderr, "cpu%d: MSR_HWP_REQUEST: 0x%08llx "
+       fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx "
                        "(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x pkg 0x%x)\n",
                        cpu, msr,
                        (unsigned int)(((msr) >> 0) & 0xff),
@@ -2108,7 +2119,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_HWP_REQUEST_PKG, &msr))
                        return 0;
 
-               fprintf(stderr, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx "
+               fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx "
                        "(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x)\n",
                        cpu, msr,
                        (unsigned int)(((msr) >> 0) & 0xff),
@@ -2121,7 +2132,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_HWP_INTERRUPT, &msr))
                        return 0;
 
-               fprintf(stderr, "cpu%d: MSR_HWP_INTERRUPT: 0x%08llx "
+               fprintf(outf, "cpu%d: MSR_HWP_INTERRUPT: 0x%08llx "
                        "(%s_Guaranteed_Perf_Change, %s_Excursion_Min)\n",
                        cpu, msr,
                        ((msr) & 0x1) ? "EN" : "Dis",
@@ -2130,7 +2141,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (get_msr(cpu, MSR_HWP_STATUS, &msr))
                return 0;
 
-       fprintf(stderr, "cpu%d: MSR_HWP_STATUS: 0x%08llx "
+       fprintf(outf, "cpu%d: MSR_HWP_STATUS: 0x%08llx "
                        "(%sGuaranteed_Perf_Change, %sExcursion_Min)\n",
                        cpu, msr,
                        ((msr) & 0x1) ? "" : "No-",
@@ -2154,14 +2165,14 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
                return 0;
 
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
        if (do_core_perf_limit_reasons) {
                get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr);
-               fprintf(stderr, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
-               fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
+               fprintf(outf, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
+               fprintf(outf, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
                        (msr & 1 << 15) ? "bit15, " : "",
                        (msr & 1 << 14) ? "bit14, " : "",
                        (msr & 1 << 13) ? "Transitions, " : "",
@@ -2176,7 +2187,7 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
                        (msr & 1 << 2) ? "bit2, " : "",
                        (msr & 1 << 1) ? "ThermStatus, " : "",
                        (msr & 1 << 0) ? "PROCHOT, " : "");
-               fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
+               fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
                        (msr & 1 << 31) ? "bit31, " : "",
                        (msr & 1 << 30) ? "bit30, " : "",
                        (msr & 1 << 29) ? "Transitions, " : "",
@@ -2195,8 +2206,8 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
        }
        if (do_gfx_perf_limit_reasons) {
                get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr);
-               fprintf(stderr, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
-               fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s)",
+               fprintf(outf, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
+               fprintf(outf, " (Active: %s%s%s%s%s%s%s%s)",
                        (msr & 1 << 0) ? "PROCHOT, " : "",
                        (msr & 1 << 1) ? "ThermStatus, " : "",
                        (msr & 1 << 4) ? "Graphics, " : "",
@@ -2205,7 +2216,7 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
                        (msr & 1 << 9) ? "GFXPwr, " : "",
                        (msr & 1 << 10) ? "PkgPwrL1, " : "",
                        (msr & 1 << 11) ? "PkgPwrL2, " : "");
-               fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s)\n",
+               fprintf(outf, " (Logged: %s%s%s%s%s%s%s%s)\n",
                        (msr & 1 << 16) ? "PROCHOT, " : "",
                        (msr & 1 << 17) ? "ThermStatus, " : "",
                        (msr & 1 << 20) ? "Graphics, " : "",
@@ -2217,15 +2228,15 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
        }
        if (do_ring_perf_limit_reasons) {
                get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr);
-               fprintf(stderr, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
-               fprintf(stderr, " (Active: %s%s%s%s%s%s)",
+               fprintf(outf, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
+               fprintf(outf, " (Active: %s%s%s%s%s%s)",
                        (msr & 1 << 0) ? "PROCHOT, " : "",
                        (msr & 1 << 1) ? "ThermStatus, " : "",
                        (msr & 1 << 6) ? "VR-Therm, " : "",
                        (msr & 1 << 8) ? "Amps, " : "",
                        (msr & 1 << 10) ? "PkgPwrL1, " : "",
                        (msr & 1 << 11) ? "PkgPwrL2, " : "");
-               fprintf(stderr, " (Logged: %s%s%s%s%s%s)\n",
+               fprintf(outf, " (Logged: %s%s%s%s%s%s)\n",
                        (msr & 1 << 16) ? "PROCHOT, " : "",
                        (msr & 1 << 17) ? "ThermStatus, " : "",
                        (msr & 1 << 22) ? "VR-Therm, " : "",
@@ -2348,7 +2359,7 @@ void rapl_probe(unsigned int family, unsigned int model)
 
        rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
        if (debug)
-               fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
+               fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
 
        return;
 }
@@ -2390,7 +2401,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
                return 0;
 
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
@@ -2399,7 +2410,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
                        return 0;
 
                dts = (msr >> 16) & 0x7F;
-               fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
                        cpu, msr, tcc_activation_temp - dts);
 
 #ifdef THERM_DEBUG
@@ -2408,7 +2419,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
 
                dts = (msr >> 16) & 0x7F;
                dts2 = (msr >> 8) & 0x7F;
-               fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
                        cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
 #endif
        }
@@ -2422,7 +2433,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
 
                dts = (msr >> 16) & 0x7F;
                resolution = (msr >> 27) & 0xF;
-               fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
                        cpu, msr, tcc_activation_temp - dts, resolution);
 
 #ifdef THERM_DEBUG
@@ -2431,7 +2442,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
 
                dts = (msr >> 16) & 0x7F;
                dts2 = (msr >> 8) & 0x7F;
-               fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
                        cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
 #endif
        }
@@ -2441,7 +2452,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
        
 void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
 {
-       fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
+       fprintf(outf, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
                cpu, label,
                ((msr >> 15) & 1) ? "EN" : "DIS",
                ((msr >> 0) & 0x7FFF) * rapl_power_units,
@@ -2465,7 +2476,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 
        cpu = t->cpu_id;
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
@@ -2473,7 +2484,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                return -1;
 
        if (debug) {
-               fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
+               fprintf(outf, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
                        "(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
                        rapl_power_units, rapl_energy_units, rapl_time_units);
        }
@@ -2483,7 +2494,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                        return -5;
 
 
-               fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
+               fprintf(outf, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
                        cpu, msr,
                        ((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
                        ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
@@ -2496,11 +2507,11 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
                        return -9;
 
-               fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
+               fprintf(outf, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
                        cpu, msr, (msr >> 63) & 1 ? "": "UN");
 
                print_power_limit_msr(cpu, msr, "PKG Limit #1");
-               fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
+               fprintf(outf, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
                        cpu,
                        ((msr >> 47) & 1) ? "EN" : "DIS",
                        ((msr >> 32) & 0x7FFF) * rapl_power_units,
@@ -2512,7 +2523,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
                        return -6;
 
-               fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
+               fprintf(outf, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
                        cpu, msr,
                        ((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
                        ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
@@ -2522,7 +2533,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        if (do_rapl & RAPL_DRAM) {
                if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
                        return -9;
-               fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
+               fprintf(outf, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
                                cpu, msr, (msr >> 31) & 1 ? "": "UN");
 
                print_power_limit_msr(cpu, msr, "DRAM Limit");
@@ -2532,7 +2543,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                        if (get_msr(cpu, MSR_PP0_POLICY, &msr))
                                return -7;
 
-                       fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
+                       fprintf(outf, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
                }
        }
        if (do_rapl & RAPL_CORES) {
@@ -2540,7 +2551,7 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 
                        if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
                                return -9;
-                       fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                       fprintf(outf, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
                                        cpu, msr, (msr >> 31) & 1 ? "": "UN");
                        print_power_limit_msr(cpu, msr, "Cores Limit");
                }
@@ -2550,11 +2561,11 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                        if (get_msr(cpu, MSR_PP1_POLICY, &msr))
                                return -8;
 
-                       fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
+                       fprintf(outf, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
 
                        if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
                                return -9;
-                       fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                       fprintf(outf, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
                                        cpu, msr, (msr >> 31) & 1 ? "": "UN");
                        print_power_limit_msr(cpu, msr, "GFX Limit");
                }
@@ -2680,16 +2691,16 @@ double slm_bclk(void)
        double freq;
 
        if (get_msr(base_cpu, MSR_FSB_FREQ, &msr))
-               fprintf(stderr, "SLM BCLK: unknown\n");
+               fprintf(outf, "SLM BCLK: unknown\n");
 
        i = msr & 0xf;
        if (i >= SLM_BCLK_FREQS) {
-               fprintf(stderr, "SLM BCLK[%d] invalid\n", i);
+               fprintf(outf, "SLM BCLK[%d] invalid\n", i);
                msr = 3;
        }
        freq = slm_freq_table[i];
 
-       fprintf(stderr, "SLM BCLK: %.1f Mhz\n", freq);
+       fprintf(outf, "SLM BCLK: %.1f Mhz\n", freq);
 
        return freq;
 }
@@ -2732,13 +2743,13 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
 
        cpu = t->cpu_id;
        if (cpu_migrate(cpu)) {
-               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
        if (tcc_activation_temp_override != 0) {
                tcc_activation_temp = tcc_activation_temp_override;
-               fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n",
+               fprintf(outf, "cpu%d: Using cmdline TCC Target (%d C)\n",
                        cpu, tcc_activation_temp);
                return 0;
        }
@@ -2753,7 +2764,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
        target_c_local = (msr >> 16) & 0xFF;
 
        if (debug)
-               fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
                        cpu, msr, target_c_local);
 
        if (!target_c_local)
@@ -2765,7 +2776,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
 
 guess:
        tcc_activation_temp = TJMAX_DEFAULT;
-       fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
+       fprintf(outf, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
                cpu, tcc_activation_temp);
 
        return 0;
@@ -2776,7 +2787,7 @@ void decode_misc_enable_msr(void)
        unsigned long long msr;
 
        if (!get_msr(base_cpu, MSR_IA32_MISC_ENABLE, &msr))
-               fprintf(stderr, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%s %s %s)\n",
+               fprintf(outf, "cpu%d: MSR_IA32_MISC_ENABLE: 0x%08llx (%s %s %s)\n",
                        base_cpu, msr,
                        msr & (1 << 3) ? "TCC" : "",
                        msr & (1 << 16) ? "EIST" : "",
@@ -2798,7 +2809,7 @@ void decode_misc_pwr_mgmt_msr(void)
                return;
 
        if (!get_msr(base_cpu, MSR_MISC_PWR_MGMT, &msr))
-               fprintf(stderr, "cpu%d: MSR_MISC_PWR_MGMT: 0x%08llx (%sable-EIST_Coordination %sable-EPB)\n",
+               fprintf(outf, "cpu%d: MSR_MISC_PWR_MGMT: 0x%08llx (%sable-EIST_Coordination %sable-EPB)\n",
                        base_cpu, msr,
                        msr & (1 << 0) ? "DIS" : "EN",
                        msr & (1 << 1) ? "EN" : "DIS");
@@ -2817,7 +2828,7 @@ void process_cpuid()
                genuine_intel = 1;
 
        if (debug)
-               fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
+               fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
                        (char *)&ebx, (char *)&edx, (char *)&ecx);
 
        __get_cpuid(1, &fms, &ebx, &ecx, &edx);
@@ -2828,9 +2839,9 @@ void process_cpuid()
                model += ((fms >> 16) & 0xf) << 4;
 
        if (debug) {
-               fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
+               fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
                        max_level, family, model, stepping, family, model, stepping);
-               fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n",
+               fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s\n",
                        ecx & (1 << 0) ? "SSE3" : "-",
                        ecx & (1 << 3) ? "MONITOR" : "-",
                        ecx & (1 << 7) ? "EIST" : "-",
@@ -2879,7 +2890,7 @@ void process_cpuid()
        has_epb = ecx & (1 << 3);
 
        if (debug)
-               fprintf(stderr, "CPUID(6): %sAPERF, %sDTS, %sPTM, %sHWP, "
+               fprintf(outf, "CPUID(6): %sAPERF, %sDTS, %sPTM, %sHWP, "
                        "%sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n",
                        has_aperf ? "" : "No-",
                        do_dts ? "" : "No-",
@@ -2907,7 +2918,7 @@ void process_cpuid()
                if (ebx_tsc != 0) {
 
                        if (debug && (ebx != 0))
-                               fprintf(stderr, "CPUID(0x15): eax_crystal: %d ebx_tsc: %d ecx_crystal_hz: %d\n",
+                               fprintf(outf, "CPUID(0x15): eax_crystal: %d ebx_tsc: %d ecx_crystal_hz: %d\n",
                                        eax_crystal, ebx_tsc, crystal_hz);
 
                        if (crystal_hz == 0)
@@ -2923,7 +2934,7 @@ void process_cpuid()
                        if (crystal_hz) {
                                tsc_hz =  (unsigned long long) crystal_hz * ebx_tsc / eax_crystal;
                                if (debug)
-                                       fprintf(stderr, "TSC: %lld MHz (%d Hz * %d / %d / 1000000)\n",
+                                       fprintf(outf, "TSC: %lld MHz (%d Hz * %d / %d / 1000000)\n",
                                                tsc_hz / 1000000, crystal_hz, ebx_tsc,  eax_crystal);
                        }
                }
@@ -2938,7 +2949,7 @@ void process_cpuid()
 
                __get_cpuid(0x16, &base_mhz, &max_mhz, &bus_mhz, &edx);
                if (debug)
-                       fprintf(stderr, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n",
+                       fprintf(outf, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n",
                                base_mhz, max_mhz, bus_mhz);
        }
 
@@ -2973,7 +2984,7 @@ void process_cpuid()
 
 void help()
 {
-       fprintf(stderr,
+       fprintf(outf,
        "Usage: turbostat [OPTIONS][(--interval seconds) | COMMAND ...]\n"
        "\n"
        "Turbostat forks the specified COMMAND and prints statistics\n"
@@ -2985,6 +2996,7 @@ void help()
        "--help         print this help message\n"
        "--counter msr  print 32-bit counter at address \"msr\"\n"
        "--Counter msr  print 64-bit Counter at address \"msr\"\n"
+       "--out file     create or truncate \"file\" for all output\n"
        "--msr msr      print 32-bit value at address \"msr\"\n"
        "--MSR msr      print 64-bit Value at address \"msr\"\n"
        "--version      print version information\n"
@@ -3029,7 +3041,7 @@ void topology_probe()
                show_cpu = 1;
 
        if (debug > 1)
-               fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
+               fprintf(outf, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
 
        cpus = calloc(1, (topo.max_cpu_num  + 1) * sizeof(struct cpu_topology));
        if (cpus == NULL)
@@ -3064,7 +3076,7 @@ void topology_probe()
 
                if (cpu_is_not_present(i)) {
                        if (debug > 1)
-                               fprintf(stderr, "cpu%d NOT PRESENT\n", i);
+                               fprintf(outf, "cpu%d NOT PRESENT\n", i);
                        continue;
                }
                cpus[i].core_id = get_core_id(i);
@@ -3079,26 +3091,26 @@ void topology_probe()
                if (siblings > max_siblings)
                        max_siblings = siblings;
                if (debug > 1)
-                       fprintf(stderr, "cpu %d pkg %d core %d\n",
+                       fprintf(outf, "cpu %d pkg %d core %d\n",
                                i, cpus[i].physical_package_id, cpus[i].core_id);
        }
        topo.num_cores_per_pkg = max_core_id + 1;
        if (debug > 1)
-               fprintf(stderr, "max_core_id %d, sizing for %d cores per package\n",
+               fprintf(outf, "max_core_id %d, sizing for %d cores per package\n",
                        max_core_id, topo.num_cores_per_pkg);
        if (debug && !summary_only && topo.num_cores_per_pkg > 1)
                show_core = 1;
 
        topo.num_packages = max_package_id + 1;
        if (debug > 1)
-               fprintf(stderr, "max_package_id %d, sizing for %d packages\n",
+               fprintf(outf, "max_package_id %d, sizing for %d packages\n",
                        max_package_id, topo.num_packages);
        if (debug && !summary_only && topo.num_packages > 1)
                show_pkg = 1;
 
        topo.num_threads_per_core = max_siblings;
        if (debug > 1)
-               fprintf(stderr, "max_siblings %d\n", max_siblings);
+               fprintf(outf, "max_siblings %d\n", max_siblings);
 
        free(cpus);
 }
@@ -3207,7 +3219,7 @@ void set_base_cpu(void)
                err(-ENODEV, "No valid cpus found");
 
        if (debug > 1)
-               fprintf(stderr, "base_cpu = %d\n", base_cpu);
+               fprintf(outf, "base_cpu = %d\n", base_cpu);
 }
 
 void turbostat_init()
@@ -3274,9 +3286,10 @@ int fork_it(char **argv)
        for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
        compute_average(EVEN_COUNTERS);
        format_all_counters(EVEN_COUNTERS);
-       flush_stderr();
 
-       fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
+       fprintf(outf, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
+
+       flush_output_stderr();
 
        return status;
 }
@@ -3293,13 +3306,13 @@ int get_and_dump_counters(void)
        if (status)
                return status;
 
-       flush_stdout();
+       flush_output_stdout();
 
        return status;
 }
 
 void print_version() {
-       fprintf(stderr, "turbostat version 4.10 10 Dec, 2015"
+       fprintf(outf, "turbostat version 4.10 10 Dec, 2015"
                " - Len Brown <lenb@kernel.org>\n");
 }
 
@@ -3317,6 +3330,7 @@ void cmdline(int argc, char **argv)
                {"Joules",      no_argument,            0, 'J'},
                {"MSR",         required_argument,      0, 'M'},
                {"msr",         required_argument,      0, 'm'},
+               {"out",         required_argument,      0, 'o'},
                {"Package",     no_argument,            0, 'p'},
                {"processor",   no_argument,            0, 'p'},
                {"Summary",     no_argument,            0, 'S'},
@@ -3327,7 +3341,7 @@ void cmdline(int argc, char **argv)
 
        progname = argv[0];
 
-       while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:PpST:v",
+       while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:PpST:v",
                                long_options, &option_index)) != -1) {
                switch (opt) {
                case 'C':
@@ -3351,7 +3365,7 @@ void cmdline(int argc, char **argv)
                                double interval = strtod(optarg, NULL);
 
                                if (interval < 0.001) {
-                                       fprintf(stderr, "interval %f seconds is too small\n",
+                                       fprintf(outf, "interval %f seconds is too small\n",
                                                interval);
                                        exit(2);
                                }
@@ -3369,6 +3383,9 @@ void cmdline(int argc, char **argv)
                case 'm':
                        sscanf(optarg, "%x", &extra_msr_offset32);
                        break;
+               case 'o':
+                       outf = fopen_or_die(optarg, "w");
+                       break;
                case 'P':
                        show_pkg_only++;
                        break;
@@ -3391,6 +3408,8 @@ void cmdline(int argc, char **argv)
 
 int main(int argc, char **argv)
 {
+       outf = stderr;
+
        cmdline(argc, argv);
 
        if (debug)