Эх сурвалжийг харах

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Conflicts:
	tools/perf/builtin-stat.c
Ingo Molnar 14 жил өмнө
parent
commit
51887c8230

+ 11 - 0
tools/perf/Documentation/perf-annotate.txt

@@ -72,6 +72,17 @@ OPTIONS
 	CPUs are specified with -: 0-2. Default is to report samples on all
 	CPUs are specified with -: 0-2. Default is to report samples on all
 	CPUs.
 	CPUs.
 
 
+--asm-raw::
+	Show raw instruction encoding of assembly instructions. They
+	are displayed by default, disable with --no-asm-raw.
+
+--source::
+	Interleave source code with assembly code. Enabled by default,
+	disable with --no-source.
+
+--symfs=<directory>::
+        Look for files with symbols relative to this directory.
+
 SEE ALSO
 SEE ALSO
 --------
 --------
 linkperf:perf-record[1], linkperf:perf-report[1]
 linkperf:perf-record[1], linkperf:perf-report[1]

+ 7 - 0
tools/perf/Documentation/perf-stat.txt

@@ -94,6 +94,13 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
 corresponding events, i.e., they always refer to events defined earlier on the command
 corresponding events, i.e., they always refer to events defined earlier on the command
 line.
 line.
 
 
+-o file::
+-output file::
+Print the output into the designated file.
+
+--append::
+Append to the output file designated with the -o option. Ignored if -o is not specified.
+
 EXAMPLES
 EXAMPLES
 --------
 --------
 
 

+ 6 - 0
tools/perf/builtin-annotate.c

@@ -267,6 +267,12 @@ static const struct option options[] = {
 	OPT_BOOLEAN('P', "full-paths", &full_paths,
 	OPT_BOOLEAN('P', "full-paths", &full_paths,
 		    "Don't shorten the displayed pathnames"),
 		    "Don't shorten the displayed pathnames"),
 	OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
 	OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
+	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+		   "Look for files with symbols relative to this directory"),
+	OPT_BOOLEAN('0', "source", &symbol_conf.annotate_src,
+		    "Interleave source code with assembly code (default)"),
+	OPT_BOOLEAN('0', "asm-raw", &symbol_conf.annotate_asm_raw,
+		    "Display raw encoding of assembly instructions (default)"),
 	OPT_END()
 	OPT_END()
 };
 };
 
 

+ 92 - 63
tools/perf/builtin-stat.c

@@ -194,6 +194,8 @@ static const char		*cpu_list;
 static const char		*csv_sep			= NULL;
 static const char		*csv_sep			= NULL;
 static bool			csv_output			= false;
 static bool			csv_output			= false;
 static bool			group				= false;
 static bool			group				= false;
+static const char		*output_name			= NULL;
+static FILE			*output				= NULL;
 
 
 static volatile int done = 0;
 static volatile int done = 0;
 
 
@@ -352,7 +354,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
 		update_stats(&ps->res_stats[i], count[i]);
 		update_stats(&ps->res_stats[i], count[i]);
 
 
 	if (verbose) {
 	if (verbose) {
-		fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+		fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
 			event_name(counter), count[0], count[1], count[2]);
 			event_name(counter), count[0], count[1], count[2]);
 	}
 	}
 
 
@@ -519,9 +521,9 @@ static void print_noise_pct(double total, double avg)
 		pct = 100.0*total/avg;
 		pct = 100.0*total/avg;
 
 
 	if (csv_output)
 	if (csv_output)
-		fprintf(stderr, "%s%.2f%%", csv_sep, pct);
+		fprintf(output, "%s%.2f%%", csv_sep, pct);
 	else
 	else
-		fprintf(stderr, "  ( +-%6.2f%% )", pct);
+		fprintf(output, "  ( +-%6.2f%% )", pct);
 }
 }
 
 
 static void print_noise(struct perf_evsel *evsel, double avg)
 static void print_noise(struct perf_evsel *evsel, double avg)
