@@ -402,6 +402,7 @@ 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
+ - event: save occurrences of the event since the last branch entry.
+
The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
@@ -25,7 +25,8 @@ struct branch_flags {
u64 spec:2;
u64 new_type:4;
u64 priv:3;
- u64 reserved:31;
+ u64 events:8;
+ u64 reserved:23;
};
};
};
@@ -1850,6 +1850,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_event)
+ evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_EVENT;
if (perf_missing_features.read_lost)
evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;
if (perf_missing_features.weight_struct) {
@@ -1903,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.read_lost &&
+ if (!perf_missing_features.branch_event &&
+ (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_EVENT)) {
+ perf_missing_features.branch_event = true;
+ pr_debug2("switching off branch event 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");
@@ -2320,7 +2327,8 @@ u64 evsel__bitfield_swap_branch_flags(u64 value)
* spec:2 //branch speculation info
* new_type:4 //additional branch type
* priv:3 //privilege level
- * reserved:31
+ * events:8 //occurrences of events
+ * reserved:23
* }
* }
*
@@ -2339,7 +2347,8 @@ u64 evsel__bitfield_swap_branch_flags(u64 value)
new_val |= bitfield_swap(value, 24, 2);
new_val |= bitfield_swap(value, 26, 4);
new_val |= bitfield_swap(value, 30, 3);
- new_val |= bitfield_swap(value, 33, 31);
+ new_val |= bitfield_swap(value, 33, 8);
+ new_val |= bitfield_swap(value, 41, 23);
} else {
new_val = bitfield_swap(value, 63, 1);
new_val |= bitfield_swap(value, 62, 1);
@@ -2350,7 +2359,8 @@ u64 evsel__bitfield_swap_branch_flags(u64 value)
new_val |= bitfield_swap(value, 38, 2);
new_val |= bitfield_swap(value, 34, 4);
new_val |= bitfield_swap(value, 31, 3);
- new_val |= bitfield_swap(value, 0, 31);
+ new_val |= bitfield_swap(value, 23, 8);
+ new_val |= bitfield_swap(value, 0, 23);
}
return new_val;
@@ -187,6 +187,7 @@ struct perf_missing_features {
bool code_page_size;
bool weight_struct;
bool read_lost;
+ bool branch_event;
};
extern struct perf_missing_features perf_missing_features;
@@ -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("event", PERF_SAMPLE_BRANCH_EVENT),
BRANCH_END
};
@@ -53,6 +53,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(EVENT),
{ .name = NULL, }
};
#undef bit_name
@@ -1180,13 +1180,14 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack)
struct branch_entry *e = &entries[i];
if (!callstack) {
- printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x %s %s\n",
+ printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x %x %s %s\n",
i, e->from, e->to,
(unsigned short)e->flags.cycles,
e->flags.mispred ? "M" : " ",
e->flags.predicted ? "P" : " ",
e->flags.abort ? "A" : " ",
e->flags.in_tx ? "T" : " ",
+ e->flags.events,
(unsigned)e->flags.reserved,
get_branch_type(e),
e->flags.spec ? branch_spec_desc(e->flags.spec) : "");