aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2012-04-02 14:19:11 -0400
committerIngo Molnar <mingo@kernel.org>2012-05-09 09:23:13 -0400
commitd47e8238cd76f1ffa7c8cd30e08b8e9074fd597e (patch)
treec172174db097b3afd7b36cc90a5b790e35a9f5f6 /arch
parent6accb9cf76080422d400a641d9068b6b2a2c216f (diff)
perf/x86-ibs: Take instruction pointer from ibs sample
Each IBS sample contains a linear address of the instruction that caused the sample to trigger. This address is more precise than the rip that was taken from the interrupt handler's stack. Update the rip with that address. We use this in the next patch to implement precise-event sampling on AMD systems using IBS. Signed-off-by: Robert Richter <robert.richter@amd.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1333390758-10893-6-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/perf_event.h6
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c48
2 files changed, 35 insertions, 19 deletions
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 8a3c75d824b7..4e40a64315c9 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -158,6 +158,7 @@ struct x86_pmu_capability {
158#define IBS_CAPS_OPCNT (1U<<4) 158#define IBS_CAPS_OPCNT (1U<<4)
159#define IBS_CAPS_BRNTRGT (1U<<5) 159#define IBS_CAPS_BRNTRGT (1U<<5)
160#define IBS_CAPS_OPCNTEXT (1U<<6) 160#define IBS_CAPS_OPCNTEXT (1U<<6)
161#define IBS_CAPS_RIPINVALIDCHK (1U<<7)
161 162
162#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \ 163#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
163 | IBS_CAPS_FETCHSAM \ 164 | IBS_CAPS_FETCHSAM \
@@ -170,14 +171,14 @@ struct x86_pmu_capability {
170#define IBSCTL_LVT_OFFSET_VALID (1ULL<<8) 171#define IBSCTL_LVT_OFFSET_VALID (1ULL<<8)
171#define IBSCTL_LVT_OFFSET_MASK 0x0F 172#define IBSCTL_LVT_OFFSET_MASK 0x0F
172 173
173/* IbsFetchCtl bits/masks */ 174/* ibs fetch bits/masks */
174#define IBS_FETCH_RAND_EN (1ULL<<57) 175#define IBS_FETCH_RAND_EN (1ULL<<57)
175#define IBS_FETCH_VAL (1ULL<<49) 176#define IBS_FETCH_VAL (1ULL<<49)
176#define IBS_FETCH_ENABLE (1ULL<<48) 177#define IBS_FETCH_ENABLE (1ULL<<48)
177#define IBS_FETCH_CNT 0xFFFF0000ULL 178#define IBS_FETCH_CNT 0xFFFF0000ULL
178#define IBS_FETCH_MAX_CNT 0x0000FFFFULL 179#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
179 180
180/* IbsOpCtl bits */ 181/* ibs op bits/masks */
181/* lower 4 bits of the current count are ignored: */ 182/* lower 4 bits of the current count are ignored: */
182#define IBS_OP_CUR_CNT (0xFFFF0ULL<<32) 183#define IBS_OP_CUR_CNT (0xFFFF0ULL<<32)
183#define IBS_OP_CNT_CTL (1ULL<<19) 184#define IBS_OP_CNT_CTL (1ULL<<19)
@@ -185,6 +186,7 @@ struct x86_pmu_capability {
185#define IBS_OP_ENABLE (1ULL<<17) 186#define IBS_OP_ENABLE (1ULL<<17)
186#define IBS_OP_MAX_CNT 0x0000FFFFULL 187#define IBS_OP_MAX_CNT 0x0000FFFFULL
187#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */ 188#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
189#define IBS_RIP_INVALID (1ULL<<38)
188 190
189extern u32 get_ibs_caps(void); 191extern u32 get_ibs_caps(void);
190 192
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index bc401bd9f14a..cc1f3293d6c2 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -9,6 +9,7 @@
9#include <linux/perf_event.h> 9#include <linux/perf_event.h>
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/pci.h> 11#include <linux/pci.h>
12#include <linux/ptrace.h>
12 13
13#include <asm/apic.h> 14#include <asm/apic.h>
14 15
@@ -382,7 +383,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
382 struct perf_raw_record raw; 383 struct perf_raw_record raw;
383 struct pt_regs regs; 384 struct pt_regs regs;
384 struct perf_ibs_data ibs_data; 385 struct perf_ibs_data ibs_data;
385 int offset, size, overflow, reenable; 386 int offset, size, check_rip, offset_max, throttle = 0;
386 unsigned int msr; 387 unsigned int msr;
387 u64 *buf, config; 388 u64 *buf, config;
388 389
@@ -413,28 +414,41 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
413 414
414 perf_ibs_event_update(perf_ibs, event, config); 415 perf_ibs_event_update(perf_ibs, event, config);
415 perf_sample_data_init(&data, 0, hwc->last_period); 416 perf_sample_data_init(&data, 0, hwc->last_period);
417 if (!perf_ibs_set_period(perf_ibs, hwc, &config))
418 goto out; /* no sw counter overflow */
419
420 ibs_data.caps = ibs_caps;
421 size = 1;
422 offset = 1;
423 check_rip = (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK));
424 if (event->attr.sample_type & PERF_SAMPLE_RAW)
425 offset_max = perf_ibs->offset_max;
426 else if (check_rip)
427 offset_max = 2;
428 else
429 offset_max = 1;
430 do {
431 rdmsrl(msr + offset, *buf++);
432 size++;
433 offset = find_next_bit(perf_ibs->offset_mask,
434 perf_ibs->offset_max,
435 offset + 1);
436 } while (offset < offset_max);
437 ibs_data.size = sizeof(u64) * size;
438
439 regs = *iregs;
440 if (!check_rip || !(ibs_data.regs[2] & IBS_RIP_INVALID))
441 instruction_pointer_set(&regs, ibs_data.regs[1]);
416 442
417 if (event->attr.sample_type & PERF_SAMPLE_RAW) { 443 if (event->attr.sample_type & PERF_SAMPLE_RAW) {
418 ibs_data.caps = ibs_caps; 444 raw.size = sizeof(u32) + ibs_data.size;
419 size = 1;
420 offset = 1;
421 do {
422 rdmsrl(msr + offset, *buf++);
423 size++;
424 offset = find_next_bit(perf_ibs->offset_mask,
425 perf_ibs->offset_max,
426 offset + 1);
427 } while (offset < perf_ibs->offset_max);
428 raw.size = sizeof(u32) + sizeof(u64) * size;
429 raw.data = ibs_data.data; 445 raw.data = ibs_data.data;
430 data.raw = &raw; 446 data.raw = &raw;
431 } 447 }
432 448
433 regs = *iregs; /* XXX: update ip from ibs sample */ 449 throttle = perf_event_overflow(event, &data, &regs);
434 450out:
435 overflow = perf_ibs_set_period(perf_ibs, hwc, &config); 451 config = (config >> 4) | (throttle ? 0 : perf_ibs->enable_mask);
436 reenable = !(overflow && perf_event_overflow(event, &data, &regs));
437 config = (config >> 4) | (reenable ? perf_ibs->enable_mask : 0);
438 perf_ibs_enable_event(hwc, config); 452 perf_ibs_enable_event(hwc, config);
439 453
440 perf_event_update_userpage(event); 454 perf_event_update_userpage(event);