aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-10-12 13:31:58 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-12 13:31:58 -0400
commitcfdc3170d214046b9509183fe9b9544dc644d40b (patch)
tree797a826c99120d092394d46a93d2bf50635b6e11
parent7c26701a77ec4569d9054b334d70724a06ad62f9 (diff)
sparc: Fix single-pcr perf event counter management.
It is important to clear the hw->state value for non-stopped events when they are added into the PMU. Otherwise when the event is scheduled out, we won't read the counter because HES_UPTODATE is still set. This breaks 'perf stat' and similar use cases, causing all the events to show zero. This worked for multi-pcr because we make explicit sparc_pmu_start() calls in calculate_multiple_pcrs(). calculate_single_pcr() doesn't do this because the idea there is to accumulate all of the counter settings into the single pcr value. So we have to add explicit hw->state handling there. Like x86, we use the PERF_HES_ARCH bit to track truly stopped events so that we don't accidently start them on a reload. Related to all of this, sparc_pmu_start() is missing a userpage update so add it. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/kernel/perf_event.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index d3149baaa33c..a4cc26bd89a2 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -927,6 +927,8 @@ static void read_in_all_counters(struct cpu_hw_events *cpuc)
927 sparc_perf_event_update(cp, &cp->hw, 927 sparc_perf_event_update(cp, &cp->hw,
928 cpuc->current_idx[i]); 928 cpuc->current_idx[i]);
929 cpuc->current_idx[i] = PIC_NO_INDEX; 929 cpuc->current_idx[i] = PIC_NO_INDEX;
930 if (cp->hw.state & PERF_HES_STOPPED)
931 cp->hw.state |= PERF_HES_ARCH;
930 } 932 }
931 } 933 }
932} 934}
@@ -959,10 +961,12 @@ static void calculate_single_pcr(struct cpu_hw_events *cpuc)
959 961
960 enc = perf_event_get_enc(cpuc->events[i]); 962 enc = perf_event_get_enc(cpuc->events[i]);
961 cpuc->pcr[0] &= ~mask_for_index(idx); 963 cpuc->pcr[0] &= ~mask_for_index(idx);
962 if (hwc->state & PERF_HES_STOPPED) 964 if (hwc->state & PERF_HES_ARCH) {
963 cpuc->pcr[0] |= nop_for_index(idx); 965 cpuc->pcr[0] |= nop_for_index(idx);
964 else 966 } else {
965 cpuc->pcr[0] |= event_encoding(enc, idx); 967 cpuc->pcr[0] |= event_encoding(enc, idx);
968 hwc->state = 0;
969 }
966 } 970 }
967out: 971out:
968 cpuc->pcr[0] |= cpuc->event[0]->hw.config_base; 972 cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
@@ -988,6 +992,9 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
988 992
989 cpuc->current_idx[i] = idx; 993 cpuc->current_idx[i] = idx;
990 994
995 if (cp->hw.state & PERF_HES_ARCH)
996 continue;
997
991 sparc_pmu_start(cp, PERF_EF_RELOAD); 998 sparc_pmu_start(cp, PERF_EF_RELOAD);
992 } 999 }
993out: 1000out:
@@ -1079,6 +1086,8 @@ static void sparc_pmu_start(struct perf_event *event, int flags)
1079 event->hw.state = 0; 1086 event->hw.state = 0;
1080 1087
1081 sparc_pmu_enable_event(cpuc, &event->hw, idx); 1088 sparc_pmu_enable_event(cpuc, &event->hw, idx);
1089
1090 perf_event_update_userpage(event);
1082} 1091}
1083 1092
1084static void sparc_pmu_stop(struct perf_event *event, int flags) 1093static void sparc_pmu_stop(struct perf_event *event, int flags)
@@ -1371,9 +1380,9 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags)
1371 cpuc->events[n0] = event->hw.event_base; 1380 cpuc->events[n0] = event->hw.event_base;
1372 cpuc->current_idx[n0] = PIC_NO_INDEX; 1381 cpuc->current_idx[n0] = PIC_NO_INDEX;
1373 1382
1374 event->hw.state = PERF_HES_UPTODATE; 1383 event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
1375 if (!(ef_flags & PERF_EF_START)) 1384 if (!(ef_flags & PERF_EF_START))
1376 event->hw.state |= PERF_HES_STOPPED; 1385 event->hw.state |= PERF_HES_ARCH;
1377 1386
1378 /* 1387 /*
1379 * If group events scheduling transaction was started, 1388 * If group events scheduling transaction was started,