diff options
author | David S. Miller <davem@davemloft.net> | 2018-10-12 13:31:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-12 13:31:58 -0400 |
commit | cfdc3170d214046b9509183fe9b9544dc644d40b (patch) | |
tree | 797a826c99120d092394d46a93d2bf50635b6e11 | |
parent | 7c26701a77ec4569d9054b334d70724a06ad62f9 (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.c | 17 |
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 | } |
967 | out: | 971 | out: |
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 | } |
993 | out: | 1000 | out: |
@@ -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 | ||
1084 | static void sparc_pmu_stop(struct perf_event *event, int flags) | 1093 | static 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, |