aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
authorKrzysztof Łopatowski <krzysztof.m.lopatowski@gmail.com>2025-02-06 12:33:15 +0100
committerNamhyung Kim <namhyung@kernel.org>2025-02-19 13:55:59 -0800
commit4bac7fb5862740087825eda3ed6168e91da8b7e6 (patch)
tree8d58716be83fe1892389f1d868089a4fcf933022 /tools/perf
parent6353255e7cfab568058580424fa0967bf4504fe5 (diff)
downloadath-4bac7fb5862740087825eda3ed6168e91da8b7e6.tar.gz
perf tools: Improve startup time by reducing unnecessary stat() calls
When testing perf trace on NixOS, I noticed significant startup delays: - `ls`: ~2ms - `strace ls`: ~10ms - `perf trace ls`: ~550ms Profiling showed that 51% of the time is spent reading files, 26% in loading BPF programs, and 11% in `newfstatat`. This patch optimizes module path exploration by avoiding `stat()` calls unless necessary. For filesystems that do not implement `d_type` (DT_UNKNOWN), it falls back to the old behavior. See `readdir(3)` for details. This reduces `perf trace ls` time to ~500ms. A more thorough startup optimization based on command parameters would be ideal, but that is a larger effort. Signed-off-by: Krzysztof Łopatowski <krzysztof.m.lopatowski@gmail.com> Acked-by: Howard Chu <howardchu95@gmail.com> Link: https://lore.kernel.org/r/20250206113314.335376-2-krzysztof.m.lopatowski@gmail.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/machine.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index d96cbfd97ad8f..316f0879e5e08 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1339,7 +1339,7 @@ static int maps__set_module_path(struct maps *maps, const char *path, struct kmo
static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth)
{
- struct dirent *dent;
+ const struct dirent *dent;
DIR *dir = opendir(dir_name);
int ret = 0;
@@ -1350,14 +1350,20 @@ static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, i
while ((dent = readdir(dir)) != NULL) {
char path[PATH_MAX];
- struct stat st;
+ unsigned char d_type = dent->d_type;
- /*sshfs might return bad dent->d_type, so we have to stat*/
path__join(path, sizeof(path), dir_name, dent->d_name);
- if (stat(path, &st))
- continue;
- if (S_ISDIR(st.st_mode)) {
+ if (d_type == DT_UNKNOWN) {
+ struct stat st;
+
+ if (stat(path, &st))
+ continue;
+ if (S_ISDIR(st.st_mode))
+ d_type = DT_DIR;
+ }
+
+ if (d_type == DT_DIR) {
if (!strcmp(dent->d_name, ".") ||
!strcmp(dent->d_name, ".."))
continue;