diff options
Diffstat (limited to 'tools/lib/perf')
| -rw-r--r-- | tools/lib/perf/Documentation/libperf.txt | 1 | ||||
| -rw-r--r-- | tools/lib/perf/cpumap.c | 10 | ||||
| -rw-r--r-- | tools/lib/perf/evlist.c | 119 | ||||
| -rw-r--r-- | tools/lib/perf/evsel.c | 11 | ||||
| -rw-r--r-- | tools/lib/perf/include/internal/evsel.h | 3 | ||||
| -rw-r--r-- | tools/lib/perf/include/perf/cpumap.h | 2 | ||||
| -rw-r--r-- | tools/lib/perf/include/perf/event.h | 30 | ||||
| -rw-r--r-- | tools/lib/perf/include/perf/threadmap.h | 1 | ||||
| -rw-r--r-- | tools/lib/perf/threadmap.c | 17 | 
9 files changed, 155 insertions, 39 deletions
| diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt index 59aabdd3cabf..4072bc9b7670 100644 --- a/tools/lib/perf/Documentation/libperf.txt +++ b/tools/lib/perf/Documentation/libperf.txt @@ -210,6 +210,7 @@ SYNOPSIS    struct perf_record_time_conv;    struct perf_record_header_feature;    struct perf_record_compressed; +  struct perf_record_compressed2;  --  DESCRIPTION diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 4454a5987570..b20a5280f2b3 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -242,6 +242,16 @@ out:  	return cpus;  } +struct perf_cpu_map *perf_cpu_map__new_int(int cpu) +{ +	struct perf_cpu_map *cpus = perf_cpu_map__alloc(1); + +	if (cpus) +		RC_CHK_ACCESS(cpus)->map[0].cpu = cpu; + +	return cpus; +} +  static int __perf_cpu_map__nr(const struct perf_cpu_map *cpus)  {  	return RC_CHK_ACCESS(cpus)->nr; diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c index b1f4c8176b32..3ed023f4b190 100644 --- a/tools/lib/perf/evlist.c +++ b/tools/lib/perf/evlist.c @@ -36,49 +36,88 @@ void perf_evlist__init(struct perf_evlist *evlist)  static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,  					  struct perf_evsel *evsel)  { -	if (evsel->system_wide) { -		/* System wide: set the cpu map of the evsel to all online CPUs. */ -		perf_cpu_map__put(evsel->cpus); -		evsel->cpus = perf_cpu_map__new_online_cpus(); -	} else if (evlist->has_user_cpus && evsel->is_pmu_core) { -		/* -		 * User requested CPUs on a core PMU, ensure the requested CPUs -		 * are valid by intersecting with those of the PMU. -		 */ +	if (perf_cpu_map__is_empty(evsel->cpus)) { +		if (perf_cpu_map__is_empty(evsel->pmu_cpus)) { +			/* +			 * Assume the unset PMU cpus were for a system-wide +			 * event, like a software or tracepoint. +			 */ +			evsel->pmu_cpus = perf_cpu_map__new_online_cpus(); +		} +		if (evlist->has_user_cpus && !evsel->system_wide) { +			/* +			 * Use the user CPUs unless the evsel is set to be +			 * system wide, such as the dummy event. +			 */ +			evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus); +		} else { +			/* +			 * System wide and other modes, assume the cpu map +			 * should be set to all PMU CPUs. +			 */ +			evsel->cpus = perf_cpu_map__get(evsel->pmu_cpus); +		} +	} +	/* +	 * Avoid "any CPU"(-1) for uncore and PMUs that require a CPU, even if +	 * requested. +	 */ +	if (evsel->requires_cpu && perf_cpu_map__has_any_cpu(evsel->cpus)) {  		perf_cpu_map__put(evsel->cpus); -		evsel->cpus = perf_cpu_map__intersect(evlist->user_requested_cpus, evsel->own_cpus); +		evsel->cpus = perf_cpu_map__get(evsel->pmu_cpus); +	} -		/* -		 * Empty cpu lists would eventually get opened as "any" so remove -		 * genuinely empty ones before they're opened in the wrong place. -		 */ -		if (perf_cpu_map__is_empty(evsel->cpus)) { -			struct perf_evsel *next = perf_evlist__next(evlist, evsel); - -			perf_evlist__remove(evlist, evsel); -			/* Keep idx contiguous */ -			if (next) -				list_for_each_entry_from(next, &evlist->entries, node) -					next->idx--; +	/* +	 * Globally requested CPUs replace user requested unless the evsel is +	 * set to be system wide. +	 */ +	if (evlist->has_user_cpus && !evsel->system_wide) { +		assert(!perf_cpu_map__has_any_cpu(evlist->user_requested_cpus)); +		if (!perf_cpu_map__equal(evsel->cpus, evlist->user_requested_cpus)) { +			perf_cpu_map__put(evsel->cpus); +			evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);  		} -	} else if (!evsel->own_cpus || evlist->has_user_cpus || -		(!evsel->requires_cpu && perf_cpu_map__has_any_cpu(evlist->user_requested_cpus))) { -		/* -		 * The PMU didn't specify a default cpu map, this isn't a core -		 * event and the user requested CPUs or the evlist user -		 * requested CPUs have the "any CPU" (aka dummy) CPU value. In -		 * which case use the user requested CPUs rather than the PMU -		 * ones. -		 */ +	} + +	/* Ensure cpus only references valid PMU CPUs. */ +	if (!perf_cpu_map__has_any_cpu(evsel->cpus) && +	    !perf_cpu_map__is_subset(evsel->pmu_cpus, evsel->cpus)) { +		struct perf_cpu_map *tmp = perf_cpu_map__intersect(evsel->pmu_cpus, evsel->cpus); +  		perf_cpu_map__put(evsel->cpus); -		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus); -	} else if (evsel->cpus != evsel->own_cpus) { -		/* -		 * No user requested cpu map but the PMU cpu map doesn't match -		 * the evsel's. Reset it back to the PMU cpu map. -		 */ +		evsel->cpus = tmp; +	} + +	/* +	 * Was event requested on all the PMU's CPUs but the user requested is +	 * any CPU (-1)? If so switch to using any CPU (-1) to reduce the number +	 * of events. +	 */ +	if (!evsel->system_wide && +	    !evsel->requires_cpu && +	    perf_cpu_map__equal(evsel->cpus, evsel->pmu_cpus) && +	    perf_cpu_map__has_any_cpu(evlist->user_requested_cpus)) {  		perf_cpu_map__put(evsel->cpus); -		evsel->cpus = perf_cpu_map__get(evsel->own_cpus); +		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus); +	} + +	/* Sanity check assert before the evsel is potentially removed. */ +	assert(!evsel->requires_cpu || !perf_cpu_map__has_any_cpu(evsel->cpus)); + +	/* +	 * Empty cpu lists would eventually get opened as "any" so remove +	 * genuinely empty ones before they're opened in the wrong place. +	 */ +	if (perf_cpu_map__is_empty(evsel->cpus)) { +		struct perf_evsel *next = perf_evlist__next(evlist, evsel); + +		perf_evlist__remove(evlist, evsel); +		/* Keep idx contiguous */ +		if (next) +			list_for_each_entry_from(next, &evlist->entries, node) +				next->idx--; + +		return;  	}  	if (evsel->system_wide) { @@ -98,6 +137,10 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist)  	evlist->needs_map_propagation = true; +	/* Clear the all_cpus set which will be merged into during propagation. */ +	perf_cpu_map__put(evlist->all_cpus); +	evlist->all_cpus = NULL; +  	list_for_each_entry_safe(evsel, n, &evlist->entries, node)  		__perf_evlist__propagate_maps(evlist, evsel);  } diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c index c475319e2e41..13a307fc75ae 100644 --- a/tools/lib/perf/evsel.c +++ b/tools/lib/perf/evsel.c @@ -40,8 +40,19 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)  	return evsel;  } +void perf_evsel__exit(struct perf_evsel *evsel) +{ +	assert(evsel->fd == NULL);  /* If not fds were not closed. */ +	assert(evsel->mmap == NULL); /* If not munmap wasn't called. */ +	assert(evsel->sample_id == NULL); /* If not free_id wasn't called. */ +	perf_cpu_map__put(evsel->cpus); +	perf_cpu_map__put(evsel->pmu_cpus); +	perf_thread_map__put(evsel->threads); +} +  void perf_evsel__delete(struct perf_evsel *evsel)  { +	perf_evsel__exit(evsel);  	free(evsel);  } diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h index ea78defa77d0..fefe64ba5e26 100644 --- a/tools/lib/perf/include/internal/evsel.h +++ b/tools/lib/perf/include/internal/evsel.h @@ -99,7 +99,7 @@ struct perf_evsel {  	 * cpu map for opening the event on, for example, the first CPU on a  	 * socket for an uncore event.  	 */ -	struct perf_cpu_map	*own_cpus; +	struct perf_cpu_map	*pmu_cpus;  	struct perf_thread_map	*threads;  	struct xyarray		*fd;  	struct xyarray		*mmap; @@ -133,6 +133,7 @@ struct perf_evsel {  void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,  		      int idx); +void perf_evsel__exit(struct perf_evsel *evsel);  int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);  void perf_evsel__close_fd(struct perf_evsel *evsel);  void perf_evsel__free_fd(struct perf_evsel *evsel); diff --git a/tools/lib/perf/include/perf/cpumap.h b/tools/lib/perf/include/perf/cpumap.h index 8c1ab0f9194e..58cc5c5fa47c 100644 --- a/tools/lib/perf/include/perf/cpumap.h +++ b/tools/lib/perf/include/perf/cpumap.h @@ -37,6 +37,8 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_online_cpus(void);   *                     perf_cpu_map__new_online_cpus is returned.   */  LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list); +/** perf_cpu_map__new_int - create a map with the one given cpu. */ +LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_int(int cpu);  LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);  LIBPERF_API int perf_cpu_map__merge(struct perf_cpu_map **orig,  				    struct perf_cpu_map *other); diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h index 37bb7771d914..6608f1e3701b 100644 --- a/tools/lib/perf/include/perf/event.h +++ b/tools/lib/perf/include/perf/event.h @@ -457,6 +457,32 @@ struct perf_record_compressed {  	char			 data[];  }; +/* + * `header.size` includes the padding we are going to add while writing the record. + * `data_size` only includes the size of `data[]` itself. + */ +struct perf_record_compressed2 { +	struct perf_event_header header; +	__u64			 data_size; +	char			 data[]; +}; + +#define BPF_METADATA_KEY_LEN   64 +#define BPF_METADATA_VALUE_LEN 256 +#define BPF_PROG_NAME_LEN      KSYM_NAME_LEN + +struct perf_record_bpf_metadata_entry { +	char key[BPF_METADATA_KEY_LEN]; +	char value[BPF_METADATA_VALUE_LEN]; +}; + +struct perf_record_bpf_metadata { +	struct perf_event_header	      header; +	char				      prog_name[BPF_PROG_NAME_LEN]; +	__u64				      nr_entries; +	struct perf_record_bpf_metadata_entry entries[]; +}; +  enum perf_user_event_type { /* above any possible kernel type */  	PERF_RECORD_USER_TYPE_START		= 64,  	PERF_RECORD_HEADER_ATTR			= 64, @@ -478,6 +504,8 @@ enum perf_user_event_type { /* above any possible kernel type */  	PERF_RECORD_HEADER_FEATURE		= 80,  	PERF_RECORD_COMPRESSED			= 81,  	PERF_RECORD_FINISHED_INIT		= 82, +	PERF_RECORD_COMPRESSED2			= 83, +	PERF_RECORD_BPF_METADATA		= 84,  	PERF_RECORD_HEADER_MAX  }; @@ -518,6 +546,8 @@ union perf_event {  	struct perf_record_time_conv		time_conv;  	struct perf_record_header_feature	feat;  	struct perf_record_compressed		pack; +	struct perf_record_compressed2		pack2; +	struct perf_record_bpf_metadata		bpf_metadata;  };  #endif /* __LIBPERF_EVENT_H */ diff --git a/tools/lib/perf/include/perf/threadmap.h b/tools/lib/perf/include/perf/threadmap.h index 8b40e7777cea..44deb815b817 100644 --- a/tools/lib/perf/include/perf/threadmap.h +++ b/tools/lib/perf/include/perf/threadmap.h @@ -14,6 +14,7 @@ LIBPERF_API void perf_thread_map__set_pid(struct perf_thread_map *map, int idx,  LIBPERF_API char *perf_thread_map__comm(struct perf_thread_map *map, int idx);  LIBPERF_API int perf_thread_map__nr(struct perf_thread_map *threads);  LIBPERF_API pid_t perf_thread_map__pid(struct perf_thread_map *map, int idx); +LIBPERF_API int perf_thread_map__idx(struct perf_thread_map *map, pid_t pid);  LIBPERF_API struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map);  LIBPERF_API void perf_thread_map__put(struct perf_thread_map *map); diff --git a/tools/lib/perf/threadmap.c b/tools/lib/perf/threadmap.c index 07968f3ea093..db431b036f57 100644 --- a/tools/lib/perf/threadmap.c +++ b/tools/lib/perf/threadmap.c @@ -97,5 +97,22 @@ int perf_thread_map__nr(struct perf_thread_map *threads)  pid_t perf_thread_map__pid(struct perf_thread_map *map, int idx)  { +	if (!map) { +		assert(idx == 0); +		return -1; +	} +  	return map->map[idx].pid;  } + +int perf_thread_map__idx(struct perf_thread_map *threads, pid_t pid) +{ +	if (!threads) +		return pid == -1 ? 0 : -1; + +	for (int i = 0; i < threads->nr; ++i) { +		if (threads->map[i].pid == pid) +			return i; +	} +	return -1; +} | 
