forked from qt-creator/qt-creator
AutoTest: Optimize TestCodeParser::scanForTests
In case of loading a Creator project, after the Scanning For Tests finished, the scanForTests() called by TestCodeParser::onFinished() freezed the main thread for about 1 second. In this case requestRemoval() signal was emitted nearly 1000 times. Optimize the internals: 1. Don't emit requestRemoval() for every single file but emit it just once passing a QSet<FilePath> instead. 2. Adapt some other callees and callers to work on QSet<FilePath> instead on a single FilePath. This change constraints the freeze to about 2 ms. Change-Id: If23b85b495c125d82eb3c8b5a6912349df122745 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -389,17 +389,19 @@ QSet<QString> internalTargets(const FilePath &proFile)
|
||||
return result;
|
||||
}
|
||||
|
||||
void QuickTestTreeItem::markForRemovalRecursively(const FilePath &filePath)
|
||||
void QuickTestTreeItem::markForRemovalRecursively(const QSet<FilePath> &filePaths)
|
||||
{
|
||||
TestTreeItem::markForRemovalRecursively(filePath);
|
||||
TestTreeItem::markForRemovalRecursively(filePaths);
|
||||
auto parser = static_cast<QuickTestParser *>(framework()->testParser());
|
||||
const FilePath proFile = parser->projectFileForMainCppFile(filePath);
|
||||
if (!proFile.isEmpty()) {
|
||||
TestTreeItem *root = framework()->rootNode();
|
||||
root->forAllChildItems([proFile](TestTreeItem *it) {
|
||||
if (it->proFile() == proFile)
|
||||
it->markForRemoval(true);
|
||||
});
|
||||
for (const FilePath &filePath : filePaths) {
|
||||
const FilePath proFile = parser->projectFileForMainCppFile(filePath);
|
||||
if (!proFile.isEmpty()) {
|
||||
TestTreeItem *root = framework()->rootNode();
|
||||
root->forAllChildItems([proFile](TestTreeItem *it) {
|
||||
if (it->proFile() == proFile)
|
||||
it->markForRemoval(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
bool removeOnSweepIfEmpty() const override;
|
||||
TestTreeItem *createParentGroupNode() const override;
|
||||
bool isGroupable() const override;
|
||||
void markForRemovalRecursively(const Utils::FilePath &filePath) override;
|
||||
void markForRemovalRecursively(const QSet<Utils::FilePath> &filePaths) override;
|
||||
private:
|
||||
TestTreeItem *findChildByFileNameAndType(const Utils::FilePath &filePath, const QString &name,
|
||||
Type tType);
|
||||
|
||||
@@ -307,24 +307,20 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList<ITestPa
|
||||
TestTreeModel::instance()->updateCheckStateCache();
|
||||
if (isFullParse) {
|
||||
// remove qml files as they will be found automatically by the referencing cpp file
|
||||
list = Utils::filtered(list, [](const FilePath &fn) {
|
||||
return !fn.endsWith(".qml");
|
||||
});
|
||||
list = Utils::filtered(list, [](const FilePath &fn) { return !fn.endsWith(".qml"); });
|
||||
if (!parsers.isEmpty()) {
|
||||
for (ITestParser *parser : parsers) {
|
||||
for (ITestParser *parser : parsers)
|
||||
parser->framework()->rootNode()->markForRemovalRecursively(true);
|
||||
}
|
||||
} else {
|
||||
emit requestRemoveAllFrameworkItems();
|
||||
}
|
||||
} else if (!parsers.isEmpty()) {
|
||||
const auto set = Utils::toSet(list);
|
||||
for (ITestParser *parser: parsers) {
|
||||
for (const FilePath &filePath : std::as_const(list))
|
||||
parser->framework()->rootNode()->markForRemovalRecursively(filePath);
|
||||
parser->framework()->rootNode()->markForRemovalRecursively(set);
|
||||
}
|
||||
} else {
|
||||
for (const FilePath &filePath : std::as_const(list))
|
||||
emit requestRemoval(filePath);
|
||||
emit requestRemoval(Utils::toSet(list));
|
||||
}
|
||||
|
||||
QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(true); return);
|
||||
|
||||
@@ -53,7 +53,7 @@ signals:
|
||||
void parsingStarted();
|
||||
void parsingFinished();
|
||||
void parsingFailed();
|
||||
void requestRemoval(const Utils::FilePath &filePath);
|
||||
void requestRemoval(const QSet<Utils::FilePath> &filePaths);
|
||||
void requestRemoveAllFrameworkItems();
|
||||
|
||||
public:
|
||||
|
||||
@@ -224,11 +224,11 @@ void TestTreeItem::markForRemovalRecursively(bool mark)
|
||||
childItem(row)->markForRemovalRecursively(mark);
|
||||
}
|
||||
|
||||
void TestTreeItem::markForRemovalRecursively(const FilePath &filepath)
|
||||
void TestTreeItem::markForRemovalRecursively(const QSet<FilePath> &filePaths)
|
||||
{
|
||||
bool mark = filePath() == filepath;
|
||||
forFirstLevelChildItems([&mark, &filepath](TestTreeItem *child) {
|
||||
child->markForRemovalRecursively(filepath);
|
||||
bool mark = filePaths.contains(filePath());
|
||||
forFirstLevelChildItems([&mark, &filePaths](TestTreeItem *child) {
|
||||
child->markForRemovalRecursively(filePaths);
|
||||
mark &= child->markedForRemoval();
|
||||
});
|
||||
markForRemoval(mark);
|
||||
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
void setProFile(const Utils::FilePath &proFile) { m_proFile = proFile; }
|
||||
void markForRemoval(bool mark);
|
||||
void markForRemovalRecursively(bool mark);
|
||||
virtual void markForRemovalRecursively(const Utils::FilePath &filepath);
|
||||
virtual void markForRemovalRecursively(const QSet<Utils::FilePath> &filePaths);
|
||||
virtual bool removeOnSweepIfEmpty() const { return type() == GroupNode; }
|
||||
bool markedForRemoval() const { return m_status == MarkedForRemoval; }
|
||||
bool newlyAdded() const { return m_status == NewlyAdded; }
|
||||
|
||||
@@ -100,8 +100,8 @@ void TestTreeModel::setupParsingConnections()
|
||||
m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection);
|
||||
connect(cppMM, &CppEditor::CppModelManager::aboutToRemoveFiles,
|
||||
this, [this](const QStringList &files) {
|
||||
const FilePaths filesToRemove = FileUtils::toFilePathList(files);
|
||||
removeFiles(filesToRemove);
|
||||
markForRemoval(transform<QSet>(files, &FilePath::fromString));
|
||||
sweep();
|
||||
}, Qt::QueuedConnection);
|
||||
connect(cppMM, &CppEditor::CppModelManager::projectPartsUpdated,
|
||||
m_parser, &TestCodeParser::onProjectPartsUpdated);
|
||||
@@ -109,11 +109,11 @@ void TestTreeModel::setupParsingConnections()
|
||||
QmlJS::ModelManagerInterface *qmlJsMM = QmlJS::ModelManagerInterface::instance();
|
||||
connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated,
|
||||
m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection);
|
||||
connect(qmlJsMM,
|
||||
&QmlJS::ModelManagerInterface::aboutToRemoveFiles,
|
||||
this,
|
||||
&TestTreeModel::removeFiles,
|
||||
Qt::QueuedConnection);
|
||||
connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
|
||||
this, [this](const FilePaths &filePaths) {
|
||||
markForRemoval(Utils::toSet(filePaths));
|
||||
sweep();
|
||||
}, Qt::QueuedConnection);
|
||||
connectionsInitialized = true;
|
||||
}
|
||||
|
||||
@@ -463,13 +463,6 @@ void TestTreeModel::clearFailedMarks()
|
||||
m_failedStateCache.clear();
|
||||
}
|
||||
|
||||
void TestTreeModel::removeFiles(const FilePaths &files)
|
||||
{
|
||||
for (const FilePath &file : files)
|
||||
markForRemoval(file);
|
||||
sweep();
|
||||
}
|
||||
|
||||
void TestTreeModel::markAllFrameworkItemsForRemoval()
|
||||
{
|
||||
for (TestTreeItem *frameworkRoot : frameworkRootNodes()) {
|
||||
@@ -479,15 +472,12 @@ void TestTreeModel::markAllFrameworkItemsForRemoval()
|
||||
}
|
||||
}
|
||||
|
||||
void TestTreeModel::markForRemoval(const FilePath &filePath)
|
||||
void TestTreeModel::markForRemoval(const QSet<Utils::FilePath> &filePaths)
|
||||
{
|
||||
if (filePath.isEmpty())
|
||||
return;
|
||||
|
||||
for (TestTreeItem *frameworkRoot : frameworkRootNodes()) {
|
||||
for (int childRow = frameworkRoot->childCount() - 1; childRow >= 0; --childRow) {
|
||||
TestTreeItem *child = frameworkRoot->childItem(childRow);
|
||||
child->markForRemovalRecursively(filePath);
|
||||
child->markForRemovalRecursively(filePaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
#endif
|
||||
|
||||
void markAllFrameworkItemsForRemoval();
|
||||
void markForRemoval(const Utils::FilePath &filePath);
|
||||
void markForRemoval(const QSet<Utils::FilePath> &filePaths);
|
||||
void sweep();
|
||||
|
||||
signals:
|
||||
@@ -83,7 +83,6 @@ private:
|
||||
void handleParseResult(const TestParseResult *result, TestTreeItem *rootNode);
|
||||
void removeAllTestItems();
|
||||
void removeAllTestToolItems();
|
||||
void removeFiles(const Utils::FilePaths &files);
|
||||
bool sweepChildren(TestTreeItem *item);
|
||||
void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
|
||||
void revalidateCheckState(ITestTreeItem *item);
|
||||
|
||||
Reference in New Issue
Block a user