Commit 9fbb4b02 authored by Kan Liang's avatar Kan Liang Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add branch counter knob



Add a new branch filter, "counter", for the branch counter option. It is
used to mark the events which should be logged in the branch. If it is
applied with the -j option, the counters of all the events should be
logged in the branch. If the legacy kernel doesn't support the new
branch sample type, switching off the branch counter filter.

The stored counter values in each branch are displayed right after the
regular branch stack information via perf report -D.

Usage examples:

  # perf record -e "{branch-instructions,branch-misses}:S" -j any,counter

Only the first event, branch-instructions, collect the LBR. Both
branch-instructions and branch-misses are marked as logged events.  The
occurrences information of them can be found in the branch stack
extension space of each branch.

  # perf record -e "{cpu/branch-instructions,branch_type=any/,cpu/branch-misses,branch_type=counter/}"

Only the first event, branch-instructions, collect the LBR. Only the
branch-misses event is marked as a logged event.

Committer notes:

I noticed 'perf test "Sample parsing"' failing, reported to the list and
Kan provided a patch that checks if the evsel has a leader and that
evsel->evlist is set, the comment in the source code further explains
it.

Reviewed-by: default avatarIan Rogers <irogers@google.com>
Signed-off-by: default avatarKan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Bayduraev <alexey.v.bayduraev@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tinghao Zhang <tinghao.zhang@intel.com>
Link: https://lore.kernel.org/r/20231025201626.3000228-8-kan.liang@linux.intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent ac9cd724
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -445,6 +445,10 @@ following filters are defined:
		     4th-Gen Xeon+ server), the save branch type is unconditionally enabled
		     when the taken branch stack sampling is enabled.
	- priv: save privilege state during sampling in case binary is not available later
	- counter: save occurrences of the event since the last branch entry. Currently, the
		   feature is only supported by a newer CPU, e.g., Intel Sierra Forest and
		   later platforms. An error out is expected if it's used on the unsupported
		   kernel or CPUs.

+
The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
+34 −1
Original line number Diff line number Diff line
@@ -1832,6 +1832,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.branch_counters)
		evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_COUNTERS;
	if (perf_missing_features.read_lost)
		evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;
	if (perf_missing_features.weight_struct) {
@@ -1885,7 +1887,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.read_lost &&
	if (!perf_missing_features.branch_counters &&
	    (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) {
		perf_missing_features.branch_counters = true;
		pr_debug2("switching off branch counters support\n");
		return true;
	} else 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");
@@ -2318,6 +2325,22 @@ u64 evsel__bitfield_swap_branch_flags(u64 value)
	return new_val;
}

static inline bool evsel__has_branch_counters(const struct evsel *evsel)
{
	struct evsel *cur, *leader = evsel__leader(evsel);

	/* The branch counters feature only supports group */
	if (!leader || !evsel->evlist)
		return false;

	evlist__for_each_entry(evsel->evlist, cur) {
		if ((leader == evsel__leader(cur)) &&
		    (cur->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS))
			return true;
	}
	return false;
}

int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
			struct perf_sample *data)
{
@@ -2551,6 +2574,16 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,

		OVERFLOW_CHECK(array, sz, max_size);
		array = (void *)array + sz;

		if (evsel__has_branch_counters(evsel)) {
			OVERFLOW_CHECK_u64(array);

			data->branch_stack_cntr = (u64 *)array;
			sz = data->branch_stack->nr * sizeof(u64);

			OVERFLOW_CHECK(array, sz, max_size);
			array = (void *)array + sz;
		}
	}

	if (type & PERF_SAMPLE_REGS_USER) {
+1 −0
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ struct perf_missing_features {
	bool code_page_size;
	bool weight_struct;
	bool read_lost;
	bool branch_counters;
};

extern struct perf_missing_features perf_missing_features;
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ static const struct branch_mode branch_modes[] = {
	BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK),
	BRANCH_OPT("hw_index", PERF_SAMPLE_BRANCH_HW_INDEX),
	BRANCH_OPT("priv", PERF_SAMPLE_BRANCH_PRIV_SAVE),
	BRANCH_OPT("counter", PERF_SAMPLE_BRANCH_COUNTERS),
	BRANCH_END
};

+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value)
		bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
		bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
		bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE),
		bit_name(COUNTERS),
		{ .name = NULL, }
	};
#undef bit_name
Loading