diff options
Diffstat (limited to 'tools/perf/util/evsel.c')
| -rw-r--r-- | tools/perf/util/evsel.c | 423 | 
1 files changed, 279 insertions, 144 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ac0127be0459..76605fde3507 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -46,8 +46,13 @@  #include "string2.h"  #include "memswap.h"  #include "util.h" -#include "hashmap.h" +#ifdef HAVE_LIBBPF_SUPPORT +#include <bpf/hashmap.h> +#else +#include "util/hashmap.h" +#endif  #include "pmu-hybrid.h" +#include "off_cpu.h"  #include "../perf-sys.h"  #include "util/parse-branch-options.h"  #include <internal/xyarray.h> @@ -59,6 +64,33 @@ struct perf_missing_features perf_missing_features;  static clockid_t clockid; +static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = { +	NULL, +	"duration_time", +	"user_time", +	"system_time", +}; + +const char *perf_tool_event__to_str(enum perf_tool_event ev) +{ +	if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) +		return perf_tool_event__tool_names[ev]; + +	return NULL; +} + +enum perf_tool_event perf_tool_event__from_str(const char *str) +{ +	int i; + +	perf_tool_event__for_each_event(i) { +		if (!strcmp(str, perf_tool_event__tool_names[i])) +			return i; +	} +	return PERF_TOOL_NONE; +} + +  static int evsel__no_extra_init(struct evsel *evsel __maybe_unused)  {  	return 0; @@ -269,8 +301,8 @@ struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)  		return NULL;  	evsel__init(evsel, attr, idx); -	if (evsel__is_bpf_output(evsel)) { -		evsel->core.attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | +	if (evsel__is_bpf_output(evsel) && !attr->sample_type) { +		evsel->core.attr.sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |  					    PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),  		evsel->core.attr.sample_period = 1;  	} @@ -382,6 +414,7 @@ struct evsel *evsel__clone(struct evsel *orig)  	evsel->core.threads = perf_thread_map__get(orig->core.threads);  	evsel->core.nr_members = orig->core.nr_members;  	evsel->core.system_wide = orig->core.system_wide; +	evsel->core.requires_cpu = orig->core.requires_cpu;  	if (orig->name) {  		evsel->name = strdup(orig->name); @@ -486,7 +519,7 @@ out_err:  	return ERR_PTR(err);  } -const char *evsel__hw_names[PERF_COUNT_HW_MAX] = { +const char *const evsel__hw_names[PERF_COUNT_HW_MAX] = {  	"cycles",  	"instructions",  	"cache-references", @@ -565,13 +598,18 @@ static int evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size)  	return r;  } +int __weak arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) +{ +	return scnprintf(bf, size, "%s", __evsel__hw_name(evsel->core.attr.config)); +} +  static int evsel__hw_name(struct evsel *evsel, char *bf, size_t size)  { -	int r = scnprintf(bf, size, "%s", __evsel__hw_name(evsel->core.attr.config)); +	int r = arch_evsel__hw_name(evsel, bf, size);  	return r + evsel__add_modifiers(evsel, bf + r, size - r);  } -const char *evsel__sw_names[PERF_COUNT_SW_MAX] = { +const char *const evsel__sw_names[PERF_COUNT_SW_MAX] = {  	"cpu-clock",  	"task-clock",  	"page-faults", @@ -597,6 +635,11 @@ static int evsel__sw_name(struct evsel *evsel, char *bf, size_t size)  	return r + evsel__add_modifiers(evsel, bf + r, size - r);  } +static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size) +{ +	return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev)); +} +  static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)  {  	int r; @@ -622,7 +665,7 @@ static int evsel__bp_name(struct evsel *evsel, char *bf, size_t size)  	return r + evsel__add_modifiers(evsel, bf + r, size - r);  } -const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES] = { +const char *const evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES] = {   { "L1-dcache",	"l1-d",		"l1d",		"L1-data",		},   { "L1-icache",	"l1-i",		"l1i",		"L1-instruction",	},   { "LLC",	"L2",							}, @@ -632,13 +675,13 @@ const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES] = {   { "node",								},  }; -const char *evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][EVSEL__MAX_ALIASES] = { +const char *const evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][EVSEL__MAX_ALIASES] = {   { "load",	"loads",	"read",					},   { "store",	"stores",	"write",				},   { "prefetch",	"prefetches",	"speculative-read", "speculative-load",	},  }; -const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX][EVSEL__MAX_ALIASES] = { +const char *const evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX][EVSEL__MAX_ALIASES] = {   { "refs",	"Reference",	"ops",		"access",		},   { "misses",	"miss",							},  }; @@ -654,7 +697,7 @@ const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX][EVSEL__MAX_AL   * L1I : Read and prefetch only   * ITLB and BPU : Read-only   */ -static unsigned long evsel__hw_cache_stat[C(MAX)] = { +static const unsigned long evsel__hw_cache_stat[C(MAX)] = {   [C(L1D)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),   [C(L1I)]	= (CACHE_READ | CACHE_PREFETCH),   [C(LL)]	= (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), @@ -723,12 +766,6 @@ static int evsel__raw_name(struct evsel *evsel, char *bf, size_t size)  	return ret + evsel__add_modifiers(evsel, bf + ret, size - ret);  } -static int evsel__tool_name(char *bf, size_t size) -{ -	int ret = scnprintf(bf, size, "duration_time"); -	return ret; -} -  const char *evsel__name(struct evsel *evsel)  {  	char bf[128]; @@ -753,8 +790,8 @@ const char *evsel__name(struct evsel *evsel)  		break;  	case PERF_TYPE_SOFTWARE: -		if (evsel->tool_event) -			evsel__tool_name(bf, sizeof(bf)); +		if (evsel__is_tool(evsel)) +			evsel__tool_name(evsel->tool_event, bf, sizeof(bf));  		else  			evsel__sw_name(evsel, bf, sizeof(bf));  		break; @@ -786,8 +823,8 @@ const char *evsel__metric_id(const struct evsel *evsel)  	if (evsel->metric_id)  		return evsel->metric_id; -	if (evsel->core.attr.type == PERF_TYPE_SOFTWARE && evsel->tool_event) -		return "duration_time"; +	if (evsel__is_tool(evsel)) +		return perf_tool_event__to_str(evsel->tool_event);  	return "unknown";  } @@ -870,7 +907,7 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o  					   "specifying a subset with --user-regs may render DWARF unwinding unreliable, "  					   "so the minimal registers set (IP, SP) is explicitly forced.\n");  			} else { -				attr->sample_regs_user |= PERF_REGS_MASK; +				attr->sample_regs_user |= arch__user_reg_mask();  			}  			attr->sample_stack_user = param->dump_size;  			attr->exclude_callchain_user = 1; @@ -1064,6 +1101,27 @@ void __weak arch_evsel__fixup_new_cycles(struct perf_event_attr *attr __maybe_un  {  } +void __weak arch__post_evsel_config(struct evsel *evsel __maybe_unused, +				    struct perf_event_attr *attr __maybe_unused) +{ +} + +static void evsel__set_default_freq_period(struct record_opts *opts, +					   struct perf_event_attr *attr) +{ +	if (opts->freq) { +		attr->freq = 1; +		attr->sample_freq = opts->freq; +	} else { +		attr->sample_period = opts->default_interval; +	} +} + +static bool evsel__is_offcpu_event(struct evsel *evsel) +{ +	return evsel__is_bpf_output(evsel) && !strcmp(evsel->name, OFFCPU_EVENT); +} +  /*   * The enable_on_exec/disabled value strategy:   * @@ -1103,6 +1161,7 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,  	attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;  	attr->inherit	    = !opts->no_inherit;  	attr->write_backward = opts->overwrite ? 1 : 0; +	attr->read_format   = PERF_FORMAT_LOST;  	evsel__set_sample_bit(evsel, IP);  	evsel__set_sample_bit(evsel, TID); @@ -1130,14 +1189,12 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,  	 * We default some events to have a default interval. But keep  	 * it a weak assumption overridable by the user.  	 */ -	if (!attr->sample_period) { -		if (opts->freq) { -			attr->freq		= 1; -			attr->sample_freq	= opts->freq; -		} else { -			attr->sample_period = opts->default_interval; -		} -	} +	if ((evsel->is_libpfm_event && !attr->sample_period) || +	    (!evsel->is_libpfm_event && (!attr->sample_period || +					 opts->user_freq != UINT_MAX || +					 opts->user_interval != ULLONG_MAX))) +		evsel__set_default_freq_period(opts, attr); +  	/*  	 * If attr->freq was set (here or earlier), ask for period  	 * to be sampled. @@ -1330,6 +1387,11 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,  	 */  	if (evsel__is_dummy_event(evsel))  		evsel__reset_sample_bit(evsel, BRANCH_STACK); + +	if (evsel__is_offcpu_event(evsel)) +		evsel->core.attr.sample_type &= OFFCPU_SAMPLE_TYPES; + +	arch__post_evsel_config(evsel, attr);  }  int evsel__set_filter(struct evsel *evsel, const char *filter) @@ -1372,9 +1434,9 @@ int evsel__append_addr_filter(struct evsel *evsel, const char *filter)  }  /* Caller has to clear disabled after going through all CPUs. */ -int evsel__enable_cpu(struct evsel *evsel, int cpu) +int evsel__enable_cpu(struct evsel *evsel, int cpu_map_idx)  { -	return perf_evsel__enable_cpu(&evsel->core, cpu); +	return perf_evsel__enable_cpu(&evsel->core, cpu_map_idx);  }  int evsel__enable(struct evsel *evsel) @@ -1387,9 +1449,9 @@ int evsel__enable(struct evsel *evsel)  }  /* Caller has to set disabled after going through all CPUs. */ -int evsel__disable_cpu(struct evsel *evsel, int cpu) +int evsel__disable_cpu(struct evsel *evsel, int cpu_map_idx)  { -	return perf_evsel__disable_cpu(&evsel->core, cpu); +	return perf_evsel__disable_cpu(&evsel->core, cpu_map_idx);  }  int evsel__disable(struct evsel *evsel) @@ -1455,7 +1517,7 @@ void evsel__delete(struct evsel *evsel)  	free(evsel);  } -void evsel__compute_deltas(struct evsel *evsel, int cpu, int thread, +void evsel__compute_deltas(struct evsel *evsel, int cpu_map_idx, int thread,  			   struct perf_counts_values *count)  {  	struct perf_counts_values tmp; @@ -1463,12 +1525,12 @@ void evsel__compute_deltas(struct evsel *evsel, int cpu, int thread,  	if (!evsel->prev_raw_counts)  		return; -	if (cpu == -1) { +	if (cpu_map_idx == -1) {  		tmp = evsel->prev_raw_counts->aggr;  		evsel->prev_raw_counts->aggr = *count;  	} else { -		tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread); -		*perf_counts(evsel->prev_raw_counts, cpu, thread) = *count; +		tmp = *perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread); +		*perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread) = *count;  	}  	count->val = count->val - tmp.val; @@ -1476,50 +1538,33 @@ void evsel__compute_deltas(struct evsel *evsel, int cpu, int thread,  	count->run = count->run - tmp.run;  } -void perf_counts_values__scale(struct perf_counts_values *count, -			       bool scale, s8 *pscaled) -{ -	s8 scaled = 0; - -	if (scale) { -		if (count->run == 0) { -			scaled = -1; -			count->val = 0; -		} else if (count->run < count->ena) { -			scaled = 1; -			count->val = (u64)((double) count->val * count->ena / count->run); -		} -	} - -	if (pscaled) -		*pscaled = scaled; -} - -static int evsel__read_one(struct evsel *evsel, int cpu, int thread) +static int evsel__read_one(struct evsel *evsel, int cpu_map_idx, int thread)  { -	struct perf_counts_values *count = perf_counts(evsel->counts, cpu, thread); +	struct perf_counts_values *count = perf_counts(evsel->counts, cpu_map_idx, thread); -	return perf_evsel__read(&evsel->core, cpu, thread, count); +	return perf_evsel__read(&evsel->core, cpu_map_idx, thread, count);  } -static void evsel__set_count(struct evsel *counter, int cpu, int thread, u64 val, u64 ena, u64 run) +static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread, +			     u64 val, u64 ena, u64 run, u64 lost)  {  	struct perf_counts_values *count; -	count = perf_counts(counter->counts, cpu, thread); +	count = perf_counts(counter->counts, cpu_map_idx, thread);  	count->val    = val;  	count->ena    = ena;  	count->run    = run; +	count->lost   = lost; -	perf_counts__set_loaded(counter->counts, cpu, thread, true); +	perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true);  } -static int evsel__process_group_data(struct evsel *leader, int cpu, int thread, u64 *data) +static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int thread, u64 *data)  {  	u64 read_format = leader->core.attr.read_format;  	struct sample_read_value *v; -	u64 nr, ena = 0, run = 0, i; +	u64 nr, ena = 0, run = 0, lost = 0;  	nr = *data++; @@ -1532,24 +1577,24 @@ static int evsel__process_group_data(struct evsel *leader, int cpu, int thread,  	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)  		run = *data++; -	v = (struct sample_read_value *) data; - -	evsel__set_count(leader, cpu, thread, v[0].value, ena, run); - -	for (i = 1; i < nr; i++) { +	v = (void *)data; +	sample_read_group__for_each(v, nr, read_format) {  		struct evsel *counter; -		counter = evlist__id2evsel(leader->evlist, v[i].id); +		counter = evlist__id2evsel(leader->evlist, v->id);  		if (!counter)  			return -EINVAL; -		evsel__set_count(counter, cpu, thread, v[i].value, ena, run); +		if (read_format & PERF_FORMAT_LOST) +			lost = v->lost; + +		evsel__set_count(counter, cpu_map_idx, thread, v->value, ena, run, lost);  	}  	return 0;  } -static int evsel__read_group(struct evsel *leader, int cpu, int thread) +static int evsel__read_group(struct evsel *leader, int cpu_map_idx, int thread)  {  	struct perf_stat_evsel *ps = leader->stats;  	u64 read_format = leader->core.attr.read_format; @@ -1570,67 +1615,67 @@ static int evsel__read_group(struct evsel *leader, int cpu, int thread)  		ps->group_data = data;  	} -	if (FD(leader, cpu, thread) < 0) +	if (FD(leader, cpu_map_idx, thread) < 0)  		return -EINVAL; -	if (readn(FD(leader, cpu, thread), data, size) <= 0) +	if (readn(FD(leader, cpu_map_idx, thread), data, size) <= 0)  		return -errno; -	return evsel__process_group_data(leader, cpu, thread, data); +	return evsel__process_group_data(leader, cpu_map_idx, thread, data);  } -int evsel__read_counter(struct evsel *evsel, int cpu, int thread) +int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread)  {  	u64 read_format = evsel->core.attr.read_format;  	if (read_format & PERF_FORMAT_GROUP) -		return evsel__read_group(evsel, cpu, thread); +		return evsel__read_group(evsel, cpu_map_idx, thread); -	return evsel__read_one(evsel, cpu, thread); +	return evsel__read_one(evsel, cpu_map_idx, thread);  } -int __evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale) +int __evsel__read_on_cpu(struct evsel *evsel, int cpu_map_idx, int thread, bool scale)  {  	struct perf_counts_values count;  	size_t nv = scale ? 3 : 1; -	if (FD(evsel, cpu, thread) < 0) +	if (FD(evsel, cpu_map_idx, thread) < 0)  		return -EINVAL; -	if (evsel->counts == NULL && evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0) +	if (evsel->counts == NULL && evsel__alloc_counts(evsel) < 0)  		return -ENOMEM; -	if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) <= 0) +	if (readn(FD(evsel, cpu_map_idx, thread), &count, nv * sizeof(u64)) <= 0)  		return -errno; -	evsel__compute_deltas(evsel, cpu, thread, &count); +	evsel__compute_deltas(evsel, cpu_map_idx, thread, &count);  	perf_counts_values__scale(&count, scale, NULL); -	*perf_counts(evsel->counts, cpu, thread) = count; +	*perf_counts(evsel->counts, cpu_map_idx, thread) = count;  	return 0;  }  static int evsel__match_other_cpu(struct evsel *evsel, struct evsel *other, -				  int cpu) +				  int cpu_map_idx)  { -	int cpuid; +	struct perf_cpu cpu; -	cpuid = perf_cpu_map__cpu(evsel->core.cpus, cpu); -	return perf_cpu_map__idx(other->core.cpus, cpuid); +	cpu = perf_cpu_map__cpu(evsel->core.cpus, cpu_map_idx); +	return perf_cpu_map__idx(other->core.cpus, cpu);  } -static int evsel__hybrid_group_cpu(struct evsel *evsel, int cpu) +static int evsel__hybrid_group_cpu_map_idx(struct evsel *evsel, int cpu_map_idx)  {  	struct evsel *leader = evsel__leader(evsel);  	if ((evsel__is_hybrid(evsel) && !evsel__is_hybrid(leader)) ||  	    (!evsel__is_hybrid(evsel) && evsel__is_hybrid(leader))) { -		return evsel__match_other_cpu(evsel, leader, cpu); +		return evsel__match_other_cpu(evsel, leader, cpu_map_idx);  	} -	return cpu; +	return cpu_map_idx;  } -static int get_group_fd(struct evsel *evsel, int cpu, int thread) +static int get_group_fd(struct evsel *evsel, int cpu_map_idx, int thread)  {  	struct evsel *leader = evsel__leader(evsel);  	int fd; @@ -1644,11 +1689,11 @@ static int get_group_fd(struct evsel *evsel, int cpu, int thread)  	 */  	BUG_ON(!leader->core.fd); -	cpu = evsel__hybrid_group_cpu(evsel, cpu); -	if (cpu == -1) +	cpu_map_idx = evsel__hybrid_group_cpu_map_idx(evsel, cpu_map_idx); +	if (cpu_map_idx == -1)  		return -1; -	fd = FD(leader, cpu, thread); +	fd = FD(leader, cpu_map_idx, thread);  	BUG_ON(fd == -1);  	return fd; @@ -1662,16 +1707,16 @@ static void evsel__remove_fd(struct evsel *pos, int nr_cpus, int nr_threads, int  }  static int update_fds(struct evsel *evsel, -		      int nr_cpus, int cpu_idx, +		      int nr_cpus, int cpu_map_idx,  		      int nr_threads, int thread_idx)  {  	struct evsel *pos; -	if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) +	if (cpu_map_idx >= nr_cpus || thread_idx >= nr_threads)  		return -EINVAL;  	evlist__for_each_entry(evsel->evlist, pos) { -		nr_cpus = pos != evsel ? nr_cpus : cpu_idx; +		nr_cpus = pos != evsel ? nr_cpus : cpu_map_idx;  		evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx); @@ -1685,10 +1730,10 @@ static int update_fds(struct evsel *evsel,  	return 0;  } -bool evsel__ignore_missing_thread(struct evsel *evsel, -				  int nr_cpus, int cpu, -				  struct perf_thread_map *threads, -				  int thread, int err) +static bool evsel__ignore_missing_thread(struct evsel *evsel, +					 int nr_cpus, int cpu_map_idx, +					 struct perf_thread_map *threads, +					 int thread, int err)  {  	pid_t ignore_pid = perf_thread_map__pid(threads, thread); @@ -1711,7 +1756,7 @@ bool evsel__ignore_missing_thread(struct evsel *evsel,  	 * We should remove fd for missing_thread first  	 * because thread_map__remove() will decrease threads->nr.  	 */ -	if (update_fds(evsel, nr_cpus, cpu, threads->nr, thread)) +	if (update_fds(evsel, nr_cpus, cpu_map_idx, threads->nr, thread))  		return false;  	if (thread_map__remove(threads, thread)) @@ -1768,7 +1813,7 @@ static struct perf_thread_map *empty_thread_map;  static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,  		struct perf_thread_map *threads)  { -	int nthreads; +	int nthreads = perf_thread_map__nr(threads);  	if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) ||  	    (perf_missing_features.aux_output     && evsel->core.attr.aux_output)) @@ -1794,13 +1839,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,  		threads = empty_thread_map;  	} -	if (evsel->core.system_wide) -		nthreads = 1; -	else -		nthreads = threads->nr; -  	if (evsel->core.fd == NULL && -	    perf_evsel__alloc_fd(&evsel->core, cpus->nr, nthreads) < 0) +	    perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0)  		return -ENOMEM;  	evsel->open_flags = PERF_FLAG_FD_CLOEXEC; @@ -1812,6 +1852,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,  static void evsel__disable_missing_features(struct evsel *evsel)  { +	if (perf_missing_features.read_lost) +		evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;  	if (perf_missing_features.weight_struct) {  		evsel__set_sample_bit(evsel, WEIGHT);  		evsel__reset_sample_bit(evsel, WEIGHT_STRUCT); @@ -1863,7 +1905,12 @@ bool evsel__detect_missing_features(struct evsel *evsel)  	 * Must probe features in the order they were added to the  	 * perf_event_attr interface.  	 */ -	if (!perf_missing_features.weight_struct && +	if (!perf_missing_features.read_lost && +	    (evsel->core.attr.read_format & PERF_FORMAT_LOST)) { +		perf_missing_features.read_lost = true; +		pr_debug2("switching off PERF_FORMAT_LOST support\n"); +		return true; +	} else if (!perf_missing_features.weight_struct &&  	    (evsel->core.attr.sample_type & PERF_SAMPLE_WEIGHT_STRUCT)) {  		perf_missing_features.weight_struct = true;  		pr_debug2("switching off weight struct support\n"); @@ -1993,9 +2040,9 @@ bool evsel__increase_rlimit(enum rlimit_action *set_rlimit)  static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,  		struct perf_thread_map *threads, -		int start_cpu, int end_cpu) +		int start_cpu_map_idx, int end_cpu_map_idx)  { -	int cpu, thread, nthreads; +	int idx, thread, nthreads;  	int pid = -1, err, old_errno;  	enum rlimit_action set_rlimit = NO_CHANGE; @@ -2009,10 +2056,7 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,  	if (threads == NULL)  		threads = empty_thread_map; -	if (evsel->core.system_wide) -		nthreads = 1; -	else -		nthreads = threads->nr; +	nthreads = perf_thread_map__nr(threads);  	if (evsel->cgrp)  		pid = evsel->cgrp->fd; @@ -2022,7 +2066,7 @@ fallback_missing_features:  	display_attr(&evsel->core.attr); -	for (cpu = start_cpu; cpu < end_cpu; cpu++) { +	for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) {  		for (thread = 0; thread < nthreads; thread++) {  			int fd, group_fd; @@ -2033,17 +2077,19 @@ retry_open:  			if (!evsel->cgrp && !evsel->core.system_wide)  				pid = perf_thread_map__pid(threads, thread); -			group_fd = get_group_fd(evsel, cpu, thread); +			group_fd = get_group_fd(evsel, idx, thread);  			test_attr__ready(); +			/* Debug message used by test scripts */  			pr_debug2_peo("sys_perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx", -				pid, cpus->map[cpu], group_fd, evsel->open_flags); +				pid, perf_cpu_map__cpu(cpus, idx).cpu, group_fd, evsel->open_flags); -			fd = sys_perf_event_open(&evsel->core.attr, pid, cpus->map[cpu], +			fd = sys_perf_event_open(&evsel->core.attr, pid, +						perf_cpu_map__cpu(cpus, idx).cpu,  						group_fd, evsel->open_flags); -			FD(evsel, cpu, thread) = fd; +			FD(evsel, idx, thread) = fd;  			if (fd < 0) {  				err = -errno; @@ -2053,13 +2099,15 @@ retry_open:  				goto try_fallback;  			} -			bpf_counter__install_pe(evsel, cpu, fd); +			bpf_counter__install_pe(evsel, idx, fd);  			if (unlikely(test_attr__enabled)) { -				test_attr__open(&evsel->core.attr, pid, cpus->map[cpu], +				test_attr__open(&evsel->core.attr, pid, +						perf_cpu_map__cpu(cpus, idx),  						fd, group_fd, evsel->open_flags);  			} +			/* Debug message used by test scripts */  			pr_debug2_peo(" = %d\n", fd);  			if (evsel->bpf_fd >= 0) { @@ -2097,7 +2145,8 @@ try_fallback:  	if (evsel__precise_ip_fallback(evsel))  		goto retry_open; -	if (evsel__ignore_missing_thread(evsel, cpus->nr, cpu, threads, thread, err)) { +	if (evsel__ignore_missing_thread(evsel, perf_cpu_map__nr(cpus), +					 idx, threads, thread, err)) {  		/* We just removed 1 thread, so lower the upper nthreads limit. */  		nthreads--; @@ -2112,7 +2161,7 @@ try_fallback:  	if (err == -EMFILE && evsel__increase_rlimit(&set_rlimit))  		goto retry_open; -	if (err != -EINVAL || cpu > 0 || thread > 0) +	if (err != -EINVAL || idx > 0 || thread > 0)  		goto out_close;  	if (evsel__detect_missing_features(evsel)) @@ -2124,12 +2173,12 @@ out_close:  	old_errno = errno;  	do {  		while (--thread >= 0) { -			if (FD(evsel, cpu, thread) >= 0) -				close(FD(evsel, cpu, thread)); -			FD(evsel, cpu, thread) = -1; +			if (FD(evsel, idx, thread) >= 0) +				close(FD(evsel, idx, thread)); +			FD(evsel, idx, thread) = -1;  		}  		thread = nthreads; -	} while (--cpu >= 0); +	} while (--idx >= 0);  	errno = old_errno;  	return err;  } @@ -2137,7 +2186,7 @@ out_close:  int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus,  		struct perf_thread_map *threads)  { -	return evsel__open_cpu(evsel, cpus, threads, 0, cpus ? cpus->nr : 1); +	return evsel__open_cpu(evsel, cpus, threads, 0, perf_cpu_map__nr(cpus));  }  void evsel__close(struct evsel *evsel) @@ -2146,13 +2195,12 @@ void evsel__close(struct evsel *evsel)  	perf_evsel__free_id(&evsel->core);  } -int evsel__open_per_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, int cpu) +int evsel__open_per_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, int cpu_map_idx)  { -	if (cpu == -1) -		return evsel__open_cpu(evsel, cpus, NULL, 0, -					cpus ? cpus->nr : 1); +	if (cpu_map_idx == -1) +		return evsel__open_cpu(evsel, cpus, NULL, 0, perf_cpu_map__nr(cpus)); -	return evsel__open_cpu(evsel, cpus, NULL, cpu, cpu + 1); +	return evsel__open_cpu(evsel, cpus, NULL, cpu_map_idx, cpu_map_idx + 1);  }  int evsel__open_per_thread(struct evsel *evsel, struct perf_thread_map *threads) @@ -2329,6 +2377,7 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,  	data->misc    = event->header.misc;  	data->id = -1ULL;  	data->data_src = PERF_MEM_DATA_SRC_NONE; +	data->vcpu = -1;  	if (event->header.type != PERF_RECORD_SAMPLE) {  		if (!evsel->core.attr.sample_id_all) @@ -2433,8 +2482,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,  			if (data->read.group.nr > max_group_nr)  				return -EFAULT; -			sz = data->read.group.nr * -			     sizeof(struct sample_read_value); + +			sz = data->read.group.nr * sample_read_value_size(read_format);  			OVERFLOW_CHECK(array, sz, max_size);  			data->read.group.values =  					(struct sample_read_value *)array; @@ -2443,6 +2492,12 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,  			OVERFLOW_CHECK_u64(array);  			data->read.one.id = *array;  			array++; + +			if (read_format & PERF_FORMAT_LOST) { +				OVERFLOW_CHECK_u64(array); +				data->read.one.lost = *array; +				array++; +			}  		}  	} @@ -2688,6 +2743,32 @@ int evsel__parse_sample_timestamp(struct evsel *evsel, union perf_event *event,  	return 0;  } +u16 evsel__id_hdr_size(struct evsel *evsel) +{ +	u64 sample_type = evsel->core.attr.sample_type; +	u16 size = 0; + +	if (sample_type & PERF_SAMPLE_TID) +		size += sizeof(u64); + +	if (sample_type & PERF_SAMPLE_TIME) +		size += sizeof(u64); + +	if (sample_type & PERF_SAMPLE_ID) +		size += sizeof(u64); + +	if (sample_type & PERF_SAMPLE_STREAM_ID) +		size += sizeof(u64); + +	if (sample_type & PERF_SAMPLE_CPU) +		size += sizeof(u64); + +	if (sample_type & PERF_SAMPLE_IDENTIFIER) +		size += sizeof(u64); + +	return size; +} +  struct tep_format_field *evsel__field(struct evsel *evsel, const char *name)  {  	return tep_find_field(evsel->tp_format, name); @@ -2706,6 +2787,8 @@ void *evsel__rawptr(struct evsel *evsel, struct perf_sample *sample, const char  	if (field->flags & TEP_FIELD_IS_DYNAMIC) {  		offset = *(int *)(sample->raw_data + field->offset);  		offset &= 0xffff; +		if (field->flags & TEP_FIELD_IS_RELATIVE) +			offset += field->offset + field->size;  	}  	return sample->raw_data + offset; @@ -2852,9 +2935,23 @@ static bool find_process(const char *name)  	return ret ? false : true;  } +static bool is_amd(const char *arch, const char *cpuid) +{ +	return arch && !strcmp("x86", arch) && cpuid && strstarts(cpuid, "AuthenticAMD"); +} + +static bool is_amd_ibs(struct evsel *evsel) +{ +	return evsel->core.attr.precise_ip +	    || (evsel->pmu_name && !strncmp(evsel->pmu_name, "ibs", 3)); +} +  int evsel__open_strerror(struct evsel *evsel, struct target *target,  			 int err, char *msg, size_t size)  { +	struct perf_env *env = evsel__env(evsel); +	const char *arch = perf_env__arch(env); +	const char *cpuid = perf_env__cpuid(env);  	char sbuf[STRERR_BUFSIZE];  	int printed = 0, enforced = 0; @@ -2914,6 +3011,10 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,  	 "No such device - did you specify an out-of-range profile CPU?");  		break;  	case EOPNOTSUPP: +		if (evsel->core.attr.sample_type & PERF_SAMPLE_BRANCH_STACK) +			return scnprintf(msg, size, +	"%s: PMU Hardware or event type doesn't support branch stack sampling.", +					 evsel__name(evsel));  		if (evsel->core.attr.aux_output)  			return scnprintf(msg, size,  	"%s: PMU Hardware doesn't support 'aux_output' feature", @@ -2950,6 +3051,21 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,  			return scnprintf(msg, size, "wrong clockid (%d).", clockid);  		if (perf_missing_features.aux_output)  			return scnprintf(msg, size, "The 'aux_output' feature is not supported, update the kernel."); +		if (!target__has_cpu(target)) +			return scnprintf(msg, size, +	"Invalid event (%s) in per-thread mode, enable system wide with '-a'.", +					evsel__name(evsel)); +		if (is_amd(arch, cpuid)) { +			if (is_amd_ibs(evsel)) { +				if (evsel->core.attr.exclude_kernel) +					return scnprintf(msg, size, +	"AMD IBS can't exclude kernel events.  Try running at a higher privilege level."); +				if (!evsel->core.system_wide) +					return scnprintf(msg, size, +	"AMD IBS may only be available in system-wide/per-cpu mode.  Try using -a, or -C and workload affinity"); +			} +		} +  		break;  	case ENODATA:  		return scnprintf(msg, size, "Cannot collect data source with the load latency event alone. " @@ -2966,22 +3082,22 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,  struct perf_env *evsel__env(struct evsel *evsel)  { -	if (evsel && evsel->evlist) +	if (evsel && evsel->evlist && evsel->evlist->env)  		return evsel->evlist->env;  	return &perf_env;  }  static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist)  { -	int cpu, thread; +	int cpu_map_idx, thread; -	for (cpu = 0; cpu < xyarray__max_x(evsel->core.fd); cpu++) { +	for (cpu_map_idx = 0; cpu_map_idx < xyarray__max_x(evsel->core.fd); cpu_map_idx++) {  		for (thread = 0; thread < xyarray__max_y(evsel->core.fd);  		     thread++) { -			int fd = FD(evsel, cpu, thread); +			int fd = FD(evsel, cpu_map_idx, thread);  			if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, -						   cpu, thread, fd) < 0) +						   cpu_map_idx, thread, fd) < 0)  				return -1;  		}  	} @@ -2994,7 +3110,7 @@ int evsel__store_ids(struct evsel *evsel, struct evlist *evlist)  	struct perf_cpu_map *cpus = evsel->core.cpus;  	struct perf_thread_map *threads = evsel->core.threads; -	if (perf_evsel__alloc_id(&evsel->core, cpus->nr, threads->nr)) +	if (perf_evsel__alloc_id(&evsel->core, perf_cpu_map__nr(cpus), threads->nr))  		return -ENOMEM;  	return store_evsel_ids(evsel, evlist); @@ -3049,3 +3165,22 @@ int evsel__source_count(const struct evsel *evsel)  	}  	return count;  } + +bool __weak arch_evsel__must_be_in_group(const struct evsel *evsel __maybe_unused) +{ +	return false; +} + +/* + * Remove an event from a given group (leader). + * Some events, e.g., perf metrics Topdown events, + * must always be grouped. Ignore the events. + */ +void evsel__remove_from_group(struct evsel *evsel, struct evsel *leader) +{ +	if (!arch_evsel__must_be_in_group(evsel) && evsel != leader) { +		evsel__set_leader(evsel, evsel); +		evsel->core.nr_members = 0; +		leader->core.nr_members--; +	} +}  | 
