diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/Documentation/perf-stat.txt | 3 | ||||
| -rw-r--r-- | tools/perf/builtin-c2c.c | 10 | ||||
| -rw-r--r-- | tools/perf/builtin-script.c | 12 | ||||
| -rw-r--r-- | tools/perf/builtin-stat.c | 48 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/hists.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 12 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.y | 5 | ||||
| -rw-r--r-- | tools/perf/util/sort.h | 4 | 
9 files changed, 67 insertions, 33 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 5dfe102fb5b5..b10a90b6a718 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -178,6 +178,9 @@ Print count deltas for fixed number of times.  This option should be used together with "-I" option.  	example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' +--interval-clear:: +Clear the screen before next interval. +  --timeout msecs::  Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).  This option is not supported with the "-I" option. diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 307b3594525f..6a8738f7ead3 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -56,16 +56,16 @@ struct c2c_hist_entry {  	struct compute_stats	 cstats; +	unsigned long		 paddr; +	unsigned long		 paddr_cnt; +	bool			 paddr_zero; +	char			*nodestr; +  	/*  	 * must be at the end,  	 * because of its callchain dynamic entry  	 */  	struct hist_entry	he; - -	unsigned long		 paddr; -	unsigned long		 paddr_cnt; -	bool			 paddr_zero; -	char			*nodestr;  };  static char const *coalesce_default = "pid,iaddr"; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b3bf35512d21..a31d7082188e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -180,6 +180,18 @@ static struct {  				  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] = {  		.user_set = false, diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 096ccb25c11f..22547a490e1f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -65,6 +65,7 @@  #include "util/tool.h"  #include "util/string2.h"  #include "util/metricgroup.h" +#include "util/top.h"  #include "asm/bug.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); +#define METRIC_ONLY_LEN 20 +  static int			run_count			=  1;  static bool			no_inherit			= false;  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 bool			append_file;  static bool			interval_count; +static bool			interval_clear;  static const char		*output_name;  static int			output_fd;  static int			print_free_counters_hint; @@ -180,6 +184,7 @@ static int			print_mixed_hw_group_error;  static u64			*walltime_run;  static bool			ru_display			= false;  static struct rusage		ru_data; +static unsigned int		metric_only_len			= METRIC_ONLY_LEN;  struct perf_stat {  	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);  } -#define METRIC_ONLY_LEN 20 -  /* Filter out some columns that don't work well in metrics only mode */  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;  	FILE *out = os->fh; -	int n; -	char buf[1024]; -	unsigned mlen = METRIC_ONLY_LEN; +	char buf[1024], str[1024]; +	unsigned mlen = metric_only_len;  	if (!valid_only_metric(unit))  		return;  	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))  		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, @@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,  	if (csv_output)  		fprintf(os->fh, "%s%s", unit, csv_sep);  	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) @@ -1704,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts)  	FILE *output = stat_config.output;  	static int num_print_interval; +	if (interval_clear) +		puts(CONSOLE_CLEAR); +  	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) {  		case AGGR_SOCKET:  			fprintf(output, "#           time socket cpus"); @@ -1719,7 +1723,7 @@ static void print_interval(char *prefix, struct timespec *ts)  				fprintf(output, "             counts %*s events\n", unit_width, "unit");  			break;  		case AGGR_NONE: -			fprintf(output, "#           time CPU"); +			fprintf(output, "#           time CPU    ");  			if (!metric_only)  				fprintf(output, "                counts %*s events\n", unit_width, "unit");  			break; @@ -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);  	if (++num_print_interval == 25)  		num_print_interval = 0; @@ -2057,6 +2061,8 @@ static const struct option stat_options[] = {  		    "(overhead is possible for values <= 100ms)"),  	OPT_INTEGER(0, "interval-count", &stat_config.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,  		    "stop workload and print counts after a timeout period in ms (>= 10ms)"),  	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_RESULT_MISS	<< 16)				},  }; +	struct parse_events_error errinfo;  	/* Set attrs if no event is selected and !null_run: */  	if (null_run)  		return 0;  	if (transaction_run) { -		struct parse_events_error errinfo; -  		if (pmu_have_event("cpu", "cycles-ct") &&  		    pmu_have_event("cpu", "el-start"))  			err = parse_events(evsel_list, transaction_attrs, @@ -2454,6 +2459,7 @@ static int add_default_attributes(void)  					   &errinfo);  		if (err) {  			fprintf(stderr, "Cannot set up transaction events\n"); +			parse_events_print_error(&errinfo, transaction_attrs);  			return -1;  		}  		return 0; @@ -2479,10 +2485,11 @@ static int add_default_attributes(void)  		    pmu_have_event("msr", "smi")) {  			if (!force_metric_only)  				metric_only = true; -			err = parse_events(evsel_list, smi_cost_attrs, NULL); +			err = parse_events(evsel_list, smi_cost_attrs, &errinfo);  		} else {  			fprintf(stderr, "To measure SMI cost, it needs "  				"msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); +			parse_events_print_error(&errinfo, smi_cost_attrs);  			return -1;  		}  		if (err) { @@ -2517,12 +2524,13 @@ static int add_default_attributes(void)  		if (topdown_attrs[0] && str) {  			if (warn)  				arch_topdown_group_warn(); -			err = parse_events(evsel_list, str, NULL); +			err = parse_events(evsel_list, str, &errinfo);  			if (err) {  				fprintf(stderr,  					"Cannot set up top down events %s: %d\n",  					str, err);  				free(str); +				parse_events_print_error(&errinfo, str);  				return -1;  			}  		} else { diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index b085f1b3e34d..4ab663ec3e5e 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -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);  		} -		if (hists__has_callchains(hists) && +		if (hist_entry__has_callchains(h) &&  		    symbol_conf.use_callchain && hists__has(hists, sym)) {  			if (callchain_param.mode == CHAIN_GRAPH_REL)  				total = symbol_conf.cumulate_callchain ? diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 52e8fda93a47..828cb9794c76 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -370,9 +370,11 @@ void hists__delete_entries(struct hists *hists)  static int hist_entry__init(struct hist_entry *he,  			    struct hist_entry *template, -			    bool sample_self) +			    bool sample_self, +			    size_t callchain_size)  {  	*he = *template; +	he->callchain_size = callchain_size;  	if (symbol_conf.cumulate_callchain) {  		he->stat_acc = malloc(sizeof(he->stat)); @@ -473,7 +475,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,  	he = ops->new(callchain_size);  	if (he) { -		err = hist_entry__init(he, template, sample_self); +		err = hist_entry__init(he, template, sample_self, callchain_size);  		if (err) {  			ops->free(he);  			he = NULL; @@ -619,9 +621,11 @@ __hists__add_entry(struct hists *hists,  		.raw_data = sample->raw_data,  		.raw_size = sample->raw_size,  		.ops = ops, -	}; +	}, *he = hists__findnew_entry(hists, &entry, al, sample_self); -	return hists__findnew_entry(hists, &entry, al, sample_self); +	if (!hists->has_callchains && he && he->callchain_size != 0) +		hists->has_callchains = true; +	return he;  }  struct hist_entry *hists__add_entry(struct hists *hists, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 06607c434949..73049f7f0f60 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -85,6 +85,7 @@ struct hists {  	struct events_stats	stats;  	u64			event_stream;  	u16			col_len[HISTC_NR_COLS]; +	bool			has_callchains;  	int			socket_filter;  	struct perf_hpp_list	*hpp_list;  	struct list_head	hpp_formats; @@ -222,8 +223,7 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)  static __pure inline bool hists__has_callchains(struct hists *hists)  { -	const struct perf_evsel *evsel = hists_to_evsel(hists); -	return evsel__has_callchain(evsel); +	return hists->has_callchains;  }  int hists__init(void); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 155d2570274f..da8fe57691b8 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -227,11 +227,16 @@ event_def: event_pmu |  event_pmu:  PE_NAME opt_pmu_config  { +	struct parse_events_state *parse_state = _parse_state; +	struct parse_events_error *error = parse_state->error;  	struct list_head *list, *orig_terms, *terms;  	if (parse_events_copy_term_list($2, &orig_terms))  		YYABORT; +	if (error) +		error->idx = @1.first_column; +  	ALLOC_LIST(list);  	if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {  		struct perf_pmu *pmu = NULL; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7cf2d5cc038e..8bf302cafcec 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -112,6 +112,8 @@ struct hist_entry {  	char			level;  	u8			filtered; + +	u16			callchain_size;  	union {  		/*  		 * Since perf diff only supports the stdio output, TUI @@ -153,7 +155,7 @@ struct hist_entry {  static __pure inline bool hist_entry__has_callchains(struct hist_entry *he)  { -	return hists__has_callchains(he->hists); +	return he->callchain_size != 0;  }  static inline bool hist_entry__has_pairs(struct hist_entry *he)  | 
