Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a89d0c2a authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'perf-urgent-for-mingo-4.18-20180611' of...

Merge tag 'perf-urgent-for-mingo-4.18-20180611' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/urgent

Pull perf/urgent fixes and improvements from Arnaldo Carvalho de Melo:

perf stat:

- Fix metric column header display alignment (Jiri Olsa)

- Improve error messages for default attributes, providing better output
  for error in command lines such as:

  $ perf stat -T
  Cannot set up transaction events
  event syntax error: '..cycles,cpu/cycles-t/,cpu/tx-start/,cpu/el-start/,cpu/cycles-ct/}'
                                    \___ unknown term

  Where the "event syntax error" line now appears (Jiri Olsa)

- Add --interval-clear option, to provide a 'watch' like printing (Jiri Olsa)

perf script:

- Show hw-cache events too (Seeteena Thoufeek)

perf c2c:

- Fix data dependency problem in layout of 'struct c2c_hist_entry', where
  its member 'struct hist_entry' must be at the end because it has a ZLA
  as its last member, that gets space when handling callchains (Jiri Olsa)

Core:

- We cannot assume that a 'struct perf_evsel'  is to be obtained from a
  container_of operation on a 'struct hists' as there are tools, such as
  'perf c2c' that uses 'struct hist' instances without having them in
  container structs that also have 'struct perf_evsel' in a particular
  layout, so provide a different way of figuring out if a 'struct hists'
  and 'struct hist_entry' have callchains (Arnaldo Carvalho de Melo)

- Fix error index in the PMU event parser, so that error messages can
  point to the problematic token (Jiri Olsa)

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parents d82991a8 fad76d43
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -178,6 +178,9 @@ Print count deltas for fixed number of times.
This option should be used together with "-I" option.
This option should be used together with "-I" option.
	example: 'perf stat -I 1000 --interval-count 2 -e cycles -a'
	example: 'perf stat -I 1000 --interval-count 2 -e cycles -a'


--interval-clear::
Clear the screen before next interval.

--timeout msecs::
--timeout msecs::
Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).
Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).
This option is not supported with the "-I" option.
This option is not supported with the "-I" option.
+5 −5
Original line number Original line Diff line number Diff line
@@ -56,16 +56,16 @@ struct c2c_hist_entry {


	struct compute_stats	 cstats;
	struct compute_stats	 cstats;


	unsigned long		 paddr;
	unsigned long		 paddr_cnt;
	bool			 paddr_zero;
	char			*nodestr;

	/*
	/*
	 * must be at the end,
	 * must be at the end,
	 * because of its callchain dynamic entry
	 * because of its callchain dynamic entry
	 */
	 */
	struct hist_entry	he;
	struct hist_entry	he;

	unsigned long		 paddr;
	unsigned long		 paddr_cnt;
	bool			 paddr_zero;
	char			*nodestr;
};
};


