[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250603181634.1362626-2-ctshao@google.com>
Date: Tue, 3 Jun 2025 11:15:54 -0700
From: Chun-Tse Shao <ctshao@...gle.com>
To: linux-kernel@...r.kernel.org
Cc: Chun-Tse Shao <ctshao@...gle.com>, Ian Rogers <irogers@...gle.com>, peterz@...radead.org,
mingo@...hat.com, acme@...nel.org, namhyung@...nel.org, mark.rutland@....com,
alexander.shishkin@...ux.intel.com, jolsa@...nel.org, adrian.hunter@...el.com,
kan.liang@...ux.intel.com, james.clark@...aro.org, howardchu95@...il.com,
weilin.wang@...el.com, linux-perf-users@...r.kernel.org
Subject: [PATCH v4 2/2] perf evsel: Find process with busy PMUs for EBUSY
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@...gle.com>
Signed-off-by: Chun-Tse Shao <ctshao@...gle.com>
---
v4:
Removed the first patch in v3 since it is merged.
Retested to make sure the patch still work.
v3: lore.kernel.org/20241106003007.2112584-3-ctshao@...gle.com/
tools/perf/util/evsel.c | 79 +++++++++++++++++++++++++++++------------
1 file changed, 57 insertions(+), 22 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d55482f094bf..fa281ea15a25 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -3619,7 +3619,8 @@ 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 perf_event_attr *failed_attr,
+ char *msg, size_t size)
{
DIR *proc_dir;
struct dirent *proc_entry;
@@ -3660,29 +3661,61 @@ static int dump_perf_event_processes(char *msg, size_t size)
continue;
/* Take care as readlink doesn't null terminate the string. */
if (!strncmp(buf, "anon_inode:[perf_event]", link_size)) {
- 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);
- if (cmdline_fd == -1)
- continue;
- cmdline_size = read(cmdline_fd, buf, sizeof(buf) - 1);
- close(cmdline_fd);
- if (cmdline_size < 0)
+ int fdinfo_fd;
+ ssize_t fdinfo_size;
+ char *line;
+ u32 perf_event_type = UINT32_MAX;
+
+ /* 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);
+ fdinfo_size = read(fdinfo_fd, buf, sizeof(buf) - 1);
+ if (fdinfo_size < 0)
continue;
- buf[cmdline_size] = '\0';
- for (ssize_t i = 0; i < cmdline_size; i++) {
- if (buf[i] == '\0')
- buf[i] = ' ';
+ buf[fdinfo_size] = '\0';
+
+ line = strtok(buf, "\n");
+ while (line != NULL) {
+ if (sscanf(line,
+ "perf_event_attr.type:\t%u",
+ &perf_event_type) == 1)
+ break;
+ line = strtok(NULL, "\n");
}
- if (printed == 0)
- printed += scnprintf(msg, size, "Possible processes:\n");
-
- printed += scnprintf(msg + printed, size - printed,
- "%s %s\n", proc_entry->d_name, buf);
- break;
+ /* 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 ||
+ perf_event_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);
+ if (cmdline_fd == -1)
+ continue;
+ cmdline_size = read(cmdline_fd, buf, sizeof(buf) - 1);
+ close(cmdline_fd);
+ if (cmdline_size < 0)
+ continue;
+ buf[cmdline_size] = '\0';
+ for (ssize_t i = 0; i < cmdline_size; i++) {
+ if (buf[i] == '\0')
+ buf[i] = ' ';
+ }
+
+ if (printed == 0)
+ printed += scnprintf(
+ msg, size,
+ "Possible processes:\n");
+
+ printed += scnprintf(msg + printed, size - printed,
+ "%s %s\n", proc_entry->d_name, buf);
+ break;
+ }
}
}
closedir(fd_dir);
@@ -3799,7 +3832,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->core.attr,
+ 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.49.0.1204.g71687c7c1d-goog
Powered by blists - more mailing lists