From 6a81a3fd9e914581bb7fea383cad11445699762d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 21 Feb 2025 22:10:08 -0800 Subject: [PATCH] perf pmu: Switch to io_dir__readdir Avoid DIR allocations when scanning sysfs by using io_dir for the readdir implementation, that allocates about 1kb on the stack. Acked-by: Namhyung Kim Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250222061015.303622-4-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/pmu.c | 46 +++++++++++++++++------------------------- tools/perf/util/pmus.c | 30 ++++++++++----------------- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index ec3878c890a9..e51c17b1ea35 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -195,19 +196,17 @@ static void perf_pmu_format__load(const struct perf_pmu *pmu, struct perf_pmu_fo */ static int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load) { - struct dirent *evt_ent; - DIR *format_dir; + struct io_dirent64 *evt_ent; + struct io_dir format_dir; int ret = 0; - format_dir = fdopendir(dirfd); - if (!format_dir) - return -EINVAL; + io_dir__init(&format_dir, dirfd); - while ((evt_ent = readdir(format_dir)) != NULL) { + while ((evt_ent = io_dir__readdir(&format_dir)) != NULL) { struct perf_pmu_format *format; char *name = evt_ent->d_name; - if (!strcmp(name, ".") || !strcmp(name, "..")) + if (io_dir__is_dir(&format_dir, evt_ent)) continue; format = perf_pmu__new_format(&pmu->format, name); @@ -234,7 +233,7 @@ static int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_lo } } - closedir(format_dir); + close(format_dir.dirfd); return ret; } @@ -635,14 +634,12 @@ static inline bool pmu_alias_info_file(const char *name) */ static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd) { - struct dirent *evt_ent; - DIR *event_dir; + struct io_dirent64 *evt_ent; + struct io_dir event_dir; - event_dir = fdopendir(events_dir_fd); - if (!event_dir) - return -EINVAL; + io_dir__init(&event_dir, events_dir_fd); - while ((evt_ent = readdir(event_dir))) { + while ((evt_ent = io_dir__readdir(&event_dir))) { char *name = evt_ent->d_name; int fd; FILE *file; @@ -674,7 +671,6 @@ static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd) fclose(file); } - closedir(event_dir); pmu->sysfs_aliases_loaded = true; return 0; } @@ -2221,10 +2217,9 @@ static void perf_pmu__del_caps(struct perf_pmu *pmu) */ int perf_pmu__caps_parse(struct perf_pmu *pmu) { - struct stat st; char caps_path[PATH_MAX]; - DIR *caps_dir; - struct dirent *evt_ent; + struct io_dir caps_dir; + struct io_dirent64 *evt_ent; int caps_fd; if (pmu->caps_initialized) @@ -2235,24 +2230,21 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu) if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps")) return -1; - if (stat(caps_path, &st) < 0) { + caps_fd = open(caps_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY); + if (caps_fd == -1) { pmu->caps_initialized = true; return 0; /* no error if caps does not exist */ } - caps_dir = opendir(caps_path); - if (!caps_dir) - return -EINVAL; - - caps_fd = dirfd(caps_dir); + io_dir__init(&caps_dir, caps_fd); - while ((evt_ent = readdir(caps_dir)) != NULL) { + while ((evt_ent = io_dir__readdir(&caps_dir)) != NULL) { char *name = evt_ent->d_name; char value[128]; FILE *file; int fd; - if (!strcmp(name, ".") || !strcmp(name, "..")) + if (io_dir__is_dir(&caps_dir, evt_ent)) continue; fd = openat(caps_fd, name, O_RDONLY); @@ -2274,7 +2266,7 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu) fclose(file); } - closedir(caps_dir); + close(caps_fd); pmu->caps_initialized = true; return pmu->nr_caps; diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 8a0a919415d4..afd59d678fd0 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -3,10 +3,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -235,20 +235,16 @@ static void pmu_read_sysfs(unsigned int to_read_types) if (to_read_types & (PERF_TOOL_PMU_TYPE_PE_CORE_MASK | PERF_TOOL_PMU_TYPE_PE_OTHER_MASK)) { int fd = perf_pmu__event_source_devices_fd(); - DIR *dir; - struct dirent *dent; + struct io_dir dir; + struct io_dirent64 *dent; bool core_only = (to_read_types & PERF_TOOL_PMU_TYPE_PE_OTHER_MASK) == 0; if (fd < 0) goto skip_pe_pmus; - dir = fdopendir(fd); - if (!dir) { - close(fd); - goto skip_pe_pmus; - } + io_dir__init(&dir, fd); - while ((dent = readdir(dir))) { + while ((dent = io_dir__readdir(&dir)) != NULL) { if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; if (core_only && !is_pmu_core(dent->d_name)) @@ -257,7 +253,7 @@ static void pmu_read_sysfs(unsigned int to_read_types) perf_pmu__find2(fd, dent->d_name); } - closedir(dir); + close(fd); } skip_pe_pmus: if ((to_read_types & PERF_TOOL_PMU_TYPE_PE_CORE_MASK) && list_empty(&core_pmus)) { @@ -721,8 +717,8 @@ bool perf_pmus__supports_extended_type(void) char *perf_pmus__default_pmu_name(void) { int fd; - DIR *dir; - struct dirent *dent; + struct io_dir dir; + struct io_dirent64 *dent; char *result = NULL; if (!list_empty(&core_pmus)) @@ -732,13 +728,9 @@ char *perf_pmus__default_pmu_name(void) if (fd < 0) return strdup("cpu"); - dir = fdopendir(fd); - if (!dir) { - close(fd); - return strdup("cpu"); - } + io_dir__init(&dir, fd); - while ((dent = readdir(dir))) { + while ((dent = io_dir__readdir(&dir)) != NULL) { if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; if (is_pmu_core(dent->d_name)) { @@ -747,7 +739,7 @@ char *perf_pmus__default_pmu_name(void) } } - closedir(dir); + close(fd); return result ?: strdup("cpu"); } -- 2.50.1