Commit f9d955eb authored by Oswald Buddenhagen's avatar Oswald Buddenhagen
Browse files

cache parsed pri & prf files

no point in re-parsing them over and over during the scan of a bigger
project ...

shaves off another 20% of the loading time of Qt 4.6.
parent ef660880
......@@ -42,35 +42,27 @@ ProFileReader::ProFileReader(ProFileOption *option) : ProFileEvaluator(option)
ProFileReader::~ProFileReader()
{
foreach (ProFile *pf, m_proFiles)
delete pf;
pf->deref();
}
bool ProFileReader::readProFile(const QString &fileName)
{
//disable caching -> list of include files is not updated otherwise
ProFile *pro = new ProFile(fileName);
if (!queryProFile(pro)) {
delete pro;
return false;
if (ProFile *pro = parsedProFile(fileName)) {
aboutToEval(pro);
bool ok = accept(pro);
pro->deref();
return ok;
}
m_includeFiles.insert(fileName, pro);
m_proFiles.append(pro);
return accept(pro);
return false;
}
ProFile *ProFileReader::parsedProFile(const QString &fileName)
void ProFileReader::aboutToEval(ProFile *pro)
{
ProFile *pro = ProFileEvaluator::parsedProFile(fileName);
if (pro) {
m_includeFiles.insert(fileName, pro);
if (!m_includeFiles.contains(pro->fileName())) {
m_includeFiles.insert(pro->fileName(), pro);
m_proFiles.append(pro);
pro->ref();
}
return pro;
}
void ProFileReader::releaseParsedProFile(ProFile *)
{
return;
}
QList<ProFile*> ProFileReader::includeFiles() const
......@@ -117,3 +109,52 @@ ProFile *ProFileReader::proFileFor(const QString &name)
{
return m_includeFiles.value(name);
}
ProFileCacheManager *ProFileCacheManager::s_instance = 0;
ProFileCacheManager::ProFileCacheManager(QObject *parent) :
QObject(parent),
m_cache(0)
{
s_instance = this;
m_timer.setSingleShot(true);
m_timer.setInterval(5000);
connect(&m_timer, SIGNAL(timeout()), SLOT(clear()));
}
ProFileCacheManager::~ProFileCacheManager()
{
s_instance = 0;
clear();
}
ProFileCache *ProFileCacheManager::cache()
{
m_timer.start();
if (!m_cache)
m_cache = new ProFileCache;
return m_cache;
}
void ProFileCacheManager::clear()
{
// Just deleting the cache will be safe as long as the sequence of
// obtaining a cache pointer and using it is atomic as far as the main
// loop is concerned. Use a shared pointer once this is not true anymore.
delete m_cache;
m_cache = 0;
}
void ProFileCacheManager::discardFiles(const QString &prefix)
{
if (m_cache)
m_cache->discardFiles(prefix);
}
void ProFileCacheManager::discardFile(const QString &fileName)
{
if (m_cache)
m_cache->discardFile(fileName);
}
......@@ -34,6 +34,7 @@
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <QtCore/QTimer>
namespace Qt4ProjectManager {
namespace Internal {
......@@ -56,8 +57,7 @@ signals:
void errorFound(const QString &error);
private:
virtual ProFile *parsedProFile(const QString &fileName);
virtual void releaseParsedProFile(ProFile *proFile);
virtual void aboutToEval(ProFile *proFile);
virtual void logMessage(const QString &msg);
virtual void fileMessage(const QString &msg);
virtual void errorMessage(const QString &msg);
......@@ -67,6 +67,28 @@ private:
QList<ProFile *> m_proFiles;
};
class ProFileCacheManager : public QObject
{
Q_OBJECT
public:
static ProFileCacheManager *instance() { return s_instance; }
ProFileCache *cache();
void discardFiles(const QString &prefix);
void discardFile(const QString &fileName);
private:
ProFileCacheManager(QObject *parent);
~ProFileCacheManager();
Q_SLOT void clear();
QTimer m_timer;
ProFileCache *m_cache;
static ProFileCacheManager *s_instance;
friend class Qt4ProjectManagerPlugin;
};
} // namespace Internal
} // namespace Qt4ProjectManager
......
......@@ -115,6 +115,7 @@ Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNo
void Qt4PriFileNode::scheduleUpdate()
{
ProFileCacheManager::instance()->discardFile(m_projectFilePath);
m_qt4ProFileNode->scheduleUpdate();
}
......
......@@ -867,6 +867,8 @@ ProFileReader *Qt4Project::createProFileReader(Qt4ProFileNode *qt4ProFileNode)
if (version->isValid())
m_proFileOption->properties = version->versionInfo();
}
m_proFileOption->cache = ProFileCacheManager::instance()->cache();
}
++m_proFileOptionRefCnt;
......@@ -883,6 +885,11 @@ void Qt4Project::destroyProFileReader(ProFileReader *reader)
{
delete reader;
if (!--m_proFileOptionRefCnt) {
QString dir = QFileInfo(m_fileInfo->fileName()).absolutePath();
if (!dir.endsWith(QLatin1Char('/')))
dir += QLatin1Char('/');
m_proFileOption->cache->discardFiles(dir);
delete m_proFileOption;
m_proFileOption = 0;
}
......@@ -1040,8 +1047,10 @@ void Qt4Project::notifyChanged(const QString &name)
if (files(Qt4Project::ExcludeGeneratedFiles).contains(name)) {
QList<Qt4ProFileNode *> list;
findProFile(name, rootProjectNode(), list);
foreach(Qt4ProFileNode *node, list)
foreach(Qt4ProFileNode *node, list) {
ProFileCacheManager::instance()->discardFile(name);
node->update();
}
}
}
......
......@@ -169,6 +169,8 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
addAutoReleasedObject(MaemoManager::instance());
#endif
new ProFileCacheManager(this);
// TODO reenable
//m_embeddedPropertiesPage = new EmbeddedPropertiesPage;
//addObject(m_embeddedPropertiesPage);
......
......@@ -1207,6 +1207,7 @@ void QtVersion::updateToolChainAndMkspec() const
ProFileOption option;
option.properties = versionInfo();
option.cache = ProFileCacheManager::instance()->cache();
ProFileReader *reader = new ProFileReader(&option);
reader->setCumulative(false);
reader->setParsePreAndPostFiles(false);
......
......@@ -85,11 +85,59 @@ static void clearFunctions(ProFileEvaluator::FunctionDefs *defs)
///////////////////////////////////////////////////////////////////////
//
// ProFileOption
// ProFileCache
//
///////////////////////////////////////////////////////////////////////
ProFileCache::~ProFileCache()
{
foreach (ProFile *pro, parsed_files)
pro->deref();
}
void ProFileCache::discardFile(const QString &fileName)
{
QHash<QString, ProFile *>::Iterator it = parsed_files.find(fileName);
if (it != parsed_files.end()) {
it.value()->deref();
parsed_files.erase(it);
}
}
void ProFileCache::discardFiles(const QString &prefix)
{
QHash<QString, ProFile *>::Iterator
it = parsed_files.begin(),
end = parsed_files.end();
while (it != end)
if (it.key().startsWith(prefix)) {
it.value()->deref();
it = parsed_files.erase(it);
} else {
++it;
}
}
void ProFileCache::addFile(ProFile *pro)
{
parsed_files[pro->fileName()] = pro;
pro->ref();
}
ProFile *ProFileCache::getFile(const QString &fileName)
{
ProFile *pro = parsed_files.value(fileName);
if (pro)
pro->ref();
return pro;
}
///////////////////////////////////////////////////////////////////////
//
// ProFileOption
//
///////////////////////////////////////////////////////////////////////
ProFileOption::ProFileOption()
{
#ifdef Q_OS_WIN
......@@ -112,6 +160,8 @@ ProFileOption::ProFileOption()
#endif
field_sep = QLatin1String(" ");
cache = 0;
}
ProFileOption::~ProFileOption()
......@@ -199,6 +249,8 @@ public:
ProFile *currentProFile() const;
ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments);
ProFile *parsedProFile(const QString &fileName, bool cache,
const QString &contents = QString());
bool evaluateFile(const QString &fileName);
bool evaluateFeatureFile(const QString &fileName,
QHash<QString, QStringList> *values = 0, FunctionDefs *defs = 0);
......@@ -2776,20 +2828,20 @@ QStringList ProFileEvaluator::Private::values(const QString &variableName, const
return values(variableName, m_filevaluemap[pro], pro);
}
// virtual
ProFile *ProFileEvaluator::parsedProFile(const QString &fileName)
{
ProFile *pro = new ProFile(fileName);
if (d->read(pro))
return pro;
delete pro;
return 0;
}
// virtual
void ProFileEvaluator::releaseParsedProFile(ProFile *proFile)
ProFile *ProFileEvaluator::Private::parsedProFile(const QString &fileName, bool cache,
const QString &contents)
{
delete proFile;
ProFile *pro;
if (!m_option->cache || !(pro = m_option->cache->getFile(fileName))) {
pro = new ProFile(fileName);
if (!(contents.isNull() ? read(pro) : read(pro, contents))) {
delete pro;
return 0;
}
if (m_option->cache && cache)
m_option->cache->addFile(pro);
}
return pro;
}
bool ProFileEvaluator::Private::evaluateFile(const QString &fileName)
......@@ -2803,10 +2855,10 @@ bool ProFileEvaluator::Private::evaluateFile(const QString &fileName)
errorMessage(format("circular inclusion of %1").arg(fn));
return false;
}
ProFile *pro = q->parsedProFile(fn);
if (pro) {
if (ProFile *pro = parsedProFile(fn, true)) {
q->aboutToEval(pro);
bool ok = (pro->Accept(this) == ProItem::ReturnTrue);
q->releaseParsedProFile(pro);
pro->deref();
return ok;
} else {
return false;
......@@ -2857,12 +2909,13 @@ bool ProFileEvaluator::Private::evaluateFeatureFile(
bool cumulative = m_cumulative;
m_cumulative = false;
// Don't use evaluateFile() here to avoid the virtual parsedProFile().
// Don't use evaluateFile() here to avoid calling aboutToEval().
// The path is fully normalized already.
ProFile pro(fn);
bool ok = false;
if (read(&pro))
ok = (pro.Accept(this) == ProItem::ReturnTrue);
if (ProFile *pro = parsedProFile(fn, true)) {
ok = (pro->Accept(this) == ProItem::ReturnTrue);
pro->deref();
}
m_cumulative = cumulative;
return ok;
......@@ -3019,14 +3072,9 @@ ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
return TT_Unknown;
}
bool ProFileEvaluator::queryProFile(ProFile *pro)
ProFile *ProFileEvaluator::parsedProFile(const QString &fileName, const QString &contents)
{
return d->read(pro);
}
bool ProFileEvaluator::queryProFile(ProFile *pro, const QString &content)
{
return d->read(pro, content);
return d->parsedProFile(fileName, false, contents);
}
bool ProFileEvaluator::accept(ProFile *pro)
......@@ -3039,6 +3087,10 @@ QString ProFileEvaluator::propertyValue(const QString &name) const
return d->propertyValue(name);
}
void ProFileEvaluator::aboutToEval(ProFile *)
{
}
void ProFileEvaluator::logMessage(const QString &message)
{
qWarning("%s", qPrintable(message));
......
......@@ -42,6 +42,22 @@ QT_BEGIN_NAMESPACE
class ProFileOption;
class ProFileCache
{
public:
ProFileCache() {}
~ProFileCache();
void addFile(ProFile *pro);
ProFile *getFile(const QString &fileName);
void discardFile(const QString &fileName);
void discardFiles(const QString &prefix);
private:
QHash<QString, ProFile *> parsed_files;
};
class ProFileEvaluator
{
class Private;
......@@ -74,8 +90,8 @@ public:
void setConfigCommandLineArguments(const QStringList &addUserConfigCmdArgs, const QStringList &removeUserConfigCmdArgs);
void setParsePreAndPostFiles(bool on); // Default is true
bool queryProFile(ProFile *pro);
bool queryProFile(ProFile *pro, const QString &content); // the same as above but the content is read from "content" string, not from filesystem
// If contents is non-null, it will be used instead of the file's actual content
ProFile *parsedProFile(const QString &fileName, const QString &contents = QString());
bool accept(ProFile *pro);
QStringList values(const QString &variableName) const;
......@@ -87,8 +103,7 @@ public:
QString propertyValue(const QString &val) const;
// for our descendents
virtual ProFile *parsedProFile(const QString &fileName);
virtual void releaseParsedProFile(ProFile *proFile);
virtual void aboutToEval(ProFile *proFile); // only .pri, but not .prf. or .pro
virtual void logMessage(const QString &msg);
virtual void errorMessage(const QString &msg); // .pro parse errors
virtual void fileMessage(const QString &msg); // error() and message() from .pro file
......@@ -130,6 +145,7 @@ struct ProFileOption
QString qmakespec;
QString cachefile;
QHash<QString, QString> properties;
ProFileCache *cache;
enum TARG_MODE { TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE, TARG_MAC9_MODE, TARG_QNX6_MODE };
TARG_MODE target_mode;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment