From 15fab56ecae2cba7e9f6663979bb160c11a9c506 Mon Sep 17 00:00:00 2001 From: Chris Freehill Date: Wed, 5 Dec 2012 12:32:46 +0000 Subject: powerpc/perf: Add stalled-cycles events Support for stalled-cycles-frontend and stalled-cycles-backend is added for e500-based processors. The following mappings are used: stalled-cycles-frontend or idle-cycles-frontend: Com:18 Cycles decode stalled stalled-cycles-backend or idle-cycles-backend Com:19 cycles issue stalled Signed-off-by: Chris Freehill Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/perf/e500-pmu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/perf') diff --git a/arch/powerpc/perf/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c index cb2e2949c8d1..fb664929f5da 100644 --- a/arch/powerpc/perf/e500-pmu.c +++ b/arch/powerpc/perf/e500-pmu.c @@ -24,6 +24,8 @@ static int e500_generic_events[] = { [PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12, [PERF_COUNT_HW_BRANCH_MISSES] = 15, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 18, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 19, }; #define C(x) PERF_COUNT_HW_CACHE_##x -- cgit v1.2.3 From bc09c219b2e6f9436d06a1a3a10eff97faab371c Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 5 Nov 2012 15:53:54 +0000 Subject: powerpc/perf: Fix finding overflowed PMC in interrupt If a PMC is about to overflow on a counter that's on an active perf event (ie. less than 256 from the end) and a _different_ PMC overflows just at this time (a PMC that's not on an active perf event), we currently mark the event as found, but in reality it's not as it's likely the other PMC that caused the IRQ. Since we mark it as found the second catch all for overflows doesn't run, and we don't reset the overflowing PMC ever. Hence we keep hitting that same PMC IRQ over and over and don't reset the actual overflowing counter. This is a rewrite of the perf interrupt handler for book3s to get around this. We now check to see if any of the PMCs have actually overflowed (ie >= 0x80000000). If yes, record it for active counters and just reset it for inactive counters. If it's not overflowed, then we check to see if it's one of the buggy power7 counters and if it is, record it and continue. If none of the PMCs match this, then we make note that we couldn't find the PMC that caused the IRQ. Signed-off-by: Michael Neuling Reviewed-by: Sukadev Bhattiprolu cc: Paul Mackerras cc: Anton Blanchard cc: Linux PPC dev Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/perf/core-book3s.c | 83 +++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 29 deletions(-) (limited to 'arch/powerpc/perf') diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index aa2465e21f1a..53fc7b8e5d9a 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -1412,11 +1412,8 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) return regs->nip; } -static bool pmc_overflow(unsigned long val) +static bool pmc_overflow_power7(unsigned long val) { - if ((int)val < 0) - return true; - /* * Events on POWER7 can roll back if a speculative event doesn't * eventually complete. Unfortunately in some rare cases they will @@ -1428,7 +1425,15 @@ static bool pmc_overflow(unsigned long val) * PMCs because a user might set a period of less than 256 and we * don't want to mistakenly reset them. */ - if (pvr_version_is(PVR_POWER7) && ((0x80000000 - val) <= 256)) + if ((0x80000000 - val) <= 256) + return true; + + return false; +} + +static bool pmc_overflow(unsigned long val) +{ + if ((int)val < 0) return true; return false; @@ -1439,11 +1444,11 @@ static bool pmc_overflow(unsigned long val) */ static void perf_event_interrupt(struct pt_regs *regs) { - int i; + int i, j; struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); struct perf_event *event; - unsigned long val; - int found = 0; + unsigned long val[8]; + int found, active; int nmi; if (cpuhw->n_limited) @@ -1458,33 +1463,53 @@ static void perf_event_interrupt(struct pt_regs *regs) else irq_enter(); - for (i = 0; i < cpuhw->n_events; ++i) { - event = cpuhw->event[i]; - if (!event->hw.idx || is_limited_pmc(event->hw.idx)) + /* Read all the PMCs since we'll need them a bunch of times */ + for (i = 0; i < ppmu->n_counter; ++i) + val[i] = read_pmc(i + 1); + + /* Try to find what caused the IRQ */ + found = 0; + for (i = 0; i < ppmu->n_counter; ++i) { + if (!pmc_overflow(val[i])) continue; - val = read_pmc(event->hw.idx); - if ((int)val < 0) { - /* event has overflowed */ - found = 1; - record_and_restart(event, val, regs); + if (is_limited_pmc(i + 1)) + continue; /* these won't generate IRQs */ + /* + * We've found one that's overflowed. For active + * counters we need to log this. For inactive + * counters, we need to reset it anyway + */ + found = 1; + active = 0; + for (j = 0; j < cpuhw->n_events; ++j) { + event = cpuhw->event[j]; + if (event->hw.idx == (i + 1)) { + active = 1; + record_and_restart(event, val[i], regs); + break; + } } + if (!active) + /* reset non active counters that have overflowed */ + write_pmc(i + 1, 0); } - - /* - * In case we didn't find and reset the event that caused - * the interrupt, scan all events and reset any that are - * negative, to avoid getting continual interrupts. - * Any that we processed in the previous loop will not be negative. - */ - if (!found) { - for (i = 0; i < ppmu->n_counter; ++i) { - if (is_limited_pmc(i + 1)) + if (!found && pvr_version_is(PVR_POWER7)) { + /* check active counters for special buggy p7 overflow */ + for (i = 0; i < cpuhw->n_events; ++i) { + event = cpuhw->event[i]; + if (!event->hw.idx || is_limited_pmc(event->hw.idx)) continue; - val = read_pmc(i + 1); - if (pmc_overflow(val)) - write_pmc(i + 1, 0); + if (pmc_overflow_power7(val[event->hw.idx - 1])) { + /* event has overflowed in a buggy way*/ + found = 1; + record_and_restart(event, + val[event->hw.idx - 1], + regs); + } } } + if ((!found) && printk_ratelimit()) + printk(KERN_WARNING "Can't find PMC that caused IRQ\n"); /* * Reset MMCR0 to its normal value. This will set PMXE and -- cgit v1.2.3 From e13e895f8430d8c8b7a51478a4abd481bf9b64fb Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 5 Nov 2012 15:08:38 +0000 Subject: powerpc/perf: Fix for PMCs not making progress On POWER7 when we have really small counts left before overflow, we can take a PMU IRQ, but the PMC gets wound back to just before the overflow. If the kernel is setting the PMC to a value just before the overflow, we can get interrupted again without the PMC making any progress (ie another buggy overflow). In this case, we can end up making no forward progress, with the PMC interrupt returning us to the same count over and over. The below detects when we are making no forward progress (ie. delta = 0) and then increases the amount left before the overflow. This stops us from locking up. Signed-off-by: Michael Neuling Reviewed-by: Sukadev Bhattiprolu cc: Paul Mackerras cc: Anton Blanchard cc: Linux PPC dev Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/perf/core-book3s.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/perf') diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 53fc7b8e5d9a..89bd59365c07 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -1349,6 +1349,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val, */ val = 0; left = local64_read(&event->hw.period_left) - delta; + if (delta == 0) + left++; if (period) { if (left <= 0) { left += period; -- cgit v1.2.3 From f53d168c025f27d64417a56bf129dbb39d2e1189 Mon Sep 17 00:00:00 2001 From: "sukadev@linux.vnet.ibm.com" Date: Thu, 24 Jan 2013 13:25:23 +0000 Subject: perf/Power: PERF_EVENT_IOC_ENABLE does not reenable event perf/Power: PERF_EVENT_IOC_ENABLE does not reenable event If we disable a perf event because we exceeded the specified ->event_limit, power_pmu_stop() sets the PERF_HES_STOPPED flag on the event. If the application then re-enables the event using PERF_EVENT_IOC_ENABLE ioctl, we don't ever clear this STOPPED flag. Consequently, the user space is never notified of the event. Following message has more background and test case. http://lists.eecs.utk.edu/pipermail/ptools-perfapi/2012-October/002528.html Used the following test cases to verify that this patch works on latest PAPI. $ papi.git/src/ctests/nonthread PAPI_TOT_CYC@5000000 $ papi.git/src/ctests/overflow_single_event Changelog[v2]: - [Paul Mackerras] Also clear PERF_HES_UPTODATE flag since we are restarting the event; cleanup comments and patch description. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/perf/core-book3s.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch/powerpc/perf') diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 89bd59365c07..069f92b31992 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -880,8 +880,16 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) cpuhw->events[n0] = event->hw.config; cpuhw->flags[n0] = event->hw.event_base; + /* + * This event may have been disabled/stopped in record_and_restart() + * because we exceeded the ->event_limit. If re-starting the event, + * clear the ->hw.state (STOPPED and UPTODATE flags), so the user + * notification is re-enabled. + */ if (!(ef_flags & PERF_EF_START)) event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE; + else + event->hw.state = 0; /* * If group events scheduling transaction was started, -- cgit v1.2.3