@@ -546,16 +548,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
 			csv_output ? 0 : -4,
 			csv_output ? 0 : -4,
 			evsel_list->cpus->map[cpu], csv_sep);
 			evsel_list->cpus->map[cpu], csv_sep);
 
 
-	fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
+	fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
 
 
 	if (evsel->cgrp)
 	if (evsel->cgrp)
-		fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
+		fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
 
 
 	if (csv_output)
 	if (csv_output)
 		return;
 		return;
 
 
 	if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
 	if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
-		fprintf(stderr, " # %8.3f CPUs utilized          ", avg / avg_stats(&walltime_nsecs_stats));
+		fprintf(output, " # %8.3f CPUs utilized          ",
+			avg / avg_stats(&walltime_nsecs_stats));
 }
 }
 
 
 static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -576,9 +579,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
 	else if (ratio > 10.0)
 	else if (ratio > 10.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " frontend cycles idle   ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " frontend cycles idle   ");
 }
 }
 
 
 static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -599,9 +602,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
 	else if (ratio > 20.0)
 	else if (ratio > 20.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " backend  cycles idle   ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " backend  cycles idle   ");
 }
 }
 
 
 static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -622,9 +625,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all branches        ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all branches        ");
 }
 }
 
 
 static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -645,9 +648,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all L1-dcache hits  ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all L1-dcache hits  ");
 }
 }
 
 
 static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -668,9 +671,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all L1-icache hits  ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all L1-icache hits  ");
 }
 }
 
 
 static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -691,9 +694,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all dTLB cache hits ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all dTLB cache hits ");
 }
 }
 
 
 static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -714,9 +717,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all iTLB cache hits ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all iTLB cache hits ");
 }
 }
 
 
 static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
 static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -737,9 +740,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
 	else if (ratio > 5.0)
 	else if (ratio > 5.0)
 		color = PERF_COLOR_YELLOW;
 		color = PERF_COLOR_YELLOW;
 
 
-	fprintf(stderr, " #  ");
-	color_fprintf(stderr, color, "%6.2f%%", ratio);
-	fprintf(stderr, " of all LL-cache hits   ");
+	fprintf(output, " #  ");
+	color_fprintf(output, color, "%6.2f%%", ratio);
+	fprintf(output, " of all LL-cache hits   ");
 }
 }
 
 
 static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -762,10 +765,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 	else
 	else
 		cpu = 0;
 		cpu = 0;
 
 
-	fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
+	fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
 
 
 	if (evsel->cgrp)
 	if (evsel->cgrp)
-		fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
+		fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
 
 
 	if (csv_output)
 	if (csv_output)
 		return;
 		return;
@@ -776,14 +779,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 		if (total)
 		if (total)
 			ratio = avg / total;
 			ratio = avg / total;
 
 
-		fprintf(stderr, " #   %5.2f  insns per cycle        ", ratio);
+		fprintf(output, " #   %5.2f  insns per cycle        ", ratio);
 
 
 		total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
 		total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
 		total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
 		total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
 
 
 		if (total && avg) {
 		if (total && avg) {
 			ratio = total / avg;
 			ratio = total / avg;
-			fprintf(stderr, "\n                                             #   %5.2f  stalled cycles per insn", ratio);
+			fprintf(output, "\n                                             #   %5.2f  stalled cycles per insn", ratio);
 		}
 		}
 
 
 	} else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
 	} else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -831,7 +834,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 		if (total)
 		if (total)
 			ratio = avg * 100 / total;
 			ratio = avg * 100 / total;
 
 
-		fprintf(stderr, " # %8.3f %% of all cache refs    ", ratio);
+		fprintf(output, " # %8.3f %% of all cache refs    ", ratio);
 
 
 	} else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
 	} else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
 		print_stalled_cycles_frontend(cpu, evsel, avg);
 		print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -843,16 +846,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 		if (total)
 		if (total)
 			ratio = 1.0 * avg / total;
 			ratio = 1.0 * avg / total;
 
 
