cache results of feature search

looking up the same files in the same locations over and over again
is a rather significant waste. in particular, looking up the CONFIG
flags that don't correspond with features has a measurable impact on qt
creator's project loading time.

Task-number: QTCREATORBUG-9154
Change-Id: Ibae3d8b7797e706a6416a7d45c77734ab1281b51
Reviewed-by: Daniel Teske <daniel.teske@digia.com>
(cherry picked from qtcreator/fa27cd79e05aed4ebd16d5648480cc7d48fefd43)
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
This commit is contained in:
Oswald Buddenhagen 2013-06-03 19:08:10 +02:00 committed by The Qt Project
parent 547b7ed29c
commit 3a6a462ad9
2 changed files with 66 additions and 28 deletions

View File

@ -1503,7 +1503,7 @@ void QMakeEvaluator::updateFeaturePaths()
foreach (const QString &root, feature_roots)
if (IoUtils::exists(root))
ret << root;
m_featureRoots = ret;
m_featureRoots = new QMakeFeatureRoots(ret);
}
ProString QMakeEvaluator::propertyValue(const ProKey &name) const
@ -1861,35 +1861,55 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile(
if (!fn.endsWith(QLatin1String(".prf")))
fn += QLatin1String(".prf");
if (m_featureRoots.isEmpty())
if (!m_featureRoots)
updateFeaturePaths();
int start_root = 0;
QString currFn = currentFileName();
if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) {
QStringRef currPath = IoUtils::pathName(currFn);
for (int root = 0; root < m_featureRoots.size(); ++root)
if (currPath == m_featureRoots.at(root)) {
start_root = root + 1;
break;
}
}
for (int root = start_root; root < m_featureRoots.size(); ++root) {
QString fname = m_featureRoots.at(root) + fn;
if (IoUtils::exists(fname)) {
fn = fname;
goto cool;
}
}
#ifdef QMAKE_BUILTIN_PRFS
fn.prepend(QLatin1String(":/qmake/features/"));
if (QFileInfo(fn).exists())
goto cool;
#ifdef PROEVALUATOR_THREAD_SAFE
m_featureRoots->mutex.lock();
#endif
if (!silent)
evalError(fL1S("Cannot find feature %1").arg(fileName));
return ReturnFalse;
QString currFn = currentFileName();
if (IoUtils::fileName(currFn) != IoUtils::fileName(fn))
currFn.clear();
// Null values cannot regularly exist in the hash, so they indicate that the value still
// needs to be determined. Failed lookups are represented via non-null empty strings.
QString *fnp = &m_featureRoots->cache[qMakePair(fn, currFn)];
if (fnp->isNull()) {
int start_root = 0;
const QStringList &paths = m_featureRoots->paths;
if (!currFn.isEmpty()) {
QStringRef currPath = IoUtils::pathName(currFn);
for (int root = 0; root < paths.size(); ++root)
if (currPath == paths.at(root)) {
start_root = root + 1;
break;
}
}
for (int root = start_root; root < paths.size(); ++root) {
QString fname = paths.at(root) + fn;
if (IoUtils::exists(fname)) {
fn = fname;
goto cool;
}
}
#ifdef QMAKE_BUILTIN_PRFS
fn.prepend(QLatin1String(":/qmake/features/"));
if (QFileInfo(fn).exists())
goto cool;
#endif
fn = QLatin1String(""); // Indicate failed lookup. See comment above.
cool:
cool:
*fnp = fn;
} else {
fn = *fnp;
}
#ifdef PROEVALUATOR_THREAD_SAFE
m_featureRoots->mutex.unlock();
#endif
if (fn.isEmpty()) {
if (!silent)
evalError(fL1S("Cannot find feature %1").arg(fileName));
return ReturnFalse;
}
ProStringList &already = valuesRef(ProKey("QMAKE_INTERNAL_INCLUDED_FEATURES"));
ProString afn(fn);
if (already.contains(afn)) {

View File

@ -55,9 +55,13 @@
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qshareddata.h>
#ifndef QT_BOOTSTRAPPED
# include <qprocess.h>
#endif
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qmutex.h>
#endif
QT_BEGIN_NAMESPACE
@ -83,6 +87,20 @@ public:
virtual void doneWithEval(ProFile *parent) = 0;
};
typedef QPair<QString, QString> QMakeFeatureKey; // key, parent
typedef QHash<QMakeFeatureKey, QString> QMakeFeatureHash;
class QMAKE_EXPORT QMakeFeatureRoots : public QSharedData
{
public:
QMakeFeatureRoots(const QStringList &_paths) : paths(_paths) {}
const QStringList paths;
mutable QMakeFeatureHash cache;
#ifdef PROEVALUATOR_THREAD_SAFE
mutable QMutex mutex;
#endif
};
// We use a QLinkedList based stack instead of a QVector based one (QStack), so that
// the addresses of value maps stay constant. The qmake generators rely on that.
class QMAKE_EXPORT ProValueMapStack : public QLinkedList<ProValueMap>
@ -284,7 +302,7 @@ public:
QStringList m_qmakepath;
QStringList m_qmakefeatures;
QStringList m_mkspecPaths;
QStringList m_featureRoots;
QExplicitlySharedDataPointer<QMakeFeatureRoots> m_featureRoots;
ProString m_dirSep;
ProFunctionDefs m_functionDefs;
ProStringList m_returnValue;