powerpc/perf: Use pmc_overflow() to detect rolled back events
authorSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Tue, 7 Aug 2012 15:07:19 +0000 (15:07 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 24 Aug 2012 10:26:10 +0000 (20:26 +1000)
For certain speculative events on Power7, 'perf stat' reports far higher
event count than 'perf record' for the same event.

As described in following commit, a performance monitor exception is raised
even when the the performance events are rolled back.

        commit 0837e3242c73566fc1c0196b4ec61779c25ffc93
        Author: Anton Blanchard <anton@samba.org>
        Date:   Wed Mar 9 14:38:42 2011 +1100

perf_event_interrupt() records an event only when an overflow occurs. But
this check for overflow is a simple 'if (val < 0)'.

Because the events are rolled back, this check for overflow fails and the
event is not recorded. perf_event_interrupt() later uses pmc_overflow() to
detect the overflow and resets the counters and the events are lost completely.

To properly detect the overflow of rolled back events, use pmc_overflow()
even when recording events.

To reproduce:
        $ cat strcpy.c
        #include <stdio.h>
        #include <string.h>
        main()
        {
                char buf[256];

                alarm(5);
                while(1)
                        strcpy(buf, "string1");
        }

        $ perf record -e r20014 ./strcpy
        $ perf report -n > report.1
        $ perf stat -e r20014 > report.2
        # Compare report.1 and report.2

Reported-by: Maynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/perf/core-book3s.c

index 77b49ddda9d3675ed816d65af7f8c242578c01a0..7cd2dbd6e4c4fa615ae4442c5d00af106f3e17dd 100644 (file)
@@ -1431,7 +1431,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
                if (!event->hw.idx || is_limited_pmc(event->hw.idx))
                        continue;
                val = read_pmc(event->hw.idx);
-               if ((int)val < 0) {
+               if (pmc_overflow(val)) {
                        /* event has overflowed */
                        found = 1;
                        record_and_restart(event, val, regs);