-		fprintf(stderr, " # %8.3f GHz                    ", ratio);
+		fprintf(output, " # %8.3f GHz                    ", ratio);
 	} else if (runtime_nsecs_stats[cpu].n != 0) {
 	} else if (runtime_nsecs_stats[cpu].n != 0) {
 		total = avg_stats(&runtime_nsecs_stats[cpu]);
 		total = avg_stats(&runtime_nsecs_stats[cpu]);
 
 
 		if (total)
 		if (total)
 			ratio = 1000.0 * avg / total;
 			ratio = 1000.0 * avg / total;
 
 
-		fprintf(stderr, " # %8.3f M/sec                  ", ratio);
+		fprintf(output, " # %8.3f M/sec                  ", ratio);
 	} else {
 	} else {
-		fprintf(stderr, "                                   ");
+		fprintf(output, "                                   ");
 	}
 	}
 }
 }
 
 
@@ -867,7 +870,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
 	int scaled = counter->counts->scaled;
 	int scaled = counter->counts->scaled;
 
 
 	if (scaled == -1) {
 	if (scaled == -1) {
-		fprintf(stderr, "%*s%s%*s",
+		fprintf(output, "%*s%s%*s",
 			csv_output ? 0 : 18,
 			csv_output ? 0 : 18,
 			counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 			counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 			csv_sep,
 			csv_sep,
@@ -875,9 +878,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
 			event_name(counter));
 			event_name(counter));
 
 
 		if (counter->cgrp)
 		if (counter->cgrp)
-			fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
+			fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
 
 
-		fputc('\n', stderr);
+		fputc('\n', output);
 		return;
 		return;
 	}
 	}
 
 
@@ -889,7 +892,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
 	print_noise(counter, avg);
 	print_noise(counter, avg);
 
 
 	if (csv_output) {
 	if (csv_output) {
-		fputc('\n', stderr);
+		fputc('\n', output);
 		return;
 		return;
 	}
 	}
 
 
@@ -899,9 +902,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
 		avg_enabled = avg_stats(&ps->res_stats[1]);
 		avg_enabled = avg_stats(&ps->res_stats[1]);
 		avg_running = avg_stats(&ps->res_stats[2]);
 		avg_running = avg_stats(&ps->res_stats[2]);
 
 
-		fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled);
+		fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled);
 	}
 	}
