From ea868c8b46ae5c8fbf69a922b938884dcf2685f6 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 17 Jun 2022 11:58:14 +0200 Subject: [PATCH] ClangCodeModel: Check system for clangd suitability on first run Turn off clangd by default if we think the system does not have enough memory. Inform the user and let them override our decision. Task-number: QTCREATORBUG-19297 Change-Id: Ib9715c2f089c10d7a2a559a25180e9a943c118b1 Reviewed-by: Eike Ziller --- src/libs/utils/hostosinfo.cpp | 28 ++++++++++++++ src/libs/utils/hostosinfo.h | 3 ++ .../clangmodelmanagersupport.cpp | 37 +++++++++++++++++++ .../cppeditor/cppcodemodelsettings.cpp | 22 ++++++++++- src/plugins/cppeditor/cppcodemodelsettings.h | 9 ++++- 5 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/hostosinfo.cpp b/src/libs/utils/hostosinfo.cpp index 657bf08470a..79f042e0f05 100644 --- a/src/libs/utils/hostosinfo.cpp +++ b/src/libs/utils/hostosinfo.cpp @@ -31,6 +31,10 @@ #include #endif +#ifdef Q_OS_LINUX +#include +#endif + #ifdef Q_OS_WIN #include #endif @@ -111,3 +115,27 @@ bool HostOsInfo::canCreateOpenGLContext(QString *errorMessage) return canCreate; #endif } + +optional HostOsInfo::totalMemoryInstalledInBytes() +{ +#ifdef Q_OS_LINUX + struct sysinfo info; + if (sysinfo(&info) == -1) + return {}; + return info.totalram; +#elif defined(Q_OS_WIN) + MEMORYSTATUSEX statex; + statex.dwLength = sizeof statex; + if (!GlobalMemoryStatusEx(&statex)) + return {}; + return statex.ullTotalPhys; +#elif defined(Q_OS_MACOS) + int mib[] = {CTL_HW, HW_MEMSIZE}; + int64_t ram; + size_t length = sizeof(int64_t); + if (sysctl(mib, 2, &ram, &length, nullptr, 0) == -1) + return {}; + return ram; +#endif + return {}; +} diff --git a/src/libs/utils/hostosinfo.h b/src/libs/utils/hostosinfo.h index 9fa6689d4b6..9823c7e6f23 100644 --- a/src/libs/utils/hostosinfo.h +++ b/src/libs/utils/hostosinfo.h @@ -27,6 +27,7 @@ #include "utils_global.h" +#include "optional.h" #include "osspecificaspects.h" QT_BEGIN_NAMESPACE @@ -104,6 +105,8 @@ public: static bool canCreateOpenGLContext(QString *errorMessage); + static optional totalMemoryInstalledInBytes(); + private: static Qt::CaseSensitivity m_overrideFileNameCaseSensitivity; static bool m_useOverrideFileNameCaseSensitivity; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index a33d2863563..1437aff83f6 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -62,10 +62,12 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -124,6 +126,40 @@ static Client *clientForGeneratedFile(const Utils::FilePath &filePath) return nullptr; } +static void checkSystemForClangdSuitability() +{ + if (ClangdSettings::haveCheckedHardwareRequirements()) + return; + if (ClangdSettings::hardwareFulfillsRequirements()) + return; + + ClangdSettings::setUseClangd(false); + const QString warnStr = ClangModelManagerSupport::tr("The use of clangd for the C/C++ " + "code model was disabled, because it is likely that its memory requirements " + "would be higher than what your system can handle."); + const Utils::Id clangdWarningSetting("WarnAboutClangd"); + Utils::InfoBarEntry info(clangdWarningSetting, warnStr); + info.setDetailsWidgetCreator([] { + const auto label = new QLabel(ClangModelManagerSupport::tr( + "With clangd enabled, Qt Creator fully supports modern C++ " + "when highlighting code, completing symbols and so on.
" + "This comes at a higher cost in terms of CPU load and memory usage compared " + "to the built-in code model, which therefore might be the better choice " + "on older machines and/or with legacy code.
" + "You can enable/disable and fine-tune clangd here.")); + label->setWordWrap(true); + QObject::connect(label, &QLabel::linkActivated, [] { + Core::ICore::showOptionsDialog(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); + }); + return label; + }); + info.addCustomButton(ClangModelManagerSupport::tr("Enable Anyway"), [clangdWarningSetting] { + ClangdSettings::setUseClangd(true); + Core::ICore::infoBar()->removeInfo(clangdWarningSetting); + }); + Core::ICore::infoBar()->addInfo(info); +} + ClangModelManagerSupport::ClangModelManagerSupport() { QTC_CHECK(!m_instance); @@ -132,6 +168,7 @@ ClangModelManagerSupport::ClangModelManagerSupport() watchForExternalChanges(); watchForInternalChanges(); setupClangdConfigFile(); + checkSystemForClangdSuitability(); cppModelManager()->setCurrentDocumentFilter(std::make_unique()); cppModelManager()->setLocatorFilter(std::make_unique()); cppModelManager()->setClassesFilter(std::make_unique()); diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 0c59d923c25..69f61e2e549 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -81,6 +82,7 @@ static QString clangdSizeThresholdKey() { return QLatin1String("ClangdSizeThresh static QString clangdUseGlobalSettingsKey() { return QLatin1String("useGlobalSettings"); } static QString sessionsWithOneClangdKey() { return QLatin1String("SessionsWithOneClangd"); } static QString diagnosticConfigIdKey() { return QLatin1String("diagnosticConfigId"); } +static QString checkedHardwareKey() { return QLatin1String("checkedHardware"); } static FilePath g_defaultClangdFilePath; static FilePath fallbackClangdFilePath() @@ -206,6 +208,22 @@ bool ClangdSettings::useClangd() const return m_data.useClangd && clangdVersion() >= QVersionNumber(14); } +void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; } + +bool ClangdSettings::hardwareFulfillsRequirements() +{ + instance().m_data.haveCheckedHardwareReqirements = true; + instance().saveSettings(); + const quint64 minRam = quint64(12) * 1024 * 1024 * 1024; + const Utils::optional totalRam = Utils::HostOsInfo::totalMemoryInstalledInBytes(); + return !totalRam || *totalRam >= minRam; +} + +bool ClangdSettings::haveCheckedHardwareRequirements() +{ + return instance().data().haveCheckedHardwareReqirements; +} + void ClangdSettings::setDefaultClangdPath(const FilePath &filePath) { g_defaultClangdFilePath = filePath; @@ -350,8 +368,6 @@ void ClangdSettings::saveSettings() } #ifdef WITH_TESTS -void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; } - void ClangdSettings::setClangdFilePath(const FilePath &filePath) { instance().m_data.executableFilePath = filePath; @@ -435,6 +451,7 @@ QVariantMap ClangdSettings::Data::toMap() const map.insert(clangdSizeThresholdKey(), sizeThresholdInKb); map.insert(sessionsWithOneClangdKey(), sessionsWithOneClangd); map.insert(diagnosticConfigIdKey(), diagnosticConfigId.toSetting()); + map.insert(checkedHardwareKey(), true); return map; } @@ -451,6 +468,7 @@ void ClangdSettings::Data::fromMap(const QVariantMap &map) sessionsWithOneClangd = map.value(sessionsWithOneClangdKey()).toStringList(); diagnosticConfigId = Id::fromSetting(map.value(diagnosticConfigIdKey(), initialClangDiagnosticConfigId().toSetting())); + haveCheckedHardwareReqirements = map.value(checkedHardwareKey(), false).toBool(); } } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index 1bf5b46616a..8cf0bac463c 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -111,7 +111,8 @@ public: && s1.autoIncludeHeaders == s2.autoIncludeHeaders && s1.documentUpdateThreshold == s2.documentUpdateThreshold && s1.sizeThresholdEnabled == s2.sizeThresholdEnabled - && s1.sizeThresholdInKb == s2.sizeThresholdInKb; + && s1.sizeThresholdInKb == s2.sizeThresholdInKb + && s1.haveCheckedHardwareReqirements == s2.haveCheckedHardwareReqirements; } friend bool operator!=(const Data &s1, const Data &s2) { return !(s1 == s2); } @@ -126,12 +127,17 @@ public: bool enableIndexing = true; bool autoIncludeHeaders = false; bool sizeThresholdEnabled = false; + bool haveCheckedHardwareReqirements = false; }; ClangdSettings(const Data &data) : m_data(data) {} static ClangdSettings &instance(); bool useClangd() const; + static void setUseClangd(bool use); + + static bool hardwareFulfillsRequirements(); + static bool haveCheckedHardwareRequirements(); static void setDefaultClangdPath(const Utils::FilePath &filePath); static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs); @@ -159,7 +165,6 @@ public: static Utils::FilePath clangdUserConfigFilePath(); #ifdef WITH_TESTS - static void setUseClangd(bool use); static void setClangdFilePath(const Utils::FilePath &filePath); #endif