mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-21 14:40:26 -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 <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cm/optional>
|
||||||
#include <cmext/algorithm>
|
#include <cmext/algorithm>
|
||||||
#include <cmext/string_view>
|
#include <cmext/string_view>
|
||||||
|
|
||||||
@@ -158,6 +160,13 @@ std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
|
|||||||
const cmGeneratorTarget* target,
|
const cmGeneratorTarget* target,
|
||||||
cmGeneratorExpressionDAGChecker* dagChecker) const
|
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;
|
std::vector<std::string> result;
|
||||||
for (auto const& cge : cges) {
|
for (auto const& cge : cges) {
|
||||||
auto entry = cge->Evaluate(lg, config, target, dagChecker);
|
auto entry = cge->Evaluate(lg, config, target, dagChecker);
|
||||||
@@ -166,12 +175,29 @@ std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
|
|||||||
if (!cmSystemTools::FileIsFullPath(dir)) {
|
if (!cmSystemTools::FileIsFullPath(dir)) {
|
||||||
dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', 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) {
|
for (auto const& priorDir : result) {
|
||||||
auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir);
|
auto priorDirCacheEntry = dirCache.at(priorDir);
|
||||||
if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) &&
|
bool sameFile = dirCacheEntry.fileId.has_value() &&
|
||||||
(cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) ||
|
priorDirCacheEntry.fileId.has_value() &&
|
||||||
cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) {
|
(*dirCacheEntry.fileId == *priorDirCacheEntry.fileId);
|
||||||
|
if (!sameFile &&
|
||||||
|
(cmSystemTools::IsSubDirectory(dirCacheEntry.collapsedDir,
|
||||||
|
priorDirCacheEntry.collapsedDir) ||
|
||||||
|
cmSystemTools::IsSubDirectory(priorDirCacheEntry.collapsedDir,
|
||||||
|
dirCacheEntry.collapsedDir))) {
|
||||||
lg->GetCMakeInstance()->IssueMessage(
|
lg->GetCMakeInstance()->IssueMessage(
|
||||||
MessageType::FATAL_ERROR,
|
MessageType::FATAL_ERROR,
|
||||||
cmStrCat(
|
cmStrCat(
|
||||||
|
|||||||
Reference in New Issue
Block a user