-	fprintf(stderr, "\n");
+	fprintf(output, "\n");
 }
 }
 
 
 /*
 /*
@@ -918,7 +921,7 @@ static void print_counter(struct perf_evsel *counter)
 		ena = counter->counts->cpu[cpu].ena;
 		ena = counter->counts->cpu[cpu].ena;
 		run = counter->counts->cpu[cpu].run;
 		run = counter->counts->cpu[cpu].run;
 		if (run == 0 || ena == 0) {
 		if (run == 0 || ena == 0) {
-			fprintf(stderr, "CPU%*d%s%*s%s%*s",
+			fprintf(output, "CPU%*d%s%*s%s%*s",
 				csv_output ? 0 : -4,
 				csv_output ? 0 : -4,
 				evsel_list->cpus->map[cpu], csv_sep,
 				evsel_list->cpus->map[cpu], csv_sep,
 				csv_output ? 0 : 18,
 				csv_output ? 0 : 18,
@@ -928,9 +931,10 @@ static void print_counter(struct perf_evsel *counter)
 				event_name(counter));
 				event_name(counter));
 
 
 			if (counter->cgrp)
 			if (counter->cgrp)
-				fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
+				fprintf(output, "%s%s",
+					csv_sep, counter->cgrp->name);
 
 
-			fputc('\n', stderr);
+			fputc('\n', output);
 			continue;
 			continue;
 		}
 		}
 
 
@@ -943,9 +947,10 @@ static void print_counter(struct perf_evsel *counter)
 			print_noise(counter, 1.0);
 			print_noise(counter, 1.0);
 
 
 			if (run != ena)
 			if (run != ena)
-				fprintf(stderr, "  (%.2f%%)", 100.0 * run / ena);
+				fprintf(output, "  (%.2f%%)",
+					100.0 * run / ena);
 		}
 		}
-		fputc('\n', stderr);
+		fputc('\n', output);
 	}
 	}
 }
 }
 
 
@@ -957,21 +962,21 @@ static void print_stat(int argc, const char **argv)
 	fflush(stdout);
 	fflush(stdout);
 
 
 	if (!csv_output) {
 	if (!csv_output) {
-		fprintf(stderr, "\n");
-		fprintf(stderr, " Performance counter stats for ");
+		fprintf(output, "\n");
+		fprintf(output, " Performance counter stats for ");
 		if(target_pid == -1 && target_tid == -1) {
 		if(target_pid == -1 && target_tid == -1) {
-			fprintf(stderr, "\'%s", argv[0]);
+			fprintf(output, "\'%s", argv[0]);
 			for (i = 1; i < argc; i++)
 			for (i = 1; i < argc; i++)
-				fprintf(stderr, " %s", argv[i]);
+				fprintf(output, " %s", argv[i]);
 		} else if (target_pid != -1)
 		} else if (target_pid != -1)
-			fprintf(stderr, "process id \'%d", target_pid);
+			fprintf(output, "process id \'%d", target_pid);
 		else
 		else
-			fprintf(stderr, "thread id \'%d", target_tid);
+			fprintf(output, "thread id \'%d", target_tid);
 
 
-		fprintf(stderr, "\'");
+		fprintf(output, "\'");
 		if (run_count > 1)
 		if (run_count > 1)
-			fprintf(stderr, " (%d runs)", run_count);
-		fprintf(stderr, ":\n\n");
+			fprintf(output, " (%d runs)", run_count);
+		fprintf(output, ":\n\n");
 	}
 	}
 
 
 	if (no_aggr) {
 	if (no_aggr) {
@@ -984,15 +989,15 @@ static void print_stat(int argc, const char **argv)
 
 
 	if (!csv_output) {
 	if (!csv_output) {
 		if (!null_run)
 		if (!null_run)
-			fprintf(stderr, "\n");
-		fprintf(stderr, " %17.9f seconds time elapsed",
+			fprintf(output, "\n");
+		fprintf(output, " %17.9f seconds time elapsed",
 				avg_stats(&walltime_nsecs_stats)/1e9);
 				avg_stats(&walltime_nsecs_stats)/1e9);
 		if (run_count > 1) {
 		if (run_count > 1) {
-			fprintf(stderr, "                                        ");
+			fprintf(output, "                                        ");
 			print_noise_pct(stddev_stats(&walltime_nsecs_stats),
 			print_noise_pct(stddev_stats(&walltime_nsecs_stats),
 					avg_stats(&walltime_nsecs_stats));
 					avg_stats(&walltime_nsecs_stats));
 		}
 		}
-		fprintf(stderr, "\n\n");
+		fprintf(output, "\n\n");
 	}
 	}
 }
 }
 
 
@@ -1030,6 +1035,8 @@ static int stat__set_big_num(const struct option *opt __used,
 	return 0;
 	return 0;
 }
 }
 
 
+static bool append_file;
+
 static const struct option options[] = {
 static const struct option options[] = {
 	OPT_CALLBACK('e', "event", &evsel_list, "event",
 	OPT_CALLBACK('e', "event", &evsel_list, "event",
 		     "event selector. use 'perf list' to list available events",
 		     "event selector. use 'perf list' to list available events",
@@ -1070,6 +1077,9 @@ static const struct option options[] = {
 	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
 	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
 		     "monitor event in cgroup name only",
 		     "monitor event in cgroup name only",
 		     parse_cgroups),
 		     parse_cgroups),
+	OPT_STRING('o', "output", &output_name, "file",
+		    "output file name"),
+	OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
 	OPT_END()
 	OPT_END()
 };
 };
 
 
@@ -1141,6 +1151,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 {
 {
 	struct perf_evsel *pos;
 	struct perf_evsel *pos;
 	int status = -ENOMEM;
 	int status = -ENOMEM;
+	const char *mode;
 
 
 	setlocale(LC_ALL, "");
 	setlocale(LC_ALL, "");
 
 
@@ -1151,6 +1162,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 	argc = parse_options(argc, argv, options, stat_usage,
 	argc = parse_options(argc, argv, options, stat_usage,
 		PARSE_OPT_STOP_AT_NON_OPTION);
 		PARSE_OPT_STOP_AT_NON_OPTION);
 
 
+	output = stderr;
+	if (output_name && strcmp(output_name, "-"))
+		output = NULL;
+
+	if (!output) {
+		struct timespec tm;
+		mode = append_file ? "a" : "w";
+
+		output = fopen(output_name, mode);
+		if (!output) {
+			perror("failed to create output file");
+			exit(-1);
+		}
+		clock_gettime(CLOCK_REALTIME, &tm);
+		fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
+	}
+
 	if (csv_sep)
 	if (csv_sep)
 		csv_output = true;
 		csv_output = true;
 	else
 	else
@@ -1226,7 +1254,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 	status = 0;
 	status = 0;
 	for (run_idx = 0; run_idx < run_count; run_idx++) {
 	for (run_idx = 0; run_idx < run_count; run_idx++) {
 		if (run_count != 1 && verbose)
 		if (run_count != 1 && verbose)
-			fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
+			fprintf(output, "[ perf stat: executing run #%d ... ]\n",
+				run_idx + 1);
 
 
 		if (sync_run)
 		if (sync_run)
 			sync();
 			sync();

+ 4 - 1
tools/perf/util/annotate.c

@@ -324,9 +324,12 @@ fallback:
 
 
 	snprintf(command, sizeof(command),
 	snprintf(command, sizeof(command),
 		 "objdump --start-address=0x%016" PRIx64
 		 "objdump --start-address=0x%016" PRIx64
-		 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
+		 " --stop-address=0x%016" PRIx64
+		 " -d %s %s -C %s|grep -v %s|expand",
 		 map__rip_2objdump(map, sym->start),
 		 map__rip_2objdump(map, sym->start),
 		 map__rip_2objdump(map, sym->end),
 		 map__rip_2objdump(map, sym->end),
+		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
+		 symbol_conf.annotate_src ? "-S" : "",
 		 symfs_filename, filename);
 		 symfs_filename, filename);
 
 
 	pr_debug("Executing: %s\n", command);
 	pr_debug("Executing: %s\n", command);

+ 1 - 1
tools/perf/util/color.c

@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
 	 * Auto-detect:
 	 * Auto-detect:
 	 */
 	 */
 	if (perf_use_color_default < 0) {
 	if (perf_use_color_default < 0) {
-		if (isatty(1) || pager_in_use())
+		if (isatty(fileno(fp)) || pager_in_use())
 			perf_use_color_default = 1;
 			perf_use_color_default = 1;
 		else
 		else
 			perf_use_color_default = 0;
 			perf_use_color_default = 0;

+ 2 - 0
tools/perf/util/symbol.c

@@ -46,6 +46,8 @@ struct symbol_conf symbol_conf = {
 	.exclude_other	  = true,
 	.exclude_other	  = true,
 	.use_modules	  = true,
 	.use_modules	  = true,
 	.try_vmlinux_path = true,
 	.try_vmlinux_path = true,
+	.annotate_asm_raw = true,
+	.annotate_src	  = true,
 	.symfs            = "",
 	.symfs            = "",
 };
 };
 
 

+ 3 - 1
tools/perf/util/symbol.h

@@ -76,7 +76,9 @@ struct symbol_conf {
 			exclude_other,
 			exclude_other,
 			show_cpu_utilization,
 			show_cpu_utilization,
 			initialized,
 			initialized,
-			kptr_restrict;
+			kptr_restrict,
+			annotate_asm_raw,
+			annotate_src;
 	const char	*vmlinux_name,
 	const char	*vmlinux_name,
 			*kallsyms_name,
 			*kallsyms_name,
 			*source_prefix,
 			*source_prefix,