ProjectExplorer: reduce the perceived startup time

... by moving restoreKits to the delayed initialize phase.

Change-Id: If72e41b64ee71f2917b3f7a317d9887afc6e29e8
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2023-09-11 08:58:51 +02:00
parent f1fa1ad3d9
commit 0b85fc5aa0
13 changed files with 103 additions and 26 deletions

View File

@@ -224,13 +224,19 @@ CMakeKitAspectFactory::CMakeKitAspectFactory()
"This setting is ignored when using other build systems.")); "This setting is ignored when using other build systems."));
setPriority(20000); setPriority(20000);
auto updateKits = [this] {
if (KitManager::isLoaded()) {
for (Kit *k : KitManager::kits())
fix(k);
}
};
//make sure the default value is set if a selected CMake is removed //make sure the default value is set if a selected CMake is removed
connect(CMakeToolManager::instance(), &CMakeToolManager::cmakeRemoved, connect(CMakeToolManager::instance(), &CMakeToolManager::cmakeRemoved, this, updateKits);
this, [this] { for (Kit *k : KitManager::kits()) fix(k); });
//make sure the default value is set if a new default CMake is set //make sure the default value is set if a new default CMake is set
connect(CMakeToolManager::instance(), &CMakeToolManager::defaultCMakeChanged, connect(CMakeToolManager::instance(), &CMakeToolManager::defaultCMakeChanged,
this, [this] { for (Kit *k : KitManager::kits()) fix(k); }); this, updateKits);
} }
Id CMakeKitAspect::id() Id CMakeKitAspect::id()

View File

