CMake: Improve remote parsing speed

To improve the speed of parsing the result of a remote
cmake call, we move the file fetching and parsing into a
mapped concurrent call.

We also first uniquify the list of files to remove duplicates.

Fixes: QTCREATORBUG-29618
Change-Id: I18108928ba3b5f4f8ec3d5610b216c5ccf060877
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-10-04 15:34:21 +02:00
parent 39354fd5e1
commit 34fdac0d84
2 changed files with 58 additions and 42 deletions

View File

@@ -20,6 +20,7 @@
#include <projectexplorer/projecttree.h>
#include <QLoggingCategory>
#include <QtConcurrent>
using namespace ProjectExplorer;
using namespace Utils;
@@ -50,52 +51,65 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
{
CMakeFileResult result;
for (const CMakeFileInfo &info : cmakefiles) {
const FilePath sfn = sourceDirectory.resolvePath(info.path);
const int oldCount = result.cmakeFiles.count();
CMakeFileInfo absolute(info);
absolute.path = sfn;
if (cmakefiles.empty())
return result;
const auto mimeType = Utils::mimeTypeForFile(info.path);
if (mimeType.matchesName(Constants::CMAKE_MIMETYPE)
|| mimeType.matchesName(Constants::CMAKE_PROJECT_MIMETYPE)) {
expected_str<QByteArray> fileContent = sfn.fileContents();
std::string errorString;
if (fileContent) {
fileContent = fileContent->replace("\r\n", "\n");
if (!absolute.cmakeListFile.ParseString(fileContent->toStdString(),
sfn.fileName().toStdString(),
errorString))
qCWarning(cmakeLogger)
<< "Failed to parse:" << sfn.path() << QString::fromLatin1(errorString);
}
// Uniquify fileInfos
std::set<CMakeFileInfo> cmakeFileSet{cmakefiles.begin(), cmakefiles.end()};
// Load and parse cmake files. We use concurrency here to speed up the process of
// reading many small files, which can get slow especially on remote devices.
QFuture<CMakeFileInfo> mapResult
= QtConcurrent::mapped(cmakeFileSet, [sourceDirectory](const auto &info) {
const FilePath sfn = sourceDirectory.resolvePath(info.path);
CMakeFileInfo absolute(info);
absolute.path = sfn;
const auto mimeType = Utils::mimeTypeForFile(info.path);
if (mimeType.matchesName(Constants::CMAKE_MIMETYPE)
|| mimeType.matchesName(Constants::CMAKE_PROJECT_MIMETYPE)) {
expected_str<QByteArray> fileContent = sfn.fileContents();
std::string errorString;
if (fileContent) {
fileContent = fileContent->replace("\r\n", "\n");
if (!absolute.cmakeListFile.ParseString(fileContent->toStdString(),
sfn.fileName().toStdString(),
errorString)) {
qCWarning(cmakeLogger) << "Failed to parse:" << sfn.path()
<< QString::fromLatin1(errorString);
}
}
}
return absolute;
});
mapResult.waitForFinished();
for (const auto &info : mapResult.results()) {
result.cmakeFiles.insert(info);
if (info.isCMake && !info.isCMakeListsDotTxt) {
// Skip files that cmake considers to be part of the installation -- but include
// CMakeLists.txt files. This fixes cmake binaries running from their own
// build directory.
continue;
}
result.cmakeFiles.insert(absolute);
auto node = std::make_unique<FileNode>(info.path, FileType::Project);
node->setIsGenerated(info.isGenerated
&& !info.isCMakeListsDotTxt); // CMakeLists.txt are never
// generated, independent
// what cmake thinks:-)
if (oldCount < result.cmakeFiles.count()) {
if (info.isCMake && !info.isCMakeListsDotTxt) {
// Skip files that cmake considers to be part of the installation -- but include
// CMakeLists.txt files. This fixes cmake binaries running from their own
// build directory.
continue;
}
auto node = std::make_unique<FileNode>(sfn, FileType::Project);
node->setIsGenerated(info.isGenerated
&& !info.isCMakeListsDotTxt); // CMakeLists.txt are never
// generated, independent
// what cmake thinks:-)
if (info.isCMakeListsDotTxt) {
result.cmakeListNodes.emplace_back(std::move(node));
} else if (sfn.isChildOf(sourceDirectory)) {
result.cmakeNodesSource.emplace_back(std::move(node));
} else if (sfn.isChildOf(buildDirectory)) {
result.cmakeNodesBuild.emplace_back(std::move(node));
} else {
result.cmakeNodesOther.emplace_back(std::move(node));
}
if (info.isCMakeListsDotTxt) {
result.cmakeListNodes.emplace_back(std::move(node));
} else if (info.path.isChildOf(sourceDirectory)) {
result.cmakeNodesSource.emplace_back(std::move(node));
} else if (info.path.isChildOf(buildDirectory)) {
result.cmakeNodesBuild.emplace_back(std::move(node));
} else {
result.cmakeNodesOther.emplace_back(std::move(node));
}
}

View File

@@ -28,6 +28,8 @@ public:
bool operator==(const CMakeFileInfo& other) const { return path == other.path; }
friend size_t qHash(const CMakeFileInfo &info, uint seed = 0) { return qHash(info.path, seed); }
bool operator<(const CMakeFileInfo &other) const { return path < other.path; }
Utils::FilePath path;
bool isCMake = false;
bool isCMakeListsDotTxt = false;