From: "Liang, Kan" <kan.liang@linux.intel.com>
To: Namhyung Kim <namhyung@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
LKML <linux-kernel@vger.kernel.org>,
Stephane Eranian <eranian@google.com>,
stable@vger.kernel.org
Subject: Re: [PATCH] perf/x86: Fix out of range data
Date: Sat, 16 Dec 2023 07:42:45 -0500 [thread overview]
Message-ID: <ae648bc4-b32c-4b15-8dfc-9dbd481bb927@linux.intel.com> (raw)
In-Reply-To: <20231216072830.1009339-1-namhyung@kernel.org>
On 2023-12-16 2:28 a.m., Namhyung Kim wrote:
> On x86 each cpu_hw_events maintains a table for counter assignment but
> it missed to update one for the deleted event in x86_pmu_del(). This
> can make perf_clear_dirty_counters() reset used counter if it's called
> before event scheduling or enabling. Then it would return out of range
> data which doesn't make sense.
>
> The following code can reproduce the problem.
>
> $ cat repro.c
> #include <pthread.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <linux/perf_event.h>
> #include <sys/ioctl.h>
> #include <sys/mman.h>
> #include <sys/syscall.h>
>
> struct perf_event_attr attr = {
> .type = PERF_TYPE_HARDWARE,
> .config = PERF_COUNT_HW_CPU_CYCLES,
> .disabled = 1,
> };
>
> void *worker(void *arg)
> {
> int cpu = (long)arg;
> int fd1 = syscall(SYS_perf_event_open, &attr, -1, cpu, -1, 0);
> int fd2 = syscall(SYS_perf_event_open, &attr, -1, cpu, -1, 0);
> void *p;
>
> do {
> ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
> p = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd1, 0);
> ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
>
> ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
> munmap(p, 4096);
> ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
> } while (1);
>
> return NULL;
> }
>
> int main(void)
> {
> int i;
> int n = sysconf(_SC_NPROCESSORS_ONLN);
> pthread_t *th = calloc(n, sizeof(*th));
>
> for (i = 0; i < n; i++)
> pthread_create(&th[i], NULL, worker, (void *)(long)i);
> for (i = 0; i < n; i++)
> pthread_join(th[i], NULL);
>
> free(th);
> return 0;
> }
>
> And you can see the out of range data using perf stat like this.
> Probably it'd be easier to see on a large machine.
>
> $ gcc -o repro repro.c -pthread
> $ ./repro &
> $ sudo perf stat -A -I 1000 2>&1 | awk '{ if (length($3) > 15) print }'
> 1.001028462 CPU6 196,719,295,683,763 cycles # 194290.996 GHz (71.54%)
> 1.001028462 CPU3 396,077,485,787,730 branch-misses # 15804359784.80% of all branches (71.07%)
> 1.001028462 CPU17 197,608,350,727,877 branch-misses # 14594186554.56% of all branches (71.22%)
> 2.020064073 CPU4 198,372,472,612,140 cycles # 194681.113 GHz (70.95%)
> 2.020064073 CPU6 199,419,277,896,696 cycles # 195720.007 GHz (70.57%)
> 2.020064073 CPU20 198,147,174,025,639 cycles # 194474.654 GHz (71.03%)
> 2.020064073 CPU20 198,421,240,580,145 stalled-cycles-frontend # 100.14% frontend cycles idle (70.93%)
> 3.037443155 CPU4 197,382,689,923,416 cycles # 194043.065 GHz (71.30%)
> 3.037443155 CPU20 196,324,797,879,414 cycles # 193003.773 GHz (71.69%)
> 3.037443155 CPU5 197,679,956,608,205 stalled-cycles-backend # 1315606428.66% backend cycles idle (71.19%)
> 3.037443155 CPU5 198,571,860,474,851 instructions # 13215422.58 insn per cycle
>
> It should move the contents in the cpuc->assign as well.
Yes, the patch looks good to me.
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Thanks,
Kan
>
> Fixes: 5471eea5d3bf ("perf/x86: Reset the dirty counter to prevent the leak for an RDPMC task")
> Cc: Kan Liang <kan.liang@linux.intel.com>
> Cc: stable@vger.kernel.org
> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> ---
> arch/x86/events/core.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
> index 09050641ce5d..5b0dd07b1ef1 100644
> --- a/arch/x86/events/core.c
> +++ b/arch/x86/events/core.c
> @@ -1644,6 +1644,7 @@ static void x86_pmu_del(struct perf_event *event, int flags)
> while (++i < cpuc->n_events) {
> cpuc->event_list[i-1] = cpuc->event_list[i];
> cpuc->event_constraint[i-1] = cpuc->event_constraint[i];
> + cpuc->assign[i-1] = cpuc->assign[i];
> }
> cpuc->event_constraint[i-1] = NULL;
> --cpuc->n_events;
next prev parent reply other threads:[~2023-12-16 12:42 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-16 7:28 [PATCH] perf/x86: Fix out of range data Namhyung Kim
2023-12-16 12:42 ` Liang, Kan [this message]
2024-01-09 21:28 ` Namhyung Kim
2024-02-06 21:19 ` Namhyung Kim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ae648bc4-b32c-4b15-8dfc-9dbd481bb927@linux.intel.com \
--to=kan.liang@linux.intel.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=eranian@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox