Commit eb7a52d4 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

perf record: Add aux-sample-size config term



To allow individual events to be selected for AUX area sampling, add
aux-sample-size config term. attr.aux_sample_size is updated by
auxtrace_parse_sample_options() so that the existing validation will see
the value. Any event that has a non-zero aux_sample_size will cause AUX
area sampling to be configured, irrespective of the --aux-sample option.

Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lore.kernel.org/lkml/20191115124225.5247-8-adrian.hunter@intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c0a6de06
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ OPTIONS
		    like this: name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\'.
	  - 'aux-output': Generate AUX records instead of events. This requires
			  that an AUX area event is also provided.
	  - 'aux-sample-size': Set sample size for AUX area sampling. If the
	  '--aux-sample' option has been used, set aux-sample-size=0 to disable
	  AUX area sampling for the event.

          See the linkperf:perf-list[1] man page for more parameters.

+75 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include "map.h"
#include "pmu.h"
#include "evsel.h"
#include "evsel_config.h"
#include "symbol.h"
#include "util/synthetic-events.h"
#include "thread_map.h"
@@ -76,6 +77,53 @@ static bool perf_evsel__is_aux_event(struct evsel *evsel)
	return pmu && pmu->auxtrace;
}

/*
 * Make a group from 'leader' to 'last', requiring that the events were not
 * already grouped to a different leader.
 */
static int perf_evlist__regroup(struct evlist *evlist,
				struct evsel *leader,
				struct evsel *last)
{
	struct evsel *evsel;
	bool grp;

	if (!perf_evsel__is_group_leader(leader))
		return -EINVAL;

	grp = false;
	evlist__for_each_entry(evlist, evsel) {
		if (grp) {
			if (!(evsel->leader == leader ||
			     (evsel->leader == evsel &&
			      evsel->core.nr_members <= 1)))
				return -EINVAL;
		} else if (evsel == leader) {
			grp = true;
		}
		if (evsel == last)
			break;
	}

	grp = false;
	evlist__for_each_entry(evlist, evsel) {
		if (grp) {
			if (evsel->leader != leader) {
				evsel->leader = leader;
				if (leader->core.nr_members < 1)
					leader->core.nr_members = 1;
				leader->core.nr_members += 1;
			}
		} else if (evsel == leader) {
			grp = true;
		}
		if (evsel == last)
			break;
	}

	return 0;
}

static bool auxtrace__dont_decode(struct perf_session *session)
{
	return !session->itrace_synth_opts ||
@@ -679,13 +727,16 @@ int auxtrace_parse_sample_options(struct auxtrace_record *itr,
				  struct evlist *evlist,
				  struct record_opts *opts, const char *str)
{
	struct perf_evsel_config_term *term;
	struct evsel *aux_evsel;
	bool has_aux_sample_size = false;
	bool has_aux_leader = false;
	struct evsel *evsel;
	char *endptr;
	unsigned long sz;

	if (!str)
		return 0;
		goto no_opt;

	if (!itr) {
		pr_err("No AUX area event to sample\n");
@@ -712,6 +763,29 @@ int auxtrace_parse_sample_options(struct auxtrace_record *itr,
			evsel->core.attr.aux_sample_size = sz;
		}
	}
no_opt:
	aux_evsel = NULL;
	/* Override with aux_sample_size from config term */
	evlist__for_each_entry(evlist, evsel) {
		if (perf_evsel__is_aux_event(evsel))
			aux_evsel = evsel;
		term = perf_evsel__get_config_term(evsel, AUX_SAMPLE_SIZE);
		if (term) {
			has_aux_sample_size = true;
			evsel->core.attr.aux_sample_size = term->val.aux_sample_size;
			/* If possible, group with the AUX event */
			if (aux_evsel && evsel->core.attr.aux_sample_size)
				perf_evlist__regroup(evlist, aux_evsel, evsel);
		}
	}

	if (!str && !has_aux_sample_size)
		return 0;

	if (!itr) {
		pr_err("No AUX area event to sample\n");
		return -EINVAL;
	}

	return auxtrace_validate_aux_sample_size(evlist, opts);
}
+16 −0
Original line number Diff line number Diff line
@@ -846,6 +846,9 @@ static void apply_config_terms(struct evsel *evsel,
		case PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT:
			attr->aux_output = term->val.aux_output ? 1 : 0;
			break;
		case PERF_EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
			/* Already applied by auxtrace */
			break;
		default:
			break;
		}
@@ -905,6 +908,19 @@ static bool is_dummy_event(struct evsel *evsel)
	       (evsel->core.attr.config == PERF_COUNT_SW_DUMMY);
}

struct perf_evsel_config_term *__perf_evsel__get_config_term(struct evsel *evsel,
							     enum evsel_term_type type)
{
	struct perf_evsel_config_term *term, *found_term = NULL;

	list_for_each_entry(term, &evsel->config_terms, list) {
		if (term->type == type)
			found_term = term;
	}

	return found_term;
}

/*
 * The enable_on_exec/disabled value strategy:
 *
+11 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ enum evsel_term_type {
	PERF_EVSEL__CONFIG_TERM_BRANCH,
	PERF_EVSEL__CONFIG_TERM_PERCORE,
	PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT,
	PERF_EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
};

struct perf_evsel_config_term {
@@ -44,7 +45,17 @@ struct perf_evsel_config_term {
		unsigned long max_events;
		bool	      percore;
		bool	      aux_output;
		u32	      aux_sample_size;
	} val;
	bool weak;
};

struct evsel;

struct perf_evsel_config_term *__perf_evsel__get_config_term(struct evsel *evsel,
							     enum evsel_term_type type);

#define perf_evsel__get_config_term(evsel, type) \
	__perf_evsel__get_config_term(evsel, PERF_EVSEL__CONFIG_TERM_ ## type)

#endif // __PERF_EVSEL_CONFIG_H
+14 −0
Original line number Diff line number Diff line
@@ -996,6 +996,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
	[PARSE_EVENTS__TERM_TYPE_DRV_CFG]		= "driver-config",
	[PARSE_EVENTS__TERM_TYPE_PERCORE]		= "percore",
	[PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT]		= "aux-output",
	[PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE]	= "aux-sample-size",
};

static bool config_term_shrinked;
@@ -1126,6 +1127,15 @@ do { \
	case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
		CHECK_TYPE_VAL(NUM);
		break;
	case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
		CHECK_TYPE_VAL(NUM);
		if (term->val.num > UINT_MAX) {
			parse_events__handle_error(err, term->err_val,
						strdup("too big"),
						NULL);
			return -EINVAL;
		}
		break;
	default:
		parse_events__handle_error(err, term->err_term,
				strdup("unknown term"),
@@ -1177,6 +1187,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
	case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
	case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
	case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
	case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
		return config_term_common(attr, term, err);
	default:
		if (err) {
@@ -1272,6 +1283,9 @@ do { \
		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
			ADD_CONFIG_TERM(AUX_OUTPUT, aux_output, term->val.num ? 1 : 0);
			break;
		case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
			ADD_CONFIG_TERM(AUX_SAMPLE_SIZE, aux_sample_size, term->val.num);
			break;
		default:
			break;
		}
Loading