perf intel-pt: Add LBR information to synthesized PEBS sample
Add LBR information from PEBS data in the Intel PT trace to the synthesized PEBS sample. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: http://lkml.kernel.org/r/20190610072803.10456-10-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
143d34a6b3
commit
aa62afd7da
@@ -1628,6 +1628,58 @@ static void intel_pt_add_xmm(struct regs_dump *intr_regs, u64 *pos,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LBR_INFO_MISPRED (1ULL << 63)
|
||||||
|
#define LBR_INFO_IN_TX (1ULL << 62)
|
||||||
|
#define LBR_INFO_ABORT (1ULL << 61)
|
||||||
|
#define LBR_INFO_CYCLES 0xffff
|
||||||
|
|
||||||
|
/* Refer kernel's intel_pmu_store_pebs_lbrs() */
|
||||||
|
static u64 intel_pt_lbr_flags(u64 info)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct branch_flags flags;
|
||||||
|
u64 result;
|
||||||
|
} u = {
|
||||||
|
.flags = {
|
||||||
|
.mispred = !!(info & LBR_INFO_MISPRED),
|
||||||
|
.predicted = !(info & LBR_INFO_MISPRED),
|
||||||
|
.in_tx = !!(info & LBR_INFO_IN_TX),
|
||||||
|
.abort = !!(info & LBR_INFO_ABORT),
|
||||||
|
.cycles = info & LBR_INFO_CYCLES,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return u.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_pt_add_lbrs(struct branch_stack *br_stack,
|
||||||
|
const struct intel_pt_blk_items *items)
|
||||||
|
{
|
||||||
|
u64 *to;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
br_stack->nr = 0;
|
||||||
|
|
||||||
|
to = &br_stack->entries[0].from;
|
||||||
|
|
||||||
|
for (i = INTEL_PT_LBR_0_POS; i <= INTEL_PT_LBR_2_POS; i++) {
|
||||||
|
u32 mask = items->mask[i];
|
||||||
|
const u64 *from = items->val[i];
|
||||||
|
|
||||||
|
for (; mask; mask >>= 3, from += 3) {
|
||||||
|
if ((mask & 7) == 7) {
|
||||||
|
*to++ = from[0];
|
||||||
|
*to++ = from[1];
|
||||||
|
*to++ = intel_pt_lbr_flags(from[2]);
|
||||||
|
br_stack->nr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INTEL_PT_LBR_0, INTEL_PT_LBR_1 and INTEL_PT_LBR_2 */
|
||||||
|
#define LBRS_MAX (INTEL_PT_BLK_ITEM_ID_CNT * 3)
|
||||||
|
|
||||||
static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
|
static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
|
||||||
{
|
{
|
||||||
const struct intel_pt_blk_items *items = &ptq->state->items;
|
const struct intel_pt_blk_items *items = &ptq->state->items;
|
||||||
@@ -1694,6 +1746,26 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
|
|||||||
intel_pt_add_xmm(&sample.intr_regs, pos, items, regs_mask);
|
intel_pt_add_xmm(&sample.intr_regs, pos, items, regs_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
|
||||||
|
struct {
|
||||||
|
struct branch_stack br_stack;
|
||||||
|
struct branch_entry entries[LBRS_MAX];
|
||||||
|
} br;
|
||||||
|
|
||||||
|
if (items->mask[INTEL_PT_LBR_0_POS] ||
|
||||||
|
items->mask[INTEL_PT_LBR_1_POS] ||
|
||||||
|
items->mask[INTEL_PT_LBR_2_POS]) {
|
||||||
|
intel_pt_add_lbrs(&br.br_stack, items);
|
||||||
|
sample.branch_stack = &br.br_stack;
|
||||||
|
} else if (pt->synth_opts.last_branch) {
|
||||||
|
intel_pt_copy_last_branch_rb(ptq);
|
||||||
|
sample.branch_stack = ptq->last_branch;
|
||||||
|
} else {
|
||||||
|
br.br_stack.nr = 0;
|
||||||
|
sample.branch_stack = &br.br_stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return intel_pt_deliver_synth_event(pt, ptq, event, &sample, sample_type);
|
return intel_pt_deliver_synth_event(pt, ptq, event, &sample, sample_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user