ProjectExplorer/MSVC: Cache more predefined macros

...as for the gcc toolchain. Do not cache only the "last" predefined
macros, but cache them all.

Change-Id: I404955e7419089bb03f7d354488f8b9980e8583b
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2018-10-08 12:15:20 +02:00
parent eb01565c99
commit feae30d7ad
7 changed files with 148 additions and 95 deletions

View File

@@ -29,6 +29,7 @@
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projectexplorersettings.h" #include "projectexplorersettings.h"
#include "taskhub.h" #include "taskhub.h"
#include "toolchaincache.h"
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
@@ -46,7 +47,7 @@ namespace Internal {
AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Core::Id l, Detection d, AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Core::Id l, Detection d,
const Abi &abi, const Abi &abi,
const QString& vcvarsBat) : ToolChain(typeId, d), const QString& vcvarsBat) : ToolChain(typeId, d),
m_predefinedMacrosMutex(new QMutex), m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>()),
m_lastEnvironment(Utils::Environment::systemEnvironment()), m_lastEnvironment(Utils::Environment::systemEnvironment()),
m_headerPathsMutex(new QMutex), m_headerPathsMutex(new QMutex),
m_abi(abi), m_abi(abi),
@@ -57,20 +58,18 @@ AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Core::Id l, Detect
AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Detection d) : AbstractMsvcToolChain::AbstractMsvcToolChain(Core::Id typeId, Detection d) :
ToolChain(typeId, d), ToolChain(typeId, d),
m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>()),
m_lastEnvironment(Utils::Environment::systemEnvironment()) m_lastEnvironment(Utils::Environment::systemEnvironment())
{ } { }
AbstractMsvcToolChain::~AbstractMsvcToolChain() AbstractMsvcToolChain::~AbstractMsvcToolChain()
{ {
delete m_predefinedMacrosMutex;
delete m_headerPathsMutex; delete m_headerPathsMutex;
} }
AbstractMsvcToolChain::AbstractMsvcToolChain(const AbstractMsvcToolChain &other) AbstractMsvcToolChain::AbstractMsvcToolChain(const AbstractMsvcToolChain &other)
: ToolChain(other), : ToolChain(other),
m_debuggerCommand(other.m_debuggerCommand), m_debuggerCommand(other.m_debuggerCommand),
m_predefinedMacrosMutex(new QMutex),
m_predefinedMacros(other.m_predefinedMacros),
m_lastEnvironment(other.m_lastEnvironment), m_lastEnvironment(other.m_lastEnvironment),
m_resultEnvironment(other.m_resultEnvironment), m_resultEnvironment(other.m_resultEnvironment),
m_headerPathsMutex(new QMutex), m_headerPathsMutex(new QMutex),
@@ -147,6 +146,13 @@ LanguageVersion static languageVersionForMsvc(const Core::Id &language, const Ma
} }
} }
bool static hasFlagEffectOnMacros(const QString &arg)
{
if (arg.startsWith("-I"))
return false;
return true;
}
Q_GLOBAL_STATIC_WITH_ARGS(const QVector<QByteArray>, unwantedMacrosMsvc, Q_GLOBAL_STATIC_WITH_ARGS(const QVector<QByteArray>, unwantedMacrosMsvc,
({"_MSVC_LANG", ({"_MSVC_LANG",
"_MSC_BUILD", "_MSC_BUILD",
@@ -157,21 +163,29 @@ ToolChain::MacroInspectionRunner AbstractMsvcToolChain::createMacroInspectionRun
{ {
Utils::Environment env(m_lastEnvironment); Utils::Environment env(m_lastEnvironment);
addToEnvironment(env); addToEnvironment(env);
std::shared_ptr<Cache<MacroInspectionReport, 64>> macroCache = m_predefinedMacrosCache;
const Core::Id lang = language(); const Core::Id lang = language();
// This runner must be thread-safe! // This runner must be thread-safe!
return [this, env, lang](const QStringList &cxxflags) { return [this, env, macroCache, lang](const QStringList &cxxflags) {
QMutexLocker locker(m_predefinedMacrosMutex); const QStringList filteredFlags = Utils::filtered(cxxflags, [](const QString &arg) {
if (m_predefinedMacros.isEmpty() || m_cxxFlags != cxxflags) { return hasFlagEffectOnMacros(arg);
m_predefinedMacros = msvcPredefinedMacros(cxxflags, env); });
m_cxxFlags = cxxflags;
}
const QVector<Macro> filteredMacros = Utils::filtered(m_predefinedMacros, [](const Macro &m) { const Utils::optional<MacroInspectionReport> cachedMacros = macroCache->check(filteredFlags);
if (cachedMacros)
return cachedMacros.value();
const Macros macros = msvcPredefinedMacros(filteredFlags, env);
const QVector<Macro> filteredMacros = Utils::filtered(macros, [](const Macro &m) {
return !ToolChain::isUnwantedMacro(m) && !unwantedMacrosMsvc->contains(m.key); return !ToolChain::isUnwantedMacro(m) && !unwantedMacrosMsvc->contains(m.key);
}); });
return MacroInspectionReport{filteredMacros,
languageVersionForMsvc(lang, m_predefinedMacros)}; const auto report = MacroInspectionReport{filteredMacros,
languageVersionForMsvc(lang, macros)};
macroCache->insert(filteredFlags, report);
return report;
}; };
} }
@@ -460,6 +474,11 @@ void AbstractMsvcToolChain::inferWarningsForLevel(int warningLevel, WarningFlags
flags |= WarningFlags::UnusedParams; flags |= WarningFlags::UnusedParams;
} }
void Internal::AbstractMsvcToolChain::toolChainUpdated()
{
m_predefinedMacrosCache->invalidate();
}
bool AbstractMsvcToolChain::operator ==(const ToolChain &other) const bool AbstractMsvcToolChain::operator ==(const ToolChain &other) const
{ {
if (!ToolChain::operator ==(other)) if (!ToolChain::operator ==(other))

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "toolchain.h" #include "toolchain.h"
#include "toolchaincache.h"
#include "abi.h" #include "abi.h"
#include "headerpath.h" #include "headerpath.h"
@@ -92,6 +93,7 @@ protected:
}; };
static void inferWarningsForLevel(int warningLevel, WarningFlags &flags); static void inferWarningsForLevel(int warningLevel, WarningFlags &flags);
void toolChainUpdated() override;
virtual Utils::Environment readEnvironmentSetting(const Utils::Environment& env) const = 0; virtual Utils::Environment readEnvironmentSetting(const Utils::Environment& env) const = 0;
// Function must be thread-safe! // Function must be thread-safe!
virtual Macros msvcPredefinedMacros(const QStringList cxxflags, virtual Macros msvcPredefinedMacros(const QStringList cxxflags,
@@ -100,9 +102,7 @@ protected:
Utils::FileName m_debuggerCommand; Utils::FileName m_debuggerCommand;
mutable QMutex *m_predefinedMacrosMutex = nullptr; mutable std::shared_ptr<Cache<MacroInspectionReport, 64>> m_predefinedMacrosCache;
mutable Macros m_predefinedMacros;
mutable QStringList m_cxxFlags;
mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment. mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment.
mutable Utils::Environment m_resultEnvironment; // Resulting environment for VC mutable Utils::Environment m_resultEnvironment; // Resulting environment for VC

View File

@@ -28,14 +28,11 @@
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include "toolchain.h" #include "toolchain.h"
#include "toolchaincache.h"
#include "abi.h" #include "abi.h"
#include "headerpath.h" #include "headerpath.h"
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/optional.h>
#include <QMutex>
#include <QStringList>
#include <functional> #include <functional>
#include <memory> #include <memory>
@@ -54,79 +51,6 @@ class LinuxIccToolChainFactory;
// GccToolChain // GccToolChain
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
template<class T, int Size = 16>
class Cache
{
public:
Cache() { m_cache.reserve(Size); }
Cache(const Cache &other) = delete;
Cache &operator =(const Cache &other) = delete;
Cache(Cache &&other)
{
using std::swap;
QMutexLocker otherLocker(&other.m_mutex);
swap(m_cache, other.m_cache);
}
Cache &operator =(Cache &&other)
{
using std::swap;
QMutexLocker locker(&m_mutex);
QMutexLocker otherLocker(&other.m_mutex);
auto temporay(std::move(other.m_cache)); // Make sure other.m_cache is empty!
swap(m_cache, temporay);
return *this;
}
void insert(const QStringList &compilerArguments, const T &values)
{
CacheItem runResults;
runResults.first = compilerArguments;
runResults.second = values;
QMutexLocker locker(&m_mutex);
if (!checkImpl(compilerArguments)) {
if (m_cache.size() < Size) {
m_cache.push_back(runResults);
} else {
std::rotate(m_cache.begin(), std::next(m_cache.begin()), m_cache.end());
m_cache.back() = runResults;
}
}
}
Utils::optional<T> check(const QStringList &compilerArguments)
{
QMutexLocker locker(&m_mutex);
return checkImpl(compilerArguments);
}
void invalidate()
{
QMutexLocker locker(&m_mutex);
m_cache.clear();
}
private:
Utils::optional<T> checkImpl(const QStringList &compilerArguments)
{
auto it = std::stable_partition(m_cache.begin(), m_cache.end(), [&](const CacheItem &ci) {
return ci.first != compilerArguments;
});
if (it != m_cache.end())
return m_cache.back().second;
return {};
}
using CacheItem = QPair<QStringList, T>;
QMutex m_mutex;
QVector<CacheItem> m_cache;
};
class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain
{ {
public: public:

View File

@@ -470,8 +470,6 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
predefinedMacros.append(Macro::fromKeyValue(define)); predefinedMacros.append(Macro::fromKeyValue(define));
} else if (arg.startsWith(QLatin1String("/U"))) { } else if (arg.startsWith(QLatin1String("/U"))) {
predefinedMacros.append({arg.mid(2).toLocal8Bit(), ProjectExplorer::MacroType::Undefine}); predefinedMacros.append({arg.mid(2).toLocal8Bit(), ProjectExplorer::MacroType::Undefine});
} else if (arg.startsWith(QLatin1String("-I"))) {
// Include paths should not have any effect on defines
} else { } else {
toProcess.append(arg); toProcess.append(arg);
} }

View File

@@ -89,6 +89,7 @@ HEADERS += projectexplorer.h \
projectmodels.h \ projectmodels.h \
currentprojectfind.h \ currentprojectfind.h \
toolchain.h \ toolchain.h \
toolchaincache.h \
toolchainconfigwidget.h \ toolchainconfigwidget.h \
toolchainmanager.h \ toolchainmanager.h \
toolchainoptionspage.h \ toolchainoptionspage.h \

View File

@@ -145,6 +145,7 @@ Project {
"taskmodel.cpp", "taskmodel.h", "taskmodel.cpp", "taskmodel.h",
"taskwindow.cpp", "taskwindow.h", "taskwindow.cpp", "taskwindow.h",
"toolchain.cpp", "toolchain.h", "toolchain.cpp", "toolchain.h",
"toolchaincache.h",
"toolchainconfigwidget.cpp", "toolchainconfigwidget.h", "toolchainconfigwidget.cpp", "toolchainconfigwidget.h",
"toolchainmanager.cpp", "toolchainmanager.h", "toolchainmanager.cpp", "toolchainmanager.h",
"toolchainoptionspage.cpp", "toolchainoptionspage.h", "toolchainoptionspage.cpp", "toolchainoptionspage.h",

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QMutex>
#include <QMutexLocker>
#include <QStringList>
#include <QVector>
#include <utils/optional.h>
namespace ProjectExplorer {
template<class T, int Size = 16>
class Cache
{
public:
Cache() { m_cache.reserve(Size); }
Cache(const Cache &other) = delete;
Cache &operator =(const Cache &other) = delete;
Cache(Cache &&other)
{
using std::swap;
QMutexLocker otherLocker(&other.m_mutex);
swap(m_cache, other.m_cache);
}
Cache &operator =(Cache &&other)
{
using std::swap;
QMutexLocker locker(&m_mutex);
QMutexLocker otherLocker(&other.m_mutex);
auto temporay(std::move(other.m_cache)); // Make sure other.m_cache is empty!
swap(m_cache, temporay);
return *this;
}
void insert(const QStringList &compilerArguments, const T &values)
{
CacheItem runResults;
runResults.first = compilerArguments;
runResults.second = values;
QMutexLocker locker(&m_mutex);
if (!checkImpl(compilerArguments)) {
if (m_cache.size() < Size) {
m_cache.push_back(runResults);
} else {
std::rotate(m_cache.begin(), std::next(m_cache.begin()), m_cache.end());
m_cache.back() = runResults;
}
}
}
Utils::optional<T> check(const QStringList &compilerArguments)
{
QMutexLocker locker(&m_mutex);
return checkImpl(compilerArguments);
}
void invalidate()
{
QMutexLocker locker(&m_mutex);
m_cache.clear();
}
private:
Utils::optional<T> checkImpl(const QStringList &compilerArguments)
{
auto it = std::stable_partition(m_cache.begin(), m_cache.end(), [&](const CacheItem &ci) {
return ci.first != compilerArguments;
});
if (it != m_cache.end())
return m_cache.back().second;
return {};
}
using CacheItem = QPair<QStringList, T>;
QMutex m_mutex;
QVector<CacheItem> m_cache;
};
} // namespace ProjectExplorer