perf hwmon_pmu: Switch event discovery to io_dir__readdir
authorIan Rogers <irogers@google.com>
Sat, 22 Feb 2025 06:10:12 +0000 (22:10 -0800)
committerNamhyung Kim <namhyung@kernel.org>
Mon, 24 Feb 2025 23:46:33 +0000 (15:46 -0800)
Avoid DIR allocations when scanning sysfs by using io_dir for the
readdir implementation, that allocates about 1kb on the stack.

Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250222061015.303622-8-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/hwmon_pmu.c

index acd889b2462f61bd7fcfd14cbfe3a433c283df57..3cce77fc80041d9b8aeddbb81e1e5e77292790f1 100644 (file)
 #include <sys/types.h>
 #include <assert.h>
 #include <ctype.h>
-#include <dirent.h>
 #include <fcntl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <api/fs/fs.h>
 #include <api/io.h>
+#include <api/io_dir.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/zalloc.h>
@@ -235,31 +235,22 @@ static void fix_name(char *p)
 
 static int hwmon_pmu__read_events(struct hwmon_pmu *pmu)
 {
-       DIR *dir;
-       struct dirent *ent;
-       int dup_fd, err = 0;
+       int err = 0;
        struct hashmap_entry *cur, *tmp;
        size_t bkt;
+       struct io_dirent64 *ent;
+       struct io_dir dir;
 
        if (pmu->pmu.sysfs_aliases_loaded)
                return 0;
 
-       /*
-        * Use a dup-ed fd as closedir will close it. Use openat so that the
-        * directory contents are refreshed.
-        */
-       dup_fd = openat(pmu->hwmon_dir_fd, ".", O_DIRECTORY);
+       /* Use openat so that the directory contents are refreshed. */
+       io_dir__init(&dir, openat(pmu->hwmon_dir_fd, ".", O_CLOEXEC | O_DIRECTORY | O_RDONLY));
 
-       if (dup_fd == -1)
-               return -ENOMEM;
+       if (dir.dirfd < 0)
+               return -ENOENT;
 
-       dir = fdopendir(dup_fd);
-       if (!dir) {
-               close(dup_fd);
-               return -ENOMEM;
-       }
-
-       while ((ent = readdir(dir)) != NULL) {
+       while ((ent = io_dir__readdir(&dir)) != NULL) {
                enum hwmon_type type;
                int number;
                enum hwmon_item item;
@@ -347,7 +338,7 @@ static int hwmon_pmu__read_events(struct hwmon_pmu *pmu)
        pmu->pmu.sysfs_aliases_loaded = true;
 
 err_out:
-       closedir(dir);
+       close(dir.dirfd);
        return err;
 }
 
@@ -702,8 +693,8 @@ int hwmon_pmu__check_alias(struct parse_events_terms *terms, struct perf_pmu_inf
 int perf_pmus__read_hwmon_pmus(struct list_head *pmus)
 {
        char *line = NULL;
-       DIR *class_hwmon_dir;
-       struct dirent *class_hwmon_ent;
+       struct io_dirent64 *class_hwmon_ent;
+       struct io_dir class_hwmon_dir;
        char buf[PATH_MAX];
        const char *sysfs = sysfs__mountpoint();
 
@@ -711,11 +702,12 @@ int perf_pmus__read_hwmon_pmus(struct list_head *pmus)
                return 0;
 
        scnprintf(buf, sizeof(buf), "%s/class/hwmon/", sysfs);
-       class_hwmon_dir = opendir(buf);
-       if (!class_hwmon_dir)
+       io_dir__init(&class_hwmon_dir, open(buf, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
+
+       if (class_hwmon_dir.dirfd < 0)
                return 0;
 
-       while ((class_hwmon_ent = readdir(class_hwmon_dir)) != NULL) {
+       while ((class_hwmon_ent = io_dir__readdir(&class_hwmon_dir)) != NULL) {
                size_t line_len;
                int hwmon_dir, name_fd;
                struct io io;
@@ -745,7 +737,7 @@ int perf_pmus__read_hwmon_pmus(struct list_head *pmus)
                close(name_fd);
        }
        free(line);
-       closedir(class_hwmon_dir);
+       close(class_hwmon_dir.dirfd);
        return 0;
 }