From 548a880310f1178b114d9cb23ee0bd46d2fe63b2 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Wed, 18 Aug 2021 15:15:38 +0300 Subject: [PATCH] Userland: Cache stat in find(1) We have multiple commands that are implemented in terms of stat. Let's cache the stat in FileData after we query it once. This gives us another large speed-up :^) --- Userland/Utilities/find.cpp | 52 +++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/Userland/Utilities/find.cpp b/Userland/Utilities/find.cpp index c35ce10b58..4c071510e3 100644 --- a/Userland/Utilities/find.cpp +++ b/Userland/Utilities/find.cpp @@ -43,12 +43,33 @@ struct FileData { int dirfd { -1 }; // The file's basename, relative to the directory. const char* basename { nullptr }; + // Optionally, cached information as returned by stat/lstat/fstatat. + struct stat stat { + }; + bool stat_is_valid : 1 { false }; + + const struct stat* ensure_stat() + { + if (stat_is_valid) + return &stat; + + int flags = g_follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW; + int rc = fstatat(dirfd, basename, &stat, flags); + if (rc < 0) { + perror(full_path.string().characters()); + g_there_was_an_error = true; + return nullptr; + } + + stat_is_valid = true; + return &stat; + } }; class Command { public: virtual ~Command() { } - virtual bool evaluate(const FileData& file_data) const = 0; + virtual bool evaluate(FileData& file_data) const = 0; }; class StatCommand : public Command { @@ -56,17 +77,12 @@ public: virtual bool evaluate(const struct stat&) const = 0; private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { - struct stat stat; - int flags = g_follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW; - int rc = fstatat(file_data.dirfd, file_data.basename, &stat, flags); - if (rc < 0) { - perror(file_data.full_path.string().characters()); - g_there_was_an_error = true; + const struct stat* stat = file_data.ensure_stat(); + if (!stat) return false; - } - return evaluate(stat); + return evaluate(*stat); } }; @@ -213,7 +229,7 @@ public: } private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { return file_data.full_path.basename().matches(m_pattern, m_case_sensitivity); } @@ -230,7 +246,7 @@ public: } private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { out("{}{}", file_data.full_path, m_terminator); return true; @@ -247,7 +263,7 @@ public: } private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { pid_t pid = fork(); @@ -292,7 +308,7 @@ public: } private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { return m_lhs->evaluate(file_data) && m_rhs->evaluate(file_data); } @@ -310,7 +326,7 @@ public: } private: - virtual bool evaluate(const FileData& file_data) const override + virtual bool evaluate(FileData& file_data) const override { return m_lhs->evaluate(file_data) || m_rhs->evaluate(file_data); } @@ -457,7 +473,7 @@ static const char* parse_options(int argc, char* argv[]) } } -static void walk_tree(const FileData& root_data, Command& command) +static void walk_tree(FileData& root_data, Command& command) { command.evaluate(root_data); @@ -499,6 +515,8 @@ static void walk_tree(const FileData& root_data, Command& command) root_data.full_path.append(dirent->d_name), dirfd, dirent->d_name, + (struct stat) {}, + false, }; walk_tree(file_data, command); } @@ -527,6 +545,8 @@ int main(int argc, char* argv[]) root_path, dirfd, basename.characters(), + (struct stat) {}, + false, }; auto command = parse_all_commands(argv); walk_tree(file_data, *command);