Reduce startup time on Windows by using std::filesystem::canonical

realpath() apparently doesn't handle Windows symlinks very well. This
causes plugin::Manager and ScannedFile to rescan a bunch of extra
paths that they should be skipping. This commit reduces the startup
time on Windows by 3-4 seconds (~8.5s to ~5s).
This commit is contained in:
Tim Wojtulewicz 2023-01-18 13:10:33 -07:00 committed by Tim Wojtulewicz
parent d6ce5894a7
commit db161bd6df
4 changed files with 17 additions and 14 deletions

View file

@ -21,14 +21,13 @@ ScannedFile::ScannedFile(int arg_include_level, std::string arg_name, bool arg_s
canonical_path = canonical_stdin_path; canonical_path = canonical_stdin_path;
else else
{ {
char buf[PATH_MAX]; std::error_code ec;
auto res = realpath(name.data(), buf); auto canon = filesystem::canonical(name, ec);
if ( ec )
zeek::reporter->FatalError("failed to get canonical path of %s: %s", name.data(),
ec.message().c_str());
if ( ! res ) canonical_path = canon.string();
zeek::reporter->FatalError("failed to get realpath() of %s: %s", name.data(),
strerror(errno));
canonical_path = res;
} }
} }

View file

@ -12,7 +12,7 @@ namespace zeek::detail
{ {
// Script file we have already scanned (or are in the process of scanning). // Script file we have already scanned (or are in the process of scanning).
// They are identified by normalized realpath. // They are identified by normalized canonical path.
class ScannedFile class ScannedFile
{ {
@ -30,7 +30,7 @@ public:
bool skipped; // This ScannedFile was @unload'd. bool skipped; // This ScannedFile was @unload'd.
bool prefixes_checked; // If loading prefixes for this file has been tried. bool prefixes_checked; // If loading prefixes for this file has been tried.
std::string name; std::string name;
std::string canonical_path; // normalized, absolute path via realpath() std::string canonical_path; // normalized, absolute path via std::filesystem::canonical()
static auto constexpr canonical_stdin_path = "<stdin>"; static auto constexpr canonical_stdin_path = "<stdin>";
}; };

View file

@ -76,14 +76,17 @@ void Manager::SearchDynamicPlugins(const std::string& dir)
return; return;
} }
char canon_path[PATH_MAX]; std::error_code ec;
if ( ! realpath(dir.data(), canon_path) ) auto canon = filesystem::canonical(dir, ec);
if ( ec )
{ {
DBG_LOG(DBG_PLUGINS, "skip dynamic plugin search in %s, realpath failed: %s", dir.data(), DBG_LOG(DBG_PLUGINS, "skip dynamic plugin search in %s, making path canonical failed: %s",
strerror(errno)); dir.data(), ec.message().c_str());
return; return;
} }
std::string canon_path = canon.string();
if ( searched_dirs.count(canon_path) ) if ( searched_dirs.count(canon_path) )
return; return;

View file

@ -482,7 +482,8 @@ private:
// Directories that have already been searched for dynamic plugins. // Directories that have already been searched for dynamic plugins.
// Used to prevent multiple searches of the same dirs (e.g. via symlinks). // Used to prevent multiple searches of the same dirs (e.g. via symlinks).
// The paths stored in the set are made canonical via realpath(). // The paths stored in the set are made canonical via calls to
// std::filesystem::canonical().
std::set<std::string, std::less<>> searched_dirs; std::set<std::string, std::less<>> searched_dirs;
// Plugins that were explicitly requested to be activated, but failed to // Plugins that were explicitly requested to be activated, but failed to