Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 304888
b: refs/heads/master
c: 450bbd4
h: refs/heads/master
v: v3
  • Loading branch information
Robert Richter authored and Ingo Molnar committed May 9, 2012
1 parent 26fe21c commit 7a7e1fc
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d47e8238cd76f1ffa7c8cd30e08b8e9074fd597e
refs/heads/master: 450bbd493d436f9eadd1b7828158f37559f26674
7 changes: 6 additions & 1 deletion trunk/arch/x86/kernel/cpu/perf_event_amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,13 @@ static u64 amd_pmu_event_map(int hw_event)

static int amd_pmu_hw_config(struct perf_event *event)
{
int ret = x86_pmu_hw_config(event);
int ret;

/* pass precise event sampling to ibs: */
if (event->attr.precise_ip && get_ibs_caps())
return -ENOENT;

ret = x86_pmu_hw_config(event);
if (ret)
return ret;

Expand Down
73 changes: 70 additions & 3 deletions trunk/arch/x86/kernel/cpu/perf_event_amd_ibs.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,80 @@ static struct perf_ibs *get_ibs_pmu(int type)
return NULL;
}

/*
* Use IBS for precise event sampling:
*
* perf record -a -e cpu-cycles:p ... # use ibs op counting cycle count
* perf record -a -e r076:p ... # same as -e cpu-cycles:p
* perf record -a -e r0C1:p ... # use ibs op counting micro-ops
*
* IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
* MSRC001_1033) is used to select either cycle or micro-ops counting
* mode.
*
* The rip of IBS samples has skid 0. Thus, IBS supports precise
* levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
* rip is invalid when IBS was not able to record the rip correctly.
* We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
*
*/
static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
{
switch (event->attr.precise_ip) {
case 0:
return -ENOENT;
case 1:
case 2:
break;
default:
return -EOPNOTSUPP;
}

switch (event->attr.type) {
case PERF_TYPE_HARDWARE:
switch (event->attr.config) {
case PERF_COUNT_HW_CPU_CYCLES:
*config = 0;
return 0;
}
break;
case PERF_TYPE_RAW:
switch (event->attr.config) {
case 0x0076:
*config = 0;
return 0;
case 0x00C1:
*config = IBS_OP_CNT_CTL;
return 0;
}
break;
default:
return -ENOENT;
}

return -EOPNOTSUPP;
}

static int perf_ibs_init(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
struct perf_ibs *perf_ibs;
u64 max_cnt, config;
int ret;

perf_ibs = get_ibs_pmu(event->attr.type);
if (!perf_ibs)
if (perf_ibs) {
config = event->attr.config;
} else {
perf_ibs = &perf_ibs_op;
ret = perf_ibs_precise_event(event, &config);
if (ret)
return ret;
}

if (event->pmu != &perf_ibs->pmu)
return -ENOENT;

config = event->attr.config;
if (config & ~perf_ibs->config_mask)
return -EINVAL;

Expand Down Expand Up @@ -437,8 +500,12 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
ibs_data.size = sizeof(u64) * size;

regs = *iregs;
if (!check_rip || !(ibs_data.regs[2] & IBS_RIP_INVALID))
if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
regs.flags &= ~PERF_EFLAGS_EXACT;
} else {
instruction_pointer_set(&regs, ibs_data.regs[1]);
regs.flags |= PERF_EFLAGS_EXACT;
}

if (event->attr.sample_type & PERF_SAMPLE_RAW) {
raw.size = sizeof(u32) + ibs_data.size;
Expand Down

0 comments on commit 7a7e1fc

Please sign in to comment.