diff options
author | Ulf Hermann <ulf.hermann@digia.com> | 2014-04-02 12:02:14 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-03 13:59:37 +0200 |
commit | ef2e5a39fa188c0fb229e7847b5ac3f177ba778e (patch) | |
tree | 0ceb8415472c281b5a6c88cd4b3ddf84945606ee | |
parent | cf06b028f71fb80616be7fbb3ef3aaf7d5474eca (diff) |
Use RAII for VME profiler
Now that object creation is done in nested function calls we can
use an RAII-type profiler to trace it. This makes the profiling
much simpler and more robust.
Also, the stack of profiling data in the VME profiler has to match
the stack of completion callbacks in the VME, so the push and pop
operations are synchronized now.
Task-number: QTBUG-37978
Change-Id: I1bc5e0665b88e5b3772e48c8676cdda3fae59e1b
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 1 | ||||
-rw-r--r-- | src/qml/debugger/qqmlprofiler.cpp | 55 | ||||
-rw-r--r-- | src/qml/debugger/qqmlprofiler_p.h | 140 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 35 |
4 files changed, 80 insertions, 151 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index b44d4e285a..087f8df8a5 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1408,6 +1408,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>(); syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString())); + syntheticComponent->location = binding->valueLocation; if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) { QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference; diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp index a0b39744a0..99446e945e 100644 --- a/src/qml/debugger/qqmlprofiler.cpp +++ b/src/qml/debugger/qqmlprofiler.cpp @@ -147,59 +147,4 @@ void QQmlProfiler::reportData() emit dataReady(result); } -/*! - * \fn void QQmlVmeProfiler::Data::clear() - * Resets the profiling data to defaults. - */ - -/*! - * \fn bool QQmlVmeProfiler::startBackground(const QString &typeName) - * If profiling is enabled clears the current range data, then stops the - * profiler previously running in the foreground if any, then starts a new one - * in the background, setting the given typeName. \a typeName is the type of - * object being created. - */ - -/*! - * \fn bool QQmlVmeProfiler::start(const QString &typeName, const QUrl &url, int line, int column) - * If profiling is enabled clears the current range data, then stops the - * profiler previously running in the foreground if any, then starts a new one - * in the foreground, setting the given location. \a url is the URL of - * file being executed, \a line is the current line in in that file, and - * \a column is the current column in that file. - */ - -/*! - * \fn bool QQmlVmeProfiler::pop() - * Stops the currently running profiler, if any, then retrieves an old one from the stack - * of paused profilers and starts that if possible. - */ - -/*! - * \fn void QQmlVmeProfiler::push() - * Pushes the currently running profiler on the stack of paused profilers. Note: The profiler - * isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that - * won't do any harm, though. - */ - -/*! - * \fn void QQmlVmeProfiler::clear(bool stopProfiling = false) - * Stops the currently running (foreground and background) profilers and removes all saved - * data about paused profilers. - */ - -/*! - * \fn void QQmlVmeProfiler::stop() - * Stop profiler running in the foreground, if any. - */ - -/*! - * \fn bool QQmlVmeProfiler::foreground(const QUrl &url, int line, int column) - * Stops the profiler currently running in the foreground, if any and puts the - * next profiler from the background in its place if there are any profilers in - * the background. Additionally the rangeLocation is set. \a url is the URL of - * file being executed, \a line is the current line in in that file, and - * \a column is the current column in that file. - */ - QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 6afdc1e73b..84001905ab 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -55,6 +55,7 @@ #include <private/qv4function_p.h> #include <private/qqmlboundsignal_p.h> +#include <private/qfinitestack_p.h> #include "qqmlprofilerdefinitions_p.h" #include "qqmlabstractprofileradapter_p.h" @@ -142,6 +143,11 @@ public: location.sourceFile, location.line, location.column)); } + void startCreating() + { + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, 1 << Creating)); + } + void startCreating(const QString &typeName, const QUrl &fileName, int line, int column) { m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), @@ -149,16 +155,11 @@ public: 1 << Creating, typeName, fileName, line, column)); } - void startCreating(const QString &typeName) - { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeData), - 1 << Creating, typeName)); - } - - void creatingLocation(const QUrl &fileName, int line, int column) + void updateCreating(const QString &typeName, const QUrl &fileName, int line, int column) { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeLocation, 1 << Creating, - fileName, line, column)); + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), + (1 << RangeLocation | 1 << RangeData), + 1 << Creating, typeName, fileName, line, column)); } template<RangeType Range> @@ -246,108 +247,91 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper { } }; -#define Q_QML_VME_PROFILE(profilerMember, Method) Q_QML_PROFILE_IF_ENABLED(profilerMember.profiler, profilerMember.Method) - struct QQmlVmeProfiler : public QQmlProfilerDefinitions { public: struct Data { - Data() : line(0), column(0) {} - QUrl url; - int line; - int column; - QString typeName; + Data() : m_line(0), m_column(0) {} + QUrl m_url; + int m_line; + int m_column; + QString m_typeName; }; - QQmlVmeProfiler() : profiler(0), running(false) {} + QQmlVmeProfiler() : profiler(0) {} - void clear(bool stopProfiling = false) + void init(QQmlProfiler *p, int maxDepth) { - ranges.clear(); - if (running) - profiler->endRange<Creating>(); - for (int i = 0; i < backgroundRanges.count(); ++i) { - profiler->endRange<Creating>(); - } - backgroundRanges.clear(); - running = false; - if (stopProfiling) profiler = 0; + profiler = p; + ranges.allocate(maxDepth); } - void startBackground(const QString &typeName) + Data pop() { - if (running) { - profiler->endRange<Creating>(); - running = false; - } - profiler->startCreating(typeName); - backgroundRanges.push(typeName); + if (ranges.count() > 0) + return ranges.pop(); + else + return Data(); } - void start(const QString &typeName, const QUrl &url, int line, int column) + void push(const Data &data) { - switchRange(); - setCurrentRange(typeName, url, line, column); - profiler->startCreating(typeName, url, line, column); + if (ranges.capacity() > ranges.count()) + ranges.push(data); } - void stop() - { - if (running) { - profiler->endRange<Creating>(); - running = false; - } - } + QQmlProfiler *profiler; - void pop() +private: + QFiniteStack<Data> ranges; +}; + +#define Q_QML_OC_PROFILE(profilerMember, Code)\ + Q_QML_PROFILE_IF_ENABLED(profilerMember.profiler, Code) + +class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data { +public: + + QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler) { - if (ranges.count() > 0) { - switchRange(); - currentRange = ranges.pop(); - profiler->startCreating(currentRange.typeName, currentRange.url, - currentRange.line, currentRange.column); - } + Q_QML_PROFILE(profiler, startCreating()); } - void push() + ~QQmlObjectCreationProfiler() { - if (running) - ranges.push(currentRange); + Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>()); } - void foreground(const QUrl &url, int line, int column) + void update(const QString &typeName, const QUrl &url, int line, int column) { - if (backgroundRanges.count() > 0) { - switchRange(); - setCurrentRange(backgroundRanges.pop(), url, line, column); - profiler->creatingLocation(url, line, column); - } + profiler->updateCreating(typeName, url, line, column); + m_typeName = typeName; + m_url = url; + m_line = line; + m_column = column; } - QQmlProfiler *profiler; - private: + QQmlProfiler *profiler; +}; - void switchRange() +class QQmlObjectCompletionProfiler { +public: + QQmlObjectCompletionProfiler(QQmlVmeProfiler *parent) : + profiler(parent->profiler) { - if (running) - profiler->endRange<Creating>(); - else - running = true; + Q_QML_PROFILE_IF_ENABLED(profiler, { + QQmlVmeProfiler::Data data = parent->pop(); + profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column); + }); } - void setCurrentRange(const QString &typeName, const QUrl &url, int line, int column) + ~QQmlObjectCompletionProfiler() { - currentRange.typeName = typeName; - currentRange.url = url; - currentRange.line = line; - currentRange.column = column; + Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>()); } - - Data currentRange; - QStack<Data> ranges; - QStack<QString> backgroundRanges; - bool running; +private: + QQmlProfiler *profiler; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index d0c635b007..2ebf90c9be 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -98,7 +98,10 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount); sharedState->creationContext = creationContext; sharedState->rootContext = 0; - sharedState->profiler.profiler = QQmlEnginePrivate::get(engine)->profiler; + + QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler; + Q_QML_PROFILE_IF_ENABLED(profiler, + sharedState->profiler.init(profiler, compiledData->totalParserStatusCount)); } QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState) @@ -223,8 +226,6 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI ddata->compiledData->addref(); } - Q_QML_VME_PROFILE(sharedState->profiler, stop()); - phase = CreatingObjectsPhase2; if (interrupt && interrupt->shouldInterrupt()) @@ -1014,6 +1015,7 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) { + QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler); ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); bool isComponent = false; @@ -1023,21 +1025,23 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QQmlParserStatus *parserStatus = 0; bool installPropertyCache = true; + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); if (compiledData->isComponent(index)) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"), + context->url, obj->location.line, obj->location.column)); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); } else { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; QQmlType *type = typeRef->type; if (type) { - Q_QML_VME_PROFILE(sharedState->profiler, start(type->qmlTypeName(), context->url, obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(), + context->url, obj->location.line, obj->location.column)); instance = type->create(); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1059,15 +1063,16 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->component); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name, + context->url, obj->location.line, obj->location.column)); if (typeRef->component->qmlUnit->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } - Q_QML_VME_PROFILE(sharedState->profiler, startBackground(typeRef->component->name)); + QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data()); instance = subCreator.create(); - Q_QML_VME_PROFILE(sharedState->profiler, foreground(context->url, obj->location.line, obj->location.column)); if (!instance) { errors += subCreator.errors; return 0; @@ -1100,6 +1105,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (parserStatus) { parserStatus->classBegin(); + // push() the profiler state here, together with the parserStatus, as we'll pop() them + // together, too. + Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler)); sharedState->allParserStatusCallbacks.push(parserStatus); parserStatus->d = &sharedState->allParserStatusCallbacks.top(); } @@ -1186,7 +1194,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later QQmlTrace trace("VME Component Complete"); while (!sharedState->allParserStatusCallbacks.isEmpty()) { - Q_QML_VME_PROFILE(sharedState->profiler, pop()); + QQmlObjectCompletionProfiler profiler(&sharedState->profiler); QQmlParserStatus *status = sharedState->allParserStatusCallbacks.pop(); if (status && status->d) { @@ -1197,7 +1205,6 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; } - Q_QML_VME_PROFILE(sharedState->profiler, clear()); } { @@ -1246,20 +1253,12 @@ void QQmlObjectCreator::clear() while (!sharedState->allCreatedObjects.isEmpty()) delete sharedState->allCreatedObjects.pop(); - // If profiling is switched off during a VME run and then switched back on - // before or during the next run background ranges from the first run will - // be reported in the second run because we don't clear() here. We accept - // that as the collected data will be incomplete anyway and because not - // calling clear() here is benefitial for the non-profiling case. - Q_QML_VME_PROFILE(sharedState->profiler, clear(true)); - phase = Done; } bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - Q_QML_VME_PROFILE(sharedState->profiler, push()); QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); |