Commit 7fedd9b8 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo
Browse files

perf evsel: Add evsel__clone() function



The evsel__clone() is to create an exactly same evsel from same
attributes.  The function assumes the given evsel is not configured
yet so it cares fields set during event parsing.  Those fields are now
moved together as Jiri suggested.  Note that metric events will be
handled by later patch.

It will be used by perf stat to generate separate events for each
cgroup.

Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
Acked-by: default avatarJiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20200924124455.336326-2-namhyung@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent b5ff7f27
Loading
Loading
Loading
Loading
+104 −0
Original line number Diff line number Diff line
@@ -331,6 +331,110 @@ error_free:
	goto out;
}

static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src)
{
	struct evsel_config_term *pos, *tmp;

	list_for_each_entry(pos, &src->config_terms, list) {
		tmp = malloc(sizeof(*tmp));
		if (tmp == NULL)
			return -ENOMEM;

		*tmp = *pos;
		if (tmp->free_str) {
			tmp->val.str = strdup(pos->val.str);
			if (tmp->val.str == NULL) {
				free(tmp);
				return -ENOMEM;
			}
		}
		list_add_tail(&tmp->list, &dst->config_terms);
	}
	return 0;
}

/**
 * evsel__clone - create a new evsel copied from @orig
 * @orig: original evsel
 *
 * The assumption is that @orig is not configured nor opened yet.
 * So we only care about the attributes that can be set while it's parsed.
 */
struct evsel *evsel__clone(struct evsel *orig)
{
	struct evsel *evsel;

	BUG_ON(orig->core.fd);
	BUG_ON(orig->counts);
	BUG_ON(orig->priv);
	BUG_ON(orig->per_pkg_mask);

	/* cannot handle BPF objects for now */
	if (orig->bpf_obj)
		return NULL;

	evsel = evsel__new(&orig->core.attr);
	if (evsel == NULL)
		return NULL;

	evsel->core.cpus = perf_cpu_map__get(orig->core.cpus);
	evsel->core.own_cpus = perf_cpu_map__get(orig->core.own_cpus);
	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;

	if (orig->name) {
		evsel->name = strdup(orig->name);
		if (evsel->name == NULL)
			goto out_err;
	}
	if (orig->group_name) {
		evsel->group_name = strdup(orig->group_name);
		if (evsel->group_name == NULL)
			goto out_err;
	}
	if (orig->pmu_name) {
		evsel->pmu_name = strdup(orig->pmu_name);
		if (evsel->pmu_name == NULL)
			goto out_err;
	}
	if (orig->filter) {
		evsel->filter = strdup(orig->filter);
		if (evsel->filter == NULL)
			goto out_err;
	}
	evsel->cgrp = cgroup__get(orig->cgrp);
	evsel->tp_format = orig->tp_format;
	evsel->handler = orig->handler;
	evsel->leader = orig->leader;

	evsel->max_events = orig->max_events;
	evsel->tool_event = orig->tool_event;
	evsel->unit = orig->unit;
	evsel->scale = orig->scale;
	evsel->snapshot = orig->snapshot;
	evsel->per_pkg = orig->per_pkg;
	evsel->percore = orig->percore;
	evsel->precise_max = orig->precise_max;
	evsel->use_uncore_alias = orig->use_uncore_alias;
	evsel->is_libpfm_event = orig->is_libpfm_event;

	evsel->exclude_GH = orig->exclude_GH;
	evsel->sample_read = orig->sample_read;
	evsel->auto_merge_stats = orig->auto_merge_stats;
	evsel->collect_stat = orig->collect_stat;
	evsel->weak_group = orig->weak_group;

	if (evsel__copy_config_terms(evsel, orig) < 0)
		goto out_err;

	return evsel;

out_err:
	evsel__delete(evsel);
	return NULL;
}

/*
 * Returns pointer with encoded error via <linux/err.h> interface.
 */
+54 −39
Original line number Diff line number Diff line
@@ -43,64 +43,78 @@ enum perf_tool_event {
struct evsel {
	struct perf_evsel	core;
	struct evlist		*evlist;
	char			*filter;
	struct perf_counts	*counts;
	struct perf_counts	*prev_raw_counts;
	off_t			id_offset;
	int			idx;
	unsigned long		max_events;
	unsigned long		nr_events_printed;
	int			id_pos;
	int			is_pos;
	unsigned int		sample_size;

	/*
	 * These fields can be set in the parse-events code or similar.
	 * Please check evsel__clone() to copy them properly so that
	 * they can be released properly.
	 */
	struct {
		char			*name;
		char			*group_name;
		const char		*pmu_name;
		struct tep_event	*tp_format;
		char			*filter;
		unsigned long		max_events;
		double			scale;
		const char		*unit;
	struct tep_event	*tp_format;
	off_t			id_offset;
		struct cgroup		*cgrp;
		enum perf_tool_event	tool_event;
		/* parse modifier helper */
		int			exclude_GH;
		int			sample_read;
		bool			snapshot;
		bool			per_pkg;
		bool			percore;
		bool			precise_max;
		bool			use_uncore_alias;
		bool			is_libpfm_event;
		bool			auto_merge_stats;
		bool			collect_stat;
		bool			weak_group;
		int			bpf_fd;
		struct bpf_object	*bpf_obj;
	};

	/*
	 * metric fields are similar, but needs more care as they can have
	 * references to other metric (evsel).
	 */
	const char *		metric_expr;
	const char *		metric_name;
	struct evsel		**metric_events;
	struct evsel		*metric_leader;

	void			*handler;
	struct perf_counts	*counts;
	struct perf_counts	*prev_raw_counts;
	unsigned long		nr_events_printed;
	struct perf_stat_evsel  *stats;
	void			*priv;
	u64			db_id;
	struct cgroup		*cgrp;
	void			*handler;
	unsigned int		sample_size;
	int			id_pos;
	int			is_pos;
	enum perf_tool_event	tool_event;
	bool			uniquified_name;
	bool			snapshot;
	bool 			supported;
	bool 			needs_swap;
	bool 			disabled;
	bool			no_aux_samples;
	bool			immediate;
	bool			tracking;
	bool			per_pkg;
	bool			precise_max;
	bool			ignore_missing_thread;
	bool			forced_leader;
	bool			use_uncore_alias;
	bool			is_libpfm_event;
	/* parse modifier helper */
	int			exclude_GH;
	int			sample_read;
	unsigned long		*per_pkg_mask;
	struct evsel		*leader;
	char			*group_name;
	bool			cmdline_group_boundary;
	struct list_head	config_terms;
	struct bpf_object	*bpf_obj;
	int			bpf_fd;
	int			err;
	bool			auto_merge_stats;
	bool			merged_stat;
	const char *		metric_expr;
	const char *		metric_name;
	struct evsel		**metric_events;
	struct evsel		*metric_leader;
	bool			collect_stat;
	bool			weak_group;
	bool			reset_group;
	bool			errored;
	bool			percore;
	unsigned long		*per_pkg_mask;
	struct evsel		*leader;
	struct list_head	config_terms;
	int			err;
	int			cpu_iter;
	const char		*pmu_name;
	struct {
		evsel__sb_cb_t	*cb;
		void		*data;
@@ -169,6 +183,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr)
	return evsel__new_idx(attr, 0);
}

struct evsel *evsel__clone(struct evsel *orig);
struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx);

/*