moc: Cache header lookups to reduce number of file stat's

This improves moc performance on Windows where file-stat'ing is slow
and where the number of project include paths to search is often high
because project third-party headers are installed in separate
directories rather than a shared include path such as /usr/include.

In a real project of non-trivial size it reduces the total
from-scratch build time of an optimized build using CMake+ninja with
32 cores by 11% from ~11m35s to ~10m15s.

Change-Id: Ieed59646927ed75c55ed9efa97600c328b2fed2c
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
Thomas Sondergaard 2016-11-01 09:35:31 +01:00
parent 36d3f24d6a
commit 4df5003ee7
2 changed files with 22 additions and 8 deletions

View File

@ -1005,22 +1005,20 @@ static void mergeStringLiterals(Symbols *_symbols)
}
}
QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo)
static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepaths,
const QByteArray &include)
{
// #### stringery
QFileInfo fi;
if (!relativeTo.isEmpty())
fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo.constData())).dir(), QString::fromLocal8Bit(include.constData()));
for (int j = 0; j < Preprocessor::includes.size() && !fi.exists(); ++j) {
const IncludePath &p = Preprocessor::includes.at(j);
for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) {
const Parser::IncludePath &p = includepaths.at(j);
if (p.isFrameworkPath) {
const int slashPos = include.indexOf('/');
if (slashPos == -1)
continue;
fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"),
QString::fromLocal8Bit(include.mid(slashPos + 1).constData()));
QString::fromLocal8Bit(include.mid(slashPos + 1)));
} else {
fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(include.constData()));
fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(include));
}
// try again, maybe there's a file later in the include paths with the same name
// (186067)
@ -1035,6 +1033,21 @@ QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteAr
return fi.canonicalFilePath().toLocal8Bit();
}
QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo)
{
if (!relativeTo.isEmpty()) {
QFileInfo fi;
fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo)).dir(), QString::fromLocal8Bit(include));
if (fi.exists() && !fi.isDir())
return fi.canonicalFilePath().toLocal8Bit();
}
auto it = nonlocalIncludePathResolutionCache.find(include);
if (it == nonlocalIncludePathResolutionCache.end())
it = nonlocalIncludePathResolutionCache.insert(include, searchIncludePaths(includes, include));
return it.value();
}
void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
{
currentFilenames.push(filename);

View File

@ -61,6 +61,7 @@ public:
static bool preprocessOnly;
QList<QByteArray> frameworks;
QSet<QByteArray> preprocessedIncludes;
QHash<QByteArray, QByteArray> nonlocalIncludePathResolutionCache;
Macros macros;
QByteArray resolveInclude(const QByteArray &filename, const QByteArray &relativeTo);
Symbols preprocessed(const QByteArray &filename, QFile *device);