mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-30 18:29:37 -06:00
cmFileSet: Fix poor performance of large file sets with export() on Windows
Exporting targets having large FILE_SETs with install(EXPORT) or export(EXPORT) currently performs poorly on Windows compared to Unix-like systems, because cmFileSet::EvaluateDirectoryEntries calls SystemTools::SameFile on every pair of parent directories in the file set. SystemTools::SameFile opens and closes two read-only filesystem handles. This causes a significant performance drop on Windows for FILE_SETs with even a couple of dozens of files. Use the recently added SystemTools::GetFileId function in kwsys (https://gitlab.kitware.com/utils/kwsys/-/merge_requests/298) instead of SameFile to cache the identity of a directory in cmFileSet::EvaluateDirectoryEntries. This means only one filesystem handle is needed per distinct directory path, instead of two per (even if they're equal) directory pair.
This commit is contained in:
committed by
Brad King
parent
fdf671fcc5
commit
c598a4609c
@@ -4,9 +4,11 @@
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
@@ -158,6 +160,13 @@ std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
|
||||
const cmGeneratorTarget* target,
|
||||
cmGeneratorExpressionDAGChecker* dagChecker) const
|
||||
{
|
||||
struct DirCacheEntry
|
||||
{
|
||||
std::string collapsedDir;
|
||||
cm::optional<cmSystemTools::FileId> fileId;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, DirCacheEntry> dirCache;
|
||||
std::vector<std::string> result;
|
||||
for (auto const& cge : cges) {
|
||||
auto entry = cge->Evaluate(lg, config, target, dagChecker);
|
||||
@@ -166,12 +175,29 @@ std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
|
||||
if (!cmSystemTools::FileIsFullPath(dir)) {
|
||||
dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
|
||||
}
|
||||
auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
|
||||
|
||||
auto dirCacheResult = dirCache.emplace(dir, DirCacheEntry());
|
||||
auto& dirCacheEntry = dirCacheResult.first->second;
|
||||
const auto isNewCacheEntry = dirCacheResult.second;
|
||||
|
||||
if (isNewCacheEntry) {
|
||||
cmSystemTools::FileId fileId;
|
||||
auto isFileIdValid = cmSystemTools::GetFileId(dir, fileId);
|
||||
dirCacheEntry.collapsedDir = cmSystemTools::CollapseFullPath(dir);
|
||||
dirCacheEntry.fileId =
|
||||
isFileIdValid ? cm::optional<decltype(fileId)>(fileId) : cm::nullopt;
|
||||
}
|
||||
|
||||
for (auto const& priorDir : result) {
|
||||
auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir);
|
||||
if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) &&
|
||||
(cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) ||
|
||||
cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) {
|
||||
auto priorDirCacheEntry = dirCache.at(priorDir);
|
||||
bool sameFile = dirCacheEntry.fileId.has_value() &&
|
||||
priorDirCacheEntry.fileId.has_value() &&
|
||||
(*dirCacheEntry.fileId == *priorDirCacheEntry.fileId);
|
||||
if (!sameFile &&
|
||||
(cmSystemTools::IsSubDirectory(dirCacheEntry.collapsedDir,
|
||||
priorDirCacheEntry.collapsedDir) ||
|
||||
cmSystemTools::IsSubDirectory(priorDirCacheEntry.collapsedDir,
|
||||
dirCacheEntry.collapsedDir))) {
|
||||
lg->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(
|
||||
|
||||
Reference in New Issue
Block a user