static char const *coalesce_default = "pid,iaddr";
static char const *coalesce_default = "pid,iaddr";
+12 −0
Original line number Original line Diff line number Diff line
@@ -180,6 +180,18 @@ static struct {
				  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
				  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
	},
	},


	[PERF_TYPE_HW_CACHE] = {
		.user_set = false,

		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
			      PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
			      PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,

		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
	},

	[PERF_TYPE_RAW] = {
	[PERF_TYPE_RAW] = {
		.user_set = false,
		.user_set = false,


+28 −20
Original line number Original line Diff line number Diff line
@@ -65,6 +65,7 @@
#include "util/tool.h"
#include "util/tool.h"
#include "util/string2.h"
#include "util/string2.h"
#include "util/metricgroup.h"
#include "util/metricgroup.h"
#include "util/top.h"
#include "asm/bug.h"
#include "asm/bug.h"


#include <linux/time64.h>
#include <linux/time64.h>
@@ -144,6 +145,8 @@ static struct target target = {


typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);


#define METRIC_ONLY_LEN 20

static int			run_count			=  1;
static int			run_count			=  1;
static bool			no_inherit			= false;
static bool			no_inherit			= false;
static volatile pid_t		child_pid			= -1;
static volatile pid_t		child_pid			= -1;
@@ -173,6 +176,7 @@ static struct cpu_map *aggr_map;
static aggr_get_id_t		aggr_get_id;
static aggr_get_id_t		aggr_get_id;
static bool			append_file;
static bool			append_file;
static bool			interval_count;
static bool			interval_count;
static bool			interval_clear;
static const char		*output_name;
static const char		*output_name;
static int			output_fd;
static int			output_fd;
static int			print_free_counters_hint;
static int			print_free_counters_hint;
@@ -180,6 +184,7 @@ static int print_mixed_hw_group_error;
static u64			*walltime_run;
static u64			*walltime_run;
static bool			ru_display			= false;
static bool			ru_display			= false;
static struct rusage		ru_data;
static struct rusage		ru_data;
static unsigned int		metric_only_len			= METRIC_ONLY_LEN;


struct perf_stat {
struct perf_stat {
	bool			 record;
	bool			 record;
@@ -967,8 +972,6 @@ static void print_metric_csv(void *ctx,
	fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
	fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
}
}


#define METRIC_ONLY_LEN 20

/* Filter out some columns that don't work well in metrics only mode */
/* Filter out some columns that don't work well in metrics only mode */


static bool valid_only_metric(const char *unit)
static bool valid_only_metric(const char *unit)
@@ -999,22 +1002,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt,
{
{
	struct outstate *os = ctx;
	struct outstate *os = ctx;
	FILE *out = os->fh;
	FILE *out = os->fh;
	int n;
	char buf[1024], str[1024];
	char buf[1024];
	unsigned mlen = metric_only_len;
	unsigned mlen = METRIC_ONLY_LEN;


	if (!valid_only_metric(unit))
	if (!valid_only_metric(unit))
		return;
		return;
	unit = fixunit(buf, os->evsel, unit);
	unit = fixunit(buf, os->evsel, unit);
	if (color)
		n = color_fprintf(out, color, fmt, val);
	else
		n = fprintf(out, fmt, val);
	if (n > METRIC_ONLY_LEN)
		n = METRIC_ONLY_LEN;
	if (mlen < strlen(unit))
	if (mlen < strlen(unit))
		mlen = strlen(unit) + 1;
		mlen = strlen(unit) + 1;
	fprintf(out, "%*s", mlen - n, "");

	if (color)
		mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;

	color_snprintf(str, sizeof(str), color ?: "", fmt, val);
	fprintf(out, "%*s ", mlen, str);
}
}


static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
@@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,
	if (csv_output)
	if (csv_output)
		fprintf(os->fh, "%s%s", unit, csv_sep);
		fprintf(os->fh, "%s%s", unit, csv_sep);
	else
	else
		fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
		fprintf(os->fh, "%*s ", metric_only_len, unit);
}
}


static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
@@ -1704,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts)
	FILE *output = stat_config.output;
	FILE *output = stat_config.output;
	static int num_print_interval;
	static int num_print_interval;


	if (interval_clear)
		puts(CONSOLE_CLEAR);

	sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
	sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);


	if (num_print_interval == 0 && !csv_output) {
	if ((num_print_interval == 0 && !csv_output) || interval_clear) {
		switch (stat_config.aggr_mode) {
		switch (stat_config.aggr_mode) {
		case AGGR_SOCKET:
		case AGGR_SOCKET:
			fprintf(output, "#           time socket cpus");
			fprintf(output, "#           time socket cpus");
@@ -1738,7 +1742,7 @@ static void print_interval(char *prefix, struct timespec *ts)
		}
		}
	}
	}


	if (num_print_interval == 0 && metric_only)
	if ((num_print_interval == 0 && metric_only) || interval_clear)
		print_metric_headers(" ", true);
		print_metric_headers(" ", true);
	if (++num_print_interval == 25)
	if (++num_print_interval == 25)
		num_print_interval = 0;
		num_print_interval = 0;
