* [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY [not found] <CAP-5=fVzG-2oJ1gN=s-W+2r58k8P4M-E3r8aP9zJ2aK_w-K9vQ@mail.gmail.com> @ 2026-09-15 20:49 ` Chun-Tse Shao 2026-09-15 20:58 ` sashiko-bot 2026-09-16 13:57 ` Arnaldo Carvalho de Melo 0 siblings, 2 replies; 4+ messages in thread From: Chun-Tse Shao @ 2026-09-15 20:49 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: Ian Rogers, Namhyung Kim, Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, James Clark, Thomas Falcon, linux-kernel, linux-perf-users, Chun-Tse Shao It parses fdinfo with PMU type, comparing with the event which failed to open, and report the processes causing EBUSY error. Testing cycles and intel_pt// $ ./perf stat -e cycles & [1] 55569 $ ./perf stat -e intel_pt// & [2] 55683 $ ./perf stat -e intel_pt// Error: The PMU intel_pt counters are busy and in use by another process. Possible processes: 55683 ./perf stat -e intel_pt// Only perf with intel_pt was reported. Reviewed-by: Ian Rogers <irogers@google.com> Signed-off-by: Chun-Tse Shao <ctshao@google.com> Assisted-by: Gemini:gemini-3.1-pro-preview --- v9: - Rebased onto perf-tools-next --- tools/perf/util/evsel.c | 69 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b44fd880d2d5..f3f5519d0d3d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -4354,8 +4354,11 @@ static bool find_process(const char *name) return ret ? false : true; } -static int dump_perf_event_processes(char *msg, size_t size) +static int dump_perf_event_processes(const struct evsel *evsel, + char *msg, size_t size) { + const struct perf_event_attr *failed_attr = &evsel->core.attr; + u32 target_pmu_type = evsel->pmu ? evsel->pmu->type : UINT32_MAX; DIR *proc_dir; struct dirent *proc_entry; int printed = 0; @@ -4386,6 +4389,15 @@ static int dump_perf_event_processes(char *msg, size_t size) continue; } while ((fd_entry = readdir(fd_dir)) != NULL) { + const char *target_lnk = "anon_inode:[perf_event]"; + size_t target_lnk_len = sizeof("anon_inode:[perf_event]") - 1; + char fdinfo_buf[1024]; + int fdinfo_fd; + ssize_t fdinfo_size; + char *line; + char *saveptr; + u32 perf_event_type = UINT32_MAX; + u32 pmu_type = UINT32_MAX; ssize_t link_size; if (fd_entry->d_type != DT_LNK) @@ -4394,12 +4406,51 @@ static int dump_perf_event_processes(char *msg, size_t size) if (link_size < 0) continue; /* Take care as readlink doesn't null terminate the string. */ - if (!strncmp(buf, "anon_inode:[perf_event]", link_size)) { + if (link_size != (ssize_t)target_lnk_len || + strncmp(buf, target_lnk, target_lnk_len)) + continue; + + /* Let's check the PMU type reserved by this process */ + scnprintf(buf, sizeof(buf), "%s/fdinfo/%s", + proc_entry->d_name, fd_entry->d_name); + fdinfo_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); + if (fdinfo_fd == -1) + continue; + fdinfo_size = read(fdinfo_fd, fdinfo_buf, sizeof(fdinfo_buf) - 1); + close(fdinfo_fd); + if (fdinfo_size < 0) + continue; + fdinfo_buf[fdinfo_size] = '\0'; + + line = strtok_r(fdinfo_buf, "\n", &saveptr); + while (line) { + if (sscanf(line, + "perf_event_attr.type:\t%u", + &perf_event_type) == 1) { + /* continue parsing */ + } else if (sscanf(line, + "pmu_type:\t%u", + &pmu_type) == 1) { + /* continue parsing */ + } + line = strtok_r(NULL, "\n", &saveptr); + } + + /* Report the process which reserves the conflicted PMU. */ + /* If fdinfo does not contain PMU type, report it too. */ + if (perf_event_type == failed_attr->type || + pmu_type == failed_attr->type || + (target_pmu_type != UINT32_MAX && + pmu_type == target_pmu_type) || + (perf_event_type == UINT32_MAX && + pmu_type == UINT32_MAX)) { int cmdline_fd; ssize_t cmdline_size; - scnprintf(buf, sizeof(buf), "%s/cmdline", proc_entry->d_name); - cmdline_fd = openat(dirfd(proc_dir), buf, O_RDONLY); + scnprintf(buf, sizeof(buf), + "%s/cmdline", + proc_entry->d_name); + cmdline_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); if (cmdline_fd == -1) continue; cmdline_size = read(cmdline_fd, buf, sizeof(buf) - 1); @@ -4410,10 +4461,12 @@ static int dump_perf_event_processes(char *msg, size_t size) for (ssize_t i = 0; i < cmdline_size; i++) { if (buf[i] == '\0') buf[i] = ' '; + else if (!isprint((unsigned char)buf[i])) + buf[i] = '.'; } - if (printed == 0) - printed += scnprintf(msg, size, "Possible processes:\n"); + printed += scnprintf(msg, size, + "Possible processes:\n"); printed += scnprintf(msg + printed, size - printed, "%s %s\n", proc_entry->d_name, buf); @@ -4535,7 +4588,9 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, msg, size, "The PMU %s counters are busy and in use by another process.\n", evsel->pmu ? evsel->pmu->name : ""); - return printed + dump_perf_event_processes(msg + printed, size - printed); + return printed + dump_perf_event_processes(evsel, + msg + printed, + size - printed); break; case EINVAL: if (evsel->core.attr.sample_type & PERF_SAMPLE_CODE_PAGE_SIZE && perf_missing_features.code_page_size) -- 2.55.0.1032.g73a4cd73de-goog ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY 2026-09-15 20:49 ` [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY Chun-Tse Shao @ 2026-09-15 20:58 ` sashiko-bot 2026-09-16 14:02 ` Arnaldo Carvalho de Melo 2026-09-16 13:57 ` Arnaldo Carvalho de Melo 1 sibling, 1 reply; 4+ messages in thread From: sashiko-bot @ 2026-09-15 20:58 UTC (permalink / raw) To: Chun-Tse Shao; +Cc: linux-perf-users Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] perf: missing POSIX header inclusions for libc functions -- commit d5be35562f4cbefd7876eec8560215b17ee34b81 Author: Chun-Tse Shao <ctshao@google.com> perf evsel: Find process with busy PMUs for EBUSY This commit parses fdinfo with PMU type, comparing it with the event which failed to open, and reports the processes causing EBUSY errors. > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c > index d4cb455f4a7d4..e6d67d522ebf3 100644 > --- a/tools/perf/util/evsel.c > +++ b/tools/perf/util/evsel.c [ ... ] > @@ -4288,12 +4300,51 @@ static int dump_perf_event_processes(char *msg, size_t size) [ ... ] > + /* Let's check the PMU type reserved by this process */ > + scnprintf(buf, sizeof(buf), "%s/fdinfo/%s", > + proc_entry->d_name, fd_entry->d_name); > + fdinfo_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); [Severity: Low] Will this compile under musl libc without explicitly including <fcntl.h> for openat and O_NONBLOCK, as well as <unistd.h> for read and close? > + if (fdinfo_fd == -1) > + continue; > + fdinfo_size = read(fdinfo_fd, fdinfo_buf, sizeof(fdinfo_buf) - 1); > + close(fdinfo_fd); > + if (fdinfo_size < 0) > + continue; > + fdinfo_buf[fdinfo_size] = '\0'; > + > + line = strtok_r(fdinfo_buf, "\n", &saveptr); > + while (line) { > + if (sscanf(line, [Severity: Low] Does this require <stdio.h> to be explicitly included for sscanf to prevent musl libc build failures? > + "perf_event_attr.type:\t%u", > + &perf_event_type) == 1) { > + /* continue parsing */ > + } else if (sscanf(line, > + "pmu_type:\t%u", > + &pmu_type) == 1) { > + /* continue parsing */ > + } > + line = strtok_r(NULL, "\n", &saveptr); > + } [ ... ] > @@ -4304,10 +4355,12 @@ static int dump_perf_event_processes(char *msg, size_t size) > for (ssize_t i = 0; i < cmdline_size; i++) { > if (buf[i] == '\0') > buf[i] = ' '; > + else if (!isprint((unsigned char)buf[i])) [Severity: Low] Does this require <ctype.h> to be explicitly included for isprint to ensure compatibility with musl libc builds? > + buf[i] = '.'; > } -- Sashiko AI review · https://sashiko.dev/#/patchset/20260915204951.2935261-2-ctshao@google.com?part=1 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY 2026-09-15 20:58 ` sashiko-bot @ 2026-09-16 14:02 ` Arnaldo Carvalho de Melo 0 siblings, 0 replies; 4+ messages in thread From: Arnaldo Carvalho de Melo @ 2026-09-16 14:02 UTC (permalink / raw) To: sashiko-reviews; +Cc: Chun-Tse Shao, linux-perf-users On Tue, Sep 15, 2026 at 08:58:35PM +0000, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [Low] perf: missing POSIX header inclusions for libc functions > -- > commit d5be35562f4cbefd7876eec8560215b17ee34b81 > Author: Chun-Tse Shao <ctshao@google.com> > perf evsel: Find process with busy PMUs for EBUSY > This commit parses fdinfo with PMU type, comparing it with the event which > failed to open, and reports the processes causing EBUSY errors. > > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c > [ ... ] > > + /* Let's check the PMU type reserved by this process */ > > + scnprintf(buf, sizeof(buf), "%s/fdinfo/%s", > > + proc_entry->d_name, fd_entry->d_name); > > + fdinfo_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); > [Severity: Low] > Will this compile under musl libc without explicitly including <fcntl.h> for > openat and O_NONBLOCK, as well as <unistd.h> for read and close? Added while merging this patch... > [Severity: Low] > Does this require <stdio.h> to be explicitly included for sscanf to prevent > musl libc build failures? ... ditto ... > > + "perf_event_attr.type:\t%u", > > + &perf_event_type) == 1) { > > + /* continue parsing */ > > + } else if (sscanf(line, > > + "pmu_type:\t%u", > > + &pmu_type) == 1) { > > + /* continue parsing */ > > + } > > + line = strtok_r(NULL, "\n", &saveptr); > > + } > [ ... ] > > @@ -4304,10 +4355,12 @@ static int dump_perf_event_processes(char *msg, size_t size) > > for (ssize_t i = 0; i < cmdline_size; i++) { > > if (buf[i] == '\0') > > buf[i] = ' '; > > + else if (!isprint((unsigned char)buf[i])) > [Severity: Low] > Does this require <ctype.h> to be explicitly included for isprint to ensure > compatibility with musl libc builds? ⬢ [acme@tb-five-perf perf-tools-next]$ grep ctype tools/perf/util/evs evsel.c evsel_config.h evsel_fprintf.c evsel_fprintf.h evsel.h evswitch.c evswitch.h ⬢ [acme@tb-five-perf perf-tools-next]$ grep ctype tools/perf/util/evsel.c #include <linux/ctype.h> ⬢ [acme@tb-five-perf perf-tools-next]$ grep -w isprint tools/include/linux/ctype.h #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) ⬢ [acme@tb-five-perf perf-tools-next]$ We need to update review-prompts to cover this case. Anyway: Thanks, applied to perf-tools-next, for v7.4. - Arnaldo ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY 2026-09-15 20:49 ` [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY Chun-Tse Shao 2026-09-15 20:58 ` sashiko-bot @ 2026-09-16 13:57 ` Arnaldo Carvalho de Melo 1 sibling, 0 replies; 4+ messages in thread From: Arnaldo Carvalho de Melo @ 2026-09-16 13:57 UTC (permalink / raw) To: Chun-Tse Shao Cc: Ian Rogers, Namhyung Kim, Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter, James Clark, Thomas Falcon, linux-kernel, linux-perf-users On Tue, Sep 15, 2026 at 01:49:51PM -0700, Chun-Tse Shao wrote: > It parses fdinfo with PMU type, comparing with the event which failed to > open, and report the processes causing EBUSY error. > > Testing cycles and intel_pt// > > $ ./perf stat -e cycles & > [1] 55569 > $ ./perf stat -e intel_pt// & > [2] 55683 > $ ./perf stat -e intel_pt// > Error: > The PMU intel_pt counters are busy and in use by another process. > Possible processes: > 55683 ./perf stat -e intel_pt// > > Only perf with intel_pt was reported. I'll apply this after addressing Sashiko's comments about missing headers for building on musl libc systems, thanks. - Arnaldo > Reviewed-by: Ian Rogers <irogers@google.com> > Signed-off-by: Chun-Tse Shao <ctshao@google.com> > Assisted-by: Gemini:gemini-3.1-pro-preview > --- > v9: > - Rebased onto perf-tools-next > --- > tools/perf/util/evsel.c | 69 ++++++++++++++++++++++++++++++++++++----- > 1 file changed, 62 insertions(+), 7 deletions(-) > > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c > index b44fd880d2d5..f3f5519d0d3d 100644 > --- a/tools/perf/util/evsel.c > +++ b/tools/perf/util/evsel.c > @@ -4354,8 +4354,11 @@ static bool find_process(const char *name) > return ret ? false : true; > } > > -static int dump_perf_event_processes(char *msg, size_t size) > +static int dump_perf_event_processes(const struct evsel *evsel, > + char *msg, size_t size) > { > + const struct perf_event_attr *failed_attr = &evsel->core.attr; > + u32 target_pmu_type = evsel->pmu ? evsel->pmu->type : UINT32_MAX; > DIR *proc_dir; > struct dirent *proc_entry; > int printed = 0; > @@ -4386,6 +4389,15 @@ static int dump_perf_event_processes(char *msg, size_t size) > continue; > } > while ((fd_entry = readdir(fd_dir)) != NULL) { > + const char *target_lnk = "anon_inode:[perf_event]"; > + size_t target_lnk_len = sizeof("anon_inode:[perf_event]") - 1; > + char fdinfo_buf[1024]; > + int fdinfo_fd; > + ssize_t fdinfo_size; > + char *line; > + char *saveptr; > + u32 perf_event_type = UINT32_MAX; > + u32 pmu_type = UINT32_MAX; > ssize_t link_size; > > if (fd_entry->d_type != DT_LNK) > @@ -4394,12 +4406,51 @@ static int dump_perf_event_processes(char *msg, size_t size) > if (link_size < 0) > continue; > /* Take care as readlink doesn't null terminate the string. */ > - if (!strncmp(buf, "anon_inode:[perf_event]", link_size)) { > + if (link_size != (ssize_t)target_lnk_len || > + strncmp(buf, target_lnk, target_lnk_len)) > + continue; > + > + /* Let's check the PMU type reserved by this process */ > + scnprintf(buf, sizeof(buf), "%s/fdinfo/%s", > + proc_entry->d_name, fd_entry->d_name); > + fdinfo_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); > + if (fdinfo_fd == -1) > + continue; > + fdinfo_size = read(fdinfo_fd, fdinfo_buf, sizeof(fdinfo_buf) - 1); > + close(fdinfo_fd); > + if (fdinfo_size < 0) > + continue; > + fdinfo_buf[fdinfo_size] = '\0'; > + > + line = strtok_r(fdinfo_buf, "\n", &saveptr); > + while (line) { > + if (sscanf(line, > + "perf_event_attr.type:\t%u", > + &perf_event_type) == 1) { > + /* continue parsing */ > + } else if (sscanf(line, > + "pmu_type:\t%u", > + &pmu_type) == 1) { > + /* continue parsing */ > + } > + line = strtok_r(NULL, "\n", &saveptr); > + } > + > + /* Report the process which reserves the conflicted PMU. */ > + /* If fdinfo does not contain PMU type, report it too. */ > + if (perf_event_type == failed_attr->type || > + pmu_type == failed_attr->type || > + (target_pmu_type != UINT32_MAX && > + pmu_type == target_pmu_type) || > + (perf_event_type == UINT32_MAX && > + pmu_type == UINT32_MAX)) { > int cmdline_fd; > ssize_t cmdline_size; > > - scnprintf(buf, sizeof(buf), "%s/cmdline", proc_entry->d_name); > - cmdline_fd = openat(dirfd(proc_dir), buf, O_RDONLY); > + scnprintf(buf, sizeof(buf), > + "%s/cmdline", > + proc_entry->d_name); > + cmdline_fd = openat(dirfd(proc_dir), buf, O_RDONLY | O_NONBLOCK); > if (cmdline_fd == -1) > continue; > cmdline_size = read(cmdline_fd, buf, sizeof(buf) - 1); > @@ -4410,10 +4461,12 @@ static int dump_perf_event_processes(char *msg, size_t size) > for (ssize_t i = 0; i < cmdline_size; i++) { > if (buf[i] == '\0') > buf[i] = ' '; > + else if (!isprint((unsigned char)buf[i])) > + buf[i] = '.'; > } > - > if (printed == 0) > - printed += scnprintf(msg, size, "Possible processes:\n"); > + printed += scnprintf(msg, size, > + "Possible processes:\n"); > > printed += scnprintf(msg + printed, size - printed, > "%s %s\n", proc_entry->d_name, buf); > @@ -4535,7 +4588,9 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, > msg, size, > "The PMU %s counters are busy and in use by another process.\n", > evsel->pmu ? evsel->pmu->name : ""); > - return printed + dump_perf_event_processes(msg + printed, size - printed); > + return printed + dump_perf_event_processes(evsel, > + msg + printed, > + size - printed); > break; > case EINVAL: > if (evsel->core.attr.sample_type & PERF_SAMPLE_CODE_PAGE_SIZE && perf_missing_features.code_page_size) > -- > 2.55.0.1032.g73a4cd73de-goog ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-16 14:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CAP-5=fVzG-2oJ1gN=s-W+2r58k8P4M-E3r8aP9zJ2aK_w-K9vQ@mail.gmail.com>
2026-09-15 20:49 ` [PATCH v9] perf evsel: Find process with busy PMUs for EBUSY Chun-Tse Shao
2026-09-15 20:58 ` sashiko-bot
2026-09-16 14:02 ` Arnaldo Carvalho de Melo
2026-09-16 13:57 ` Arnaldo Carvalho de Melo
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.