@@ -37,6 +37,8 @@
#include <QStyle> #include <QStyle>
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <extensionsystem/pluginmanager.h>
const int kInitialWidth = 750; const int kInitialWidth = 750;
const int kInitialHeight = 450; const int kInitialHeight = 450;
const int kMaxMinimumWidth = 250; const int kMaxMinimumWidth = 250;
@@ -800,6 +802,14 @@ bool SettingsDialog::execDialog()
bool executeSettingsDialog(QWidget *parent, Id initialPage) bool executeSettingsDialog(QWidget *parent, Id initialPage)
{ {
if (!ExtensionSystem::PluginManager::isInitializationDone()) {
QObject::connect(ExtensionSystem::PluginManager::instance(),
&ExtensionSystem::PluginManager::initializationDone,
parent,
[parent, initialPage]() { executeSettingsDialog(parent, initialPage); });
return false;
}
// Make sure all wizards are there when the user might access the keyboard shortcuts: // Make sure all wizards are there when the user might access the keyboard shortcuts:
(void) IWizardFactory::allWizardFactories(); (void) IWizardFactory::allWizardFactories();

View File

@@ -1316,6 +1316,9 @@ static Kit *guessKitFromAbis(const Abis &abis)
{ {
Kit *kit = nullptr; Kit *kit = nullptr;
if (!KitManager::waitForLoaded())
return kit;
// Try to find a kit via ABI. // Try to find a kit via ABI.
if (!abis.isEmpty()) { if (!abis.isEmpty()) {
// Try exact abis. // Try exact abis.
@@ -1376,9 +1379,11 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
return false; return false;
} }
} else if (key == "kit") { } else if (key == "kit") {
kit = KitManager::kit(Id::fromString(val)); if (KitManager::waitForLoaded()) {
if (!kit) kit = KitManager::kit(Id::fromString(val));
kit = KitManager::kit(Utils::equal(&Kit::displayName, val)); if (!kit)
kit = KitManager::kit(Utils::equal(&Kit::displayName, val));
}
} else if (key == "server") { } else if (key == "server") {
startMode = AttachToRemoteServer; startMode = AttachToRemoteServer;
remoteChannel = val; remoteChannel = val;

View File

@@ -84,7 +84,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent)
if (kit) if (kit)
m_kitChooser->setCurrentKitId(kit->id()); m_kitChooser->setCurrentKitId(kit->id());
else if (KitManager::defaultKit()) else if (KitManager::waitForLoaded() && KitManager::defaultKit())
m_kitChooser->setCurrentKitId(KitManager::defaultKit()->id()); m_kitChooser->setCurrentKitId(KitManager::defaultKit()->id());
auto pathLayout = new QHBoxLayout; auto pathLayout = new QHBoxLayout;

View File

@@ -38,6 +38,8 @@
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/kitmanager.h>
#include <texteditor/texteditorconstants.h> #include <texteditor/texteditorconstants.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -283,7 +285,12 @@ void HelpPlugin::extensionsInitialized()
bool HelpPlugin::delayedInitialize() bool HelpPlugin::delayedInitialize()
{ {
HelpManager::setupHelpManager(); if (ProjectExplorer::KitManager::isLoaded()) {
HelpManager::setupHelpManager();
} else {
connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitsLoaded,
this, &HelpManager::setupHelpManager);
}
return true; return true;
} }

View File

@@ -13,6 +13,7 @@
#include "toolchainmanager.h" #include "toolchainmanager.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <android/androidconstants.h> #include <android/androidconstants.h>
#include <baremetal/baremetalconstants.h> #include <baremetal/baremetalconstants.h>
@@ -421,10 +422,10 @@ void KitManager::restoreKits()
if (!k) if (!k)
k = Utils::findOrDefault(resultList, &Kit::isValid); k = Utils::findOrDefault(resultList, &Kit::isValid);
std::swap(resultList, d->m_kitList); std::swap(resultList, d->m_kitList);
d->m_initialized = true;
setDefaultKit(k); setDefaultKit(k);
d->m_writer = std::make_unique<PersistentSettingsWriter>(settingsFileName(), "QtCreatorProfiles"); d->m_writer = std::make_unique<PersistentSettingsWriter>(settingsFileName(), "QtCreatorProfiles");
d->m_initialized = true;
kitAspectFactoriesStorage().onKitsLoaded(); kitAspectFactoriesStorage().onKitsLoaded();
@@ -467,6 +468,33 @@ bool KitManager::isLoaded()
return d->m_initialized; return d->m_initialized;
} }
bool KitManager::waitForLoaded(const int timeout)
{
if (isLoaded())
return true;
showLoadingProgress();
QElapsedTimer timer;
timer.start();
while (!isLoaded() && !timer.hasExpired(timeout))
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return KitManager::isLoaded();
}
void KitManager::showLoadingProgress()
{
if (isLoaded())
return;
static QFutureInterface<void> futureInterface;
if (futureInterface.isRunning())
return;
futureInterface.reportStarted();
Core::ProgressManager::addTimedTask(futureInterface.future(),
Tr::tr("Loading Kits"),
"LoadingKitsProgress",
5);
connect(instance(), &KitManager::kitsLoaded, []() { futureInterface.reportFinished(); });
}
void KitManager::setBinaryForKit(const FilePath &binary) void KitManager::setBinaryForKit(const FilePath &binary)
{ {
QTC_ASSERT(d, return); QTC_ASSERT(d, return);
@@ -475,6 +503,7 @@ void KitManager::setBinaryForKit(const FilePath &binary)
const QList<Kit *> KitManager::sortedKits() const QList<Kit *> KitManager::sortedKits()
{ {
QTC_ASSERT(KitManager::isLoaded(), return {});
// This method was added to delay the sorting of kits as long as possible. // This method was added to delay the sorting of kits as long as possible.
// Since the displayName can contain variables it can be costly (e.g. involve // Since the displayName can contain variables it can be costly (e.g. involve
// calling executables to find version information, etc.) to call that // calling executables to find version information, etc.) to call that
@@ -548,6 +577,7 @@ static KitList restoreKitsHelper(const FilePath &fileName)
const QList<Kit *> KitManager::kits() const QList<Kit *> KitManager::kits()
{ {
QTC_ASSERT(KitManager::isLoaded(), return {});
return Utils::toRawPointer<QList>(d->m_kitList); return Utils::toRawPointer<QList>(d->m_kitList);
} }
@@ -556,6 +586,7 @@ Kit *KitManager::kit(Id id)
if (!id.isValid()) if (!id.isValid())
return nullptr; return nullptr;
QTC_ASSERT(KitManager::isLoaded(), return {});
return Utils::findOrDefault(d->m_kitList, Utils::equal(&Kit::id, id)); return Utils::findOrDefault(d->m_kitList, Utils::equal(&Kit::id, id));
} }
@@ -566,6 +597,7 @@ Kit *KitManager::kit(const Kit::Predicate &predicate)
Kit *KitManager::defaultKit() Kit *KitManager::defaultKit()
{ {
QTC_ASSERT(KitManager::isLoaded(), return {});
return d->m_defaultKit; return d->m_defaultKit;
} }
@@ -597,7 +629,7 @@ void KitManager::notifyAboutUpdate(Kit *k)
Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Utils::Id id) Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Utils::Id id)
{ {
QTC_ASSERT(isLoaded(), return nullptr); QTC_ASSERT(isLoaded(), return {});
auto k = std::make_unique<Kit>(id); auto k = std::make_unique<Kit>(id);
QTC_ASSERT(k->id().isValid(), return nullptr); QTC_ASSERT(k->id().isValid(), return nullptr);
@@ -620,6 +652,8 @@ Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Utils::Id
void KitManager::deregisterKit(Kit *k) void KitManager::deregisterKit(Kit *k)
{ {
QTC_ASSERT(KitManager::isLoaded(), return);
if (!k || !Utils::contains(d->m_kitList, k)) if (!k || !Utils::contains(d->m_kitList, k))
return; return;
auto taken = Utils::take(d->m_kitList, k); auto taken = Utils::take(d->m_kitList, k);
@@ -632,6 +666,8 @@ void KitManager::deregisterKit(Kit *k)
void KitManager::setDefaultKit(Kit *k) void KitManager::setDefaultKit(Kit *k)
{ {
QTC_ASSERT(KitManager::isLoaded(), return);
if (defaultKit() == k) if (defaultKit() == k)
return; return;
if (k && !Utils::contains(d->m_kitList, k)) if (k && !Utils::contains(d->m_kitList, k))

View File

@@ -155,6 +155,8 @@ public:
static void saveKits(); static void saveKits();
static bool isLoaded(); static bool isLoaded();
static bool waitForLoaded(const int timeout = 60 * 1000); // timeout in ms
static void showLoadingProgress();
signals: signals:
void kitAdded(ProjectExplorer::Kit *); void kitAdded(ProjectExplorer::Kit *);

View File

@@ -197,6 +197,7 @@ signals:
void kitStateChanged(); void kitStateChanged();
private: private:
void initializeFromKitManager();
void addKit(Kit *k); void addKit(Kit *k);
void updateKit(Kit *k); void updateKit(Kit *k);
void removeKit(Kit *k); void removeKit(Kit *k);
@@ -227,10 +228,11 @@ KitModel::KitModel(QBoxLayout *parentLayout, QObject *parent)
rootItem()->appendChild(m_autoRoot); rootItem()->appendChild(m_autoRoot);
rootItem()->appendChild(m_manualRoot); rootItem()->appendChild(m_manualRoot);
for (Kit *k : KitManager::sortedKits()) if (KitManager::isLoaded()) {
addKit(k); for (Kit *k : KitManager::sortedKits())
addKit(k);
changeDefaultKit(); changeDefaultKit();
}
connect(KitManager::instance(), &KitManager::kitAdded, connect(KitManager::instance(), &KitManager::kitAdded,
this, &KitModel::addKit); this, &KitModel::addKit);

View File

@@ -24,13 +24,13 @@
#include "toolchainmanager.h" #include "toolchainmanager.h"
#include "userfileaccessor.h" #include "userfileaccessor.h"
#include <coreplugin/idocument.h>
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/iversioncontrol.h> #include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <projectexplorer/buildmanager.h> #include <projectexplorer/buildmanager.h>
#include <projectexplorer/kitmanager.h> #include <projectexplorer/kitmanager.h>
@@ -643,6 +643,12 @@ void Project::saveSettings()
Project::RestoreResult Project::restoreSettings(QString *errorMessage) Project::RestoreResult Project::restoreSettings(QString *errorMessage)
{ {
if (!KitManager::waitForLoaded()) {
if (errorMessage)
*errorMessage = Tr::tr("Could not load kits in a reasonable amount of time.");
return RestoreResult::Error;
}
if (!d->m_accessor) if (!d->m_accessor)
d->m_accessor = std::make_unique<Internal::UserFileAccessor>(this); d->m_accessor = std::make_unique<Internal::UserFileAccessor>(this);
Store map(d->m_accessor->restoreSettings(ICore::dialogParent())); Store map(d->m_accessor->restoreSettings(ICore::dialogParent()));

View File

@@ -2121,20 +2121,15 @@ void ProjectExplorerPlugin::extensionsInitialized()
// Load devices immediately, as other plugins might want to use them // Load devices immediately, as other plugins might want to use them
DeviceManager::instance()->load(); DeviceManager::instance()->load();
// delay restoring kits until UI is shown for improved perceived startup performance
QTimer::singleShot(0, this, &ProjectExplorerPlugin::restoreKits);
} }
void ProjectExplorerPlugin::restoreKits() bool ProjectExplorerPlugin::delayedInitialize()
{ {
NANOTRACE_SCOPE("ProjectExplorer", "ProjectExplorerPlugin::restoreKits"); NANOTRACE_SCOPE("ProjectExplorer", "ProjectExplorerPlugin::restoreKits");
ExtraAbi::load(); // Load this before Toolchains! ExtraAbi::load(); // Load this before Toolchains!
ToolChainManager::restoreToolChains(); ToolChainManager::restoreToolChains();
KitManager::restoreKits(); KitManager::restoreKits();
// restoring startup session is supposed to be done as a result of ICore::coreOpened, return true;
// and that is supposed to happen after restoring kits:
QTC_CHECK(!SessionManager::isStartupSessionRestored());
} }
void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu() void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu()
@@ -2379,8 +2374,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con
dd->updateActions(); dd->updateActions();
const bool switchToProjectsMode = Utils::anyOf(openedPro, &Project::needsConfiguration); const bool switchToProjectsMode = Utils::anyOf(openedPro, &Project::needsConfiguration);
const bool switchToEditMode = Utils::allOf(openedPro, const bool switchToEditMode = Utils::allOf(openedPro, &Project::isEditModePreferred);
[](Project *p) { return p->isEditModePreferred(); });
if (!openedPro.isEmpty()) { if (!openedPro.isEmpty()) {
if (switchToProjectsMode) if (switchToProjectsMode)
ModeManager::activateMode(Constants::MODE_SESSION); ModeManager::activateMode(Constants::MODE_SESSION);

View File

@@ -106,7 +106,7 @@ public:
//PluginInterface //PluginInterface
bool initialize(const QStringList &arguments, QString *errorMessage) override; bool initialize(const QStringList &arguments, QString *errorMessage) override;
void extensionsInitialized() override; void extensionsInitialized() override;
void restoreKits(); bool delayedInitialize() override;
ShutdownFlag aboutToShutdown() override; ShutdownFlag aboutToShutdown() override;
static void setProjectExplorerSettings(const ProjectExplorerSettings &pes); static void setProjectExplorerSettings(const ProjectExplorerSettings &pes);

View File

@@ -129,6 +129,7 @@ void ToolChainManager::saveToolChains()
const Toolchains &ToolChainManager::toolchains() const Toolchains &ToolChainManager::toolchains()
{ {
QTC_CHECK(d->m_loaded);
return d->m_toolChains; return d->m_toolChains;
} }
@@ -140,11 +141,13 @@ Toolchains ToolChainManager::toolchains(const ToolChain::Predicate &predicate)
ToolChain *ToolChainManager::toolChain(const ToolChain::Predicate &predicate) ToolChain *ToolChainManager::toolChain(const ToolChain::Predicate &predicate)
{ {
QTC_CHECK(d->m_loaded);
return Utils::findOrDefault(d->m_toolChains, predicate); return Utils::findOrDefault(d->m_toolChains, predicate);
} }
Toolchains ToolChainManager::findToolChains(const Abi &abi) Toolchains ToolChainManager::findToolChains(const Abi &abi)
{ {
QTC_CHECK(d->m_loaded);
Toolchains result; Toolchains result;
for (ToolChain *tc : std::as_const(d->m_toolChains)) { for (ToolChain *tc : std::as_const(d->m_toolChains)) {
bool isCompatible = Utils::anyOf(tc->supportedAbis(), [abi](const Abi &supportedAbi) { bool isCompatible = Utils::anyOf(tc->supportedAbis(), [abi](const Abi &supportedAbi) {
@@ -159,6 +162,7 @@ Toolchains ToolChainManager::findToolChains(const Abi &abi)
ToolChain *ToolChainManager::findToolChain(const QByteArray &id) ToolChain *ToolChainManager::findToolChain(const QByteArray &id)
{ {
QTC_CHECK(d->m_loaded);
if (id.isEmpty()) if (id.isEmpty())
return nullptr; return nullptr;
@@ -214,6 +218,7 @@ bool ToolChainManager::registerToolChain(ToolChain *tc)
void ToolChainManager::deregisterToolChain(ToolChain *tc) void ToolChainManager::deregisterToolChain(ToolChain *tc)
{ {
QTC_CHECK(d->m_loaded);
if (!tc || !d->m_toolChains.contains(tc)) if (!tc || !d->m_toolChains.contains(tc))
return; return;
d->m_toolChains.removeOne(tc); d->m_toolChains.removeOne(tc);

View File

@@ -179,6 +179,10 @@ static bool getEditorLaunchData(const CommandForQtVersion &commandForQtVersion,
// - default kit // - default kit
// - any other kit // - any other kit
// As fallback check PATH // As fallback check PATH
if (!KitManager::waitForLoaded()) {
*errorMessage = Tr::tr("Could not load kits in a reasonable amount of time.");
return false;
}
data->workingDirectory.clear(); data->workingDirectory.clear();
QVector<QtSupport::QtVersion *> qtVersionsToCheck; // deduplicated after being filled QVector<QtSupport::QtVersion *> qtVersionsToCheck; // deduplicated after being filled
if (const Project *project = ProjectManager::projectForFile(filePath)) { if (const Project *project = ProjectManager::projectForFile(filePath)) {