@@ -2057,6 +2061,8 @@ static const struct option stat_options[] = {
		    "(overhead is possible for values <= 100ms)"),
		    "(overhead is possible for values <= 100ms)"),
	OPT_INTEGER(0, "interval-count", &stat_config.times,
	OPT_INTEGER(0, "interval-count", &stat_config.times,
		    "print counts for fixed number of times"),
		    "print counts for fixed number of times"),
	OPT_BOOLEAN(0, "interval-clear", &interval_clear,
		    "clear screen in between new interval"),
	OPT_UINTEGER(0, "timeout", &stat_config.timeout,
	OPT_UINTEGER(0, "timeout", &stat_config.timeout,
		    "stop workload and print counts after a timeout period in ms (>= 10ms)"),
		    "stop workload and print counts after a timeout period in ms (>= 10ms)"),
	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
@@ -2436,14 +2442,13 @@ static int add_default_attributes(void)
	(PERF_COUNT_HW_CACHE_OP_PREFETCH	<<  8) |
	(PERF_COUNT_HW_CACHE_OP_PREFETCH	<<  8) |
	(PERF_COUNT_HW_CACHE_RESULT_MISS	<< 16)				},
	(PERF_COUNT_HW_CACHE_RESULT_MISS	<< 16)				},
};
};
	struct parse_events_error errinfo;


	/* Set attrs if no event is selected and !null_run: */
	/* Set attrs if no event is selected and !null_run: */
	if (null_run)
	if (null_run)
		return 0;
		return 0;


	if (transaction_run) {
	if (transaction_run) {
		struct parse_events_error errinfo;

		if (pmu_have_event("cpu", "cycles-ct") &&
		if (pmu_have_event("cpu", "cycles-ct") &&
		    pmu_have_event("cpu", "el-start"))
		    pmu_have_event("cpu", "el-start"))
			err = parse_events(evsel_list, transaction_attrs,
			err = parse_events(evsel_list, transaction_attrs,
@@ -2454,6 +2459,7 @@ static int add_default_attributes(void)
					   &errinfo);
					   &errinfo);
		if (err) {
		if (err) {
			fprintf(stderr, "Cannot set up transaction events\n");
			fprintf(stderr, "Cannot set up transaction events\n");
			parse_events_print_error(&errinfo, transaction_attrs);
			return -1;
			return -1;
		}
		}
		return 0;
		return 0;
@@ -2479,10 +2485,11 @@ static int add_default_attributes(void)
		    pmu_have_event("msr", "smi")) {
		    pmu_have_event("msr", "smi")) {
			if (!force_metric_only)
			if (!force_metric_only)
				metric_only = true;
				metric_only = true;
			err = parse_events(evsel_list, smi_cost_attrs, NULL);
			err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
		} else {
		} else {
			fprintf(stderr, "To measure SMI cost, it needs "
			fprintf(stderr, "To measure SMI cost, it needs "
				"msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
				"msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
			parse_events_print_error(&errinfo, smi_cost_attrs);
			return -1;
			return -1;
		}
		}
		if (err) {
		if (err) {
@@ -2517,12 +2524,13 @@ static int add_default_attributes(void)
		if (topdown_attrs[0] && str) {
		if (topdown_attrs[0] && str) {
			if (warn)
			if (warn)
				arch_topdown_group_warn();
				arch_topdown_group_warn();
			err = parse_events(evsel_list, str, NULL);
			err = parse_events(evsel_list, str, &errinfo);
			if (err) {
			if (err) {
				fprintf(stderr,
				fprintf(stderr,
					"Cannot set up top down events %s: %d\n",
					"Cannot set up top down events %s: %d\n",
					str, err);
					str, err);
				free(str);
				free(str);
				parse_events_print_error(&errinfo, str);
				return -1;
				return -1;
			}
			}
		} else {
		} else {
+1 −1
Original line number Original line Diff line number Diff line
@@ -382,7 +382,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
			gtk_tree_store_set(store, &iter, col_idx++, s, -1);
			gtk_tree_store_set(store, &iter, col_idx++, s, -1);
		}
		}


		if (hists__has_callchains(hists) &&
		if (hist_entry__has_callchains(h) &&
		    symbol_conf.use_callchain && hists__has(hists, sym)) {
		    symbol_conf.use_callchain && hists__has(hists, sym)) {
			if (callchain_param.mode == CHAIN_GRAPH_REL)
			if (callchain_param.mode == CHAIN_GRAPH_REL)
				total = symbol_conf.cumulate_callchain ?
				total = symbol_conf.cumulate_callchain ?
Loading