diff options
-rw-r--r-- | src/qml/debugger/qqmlprofilerdefinitions_p.h | 1 | ||||
-rw-r--r-- | src/qml/debugger/qv4profileradapter.cpp | 39 | ||||
-rw-r--r-- | src/qml/debugger/qv4profileradapter_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4mm.cpp | 20 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling_p.h | 40 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 6 | ||||
-rw-r--r-- | tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp | 13 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerdata.cpp | 3 |
10 files changed, 114 insertions, 19 deletions
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h index 9452260ce4..177b1ae8c4 100644 --- a/src/qml/debugger/qqmlprofilerdefinitions_p.h +++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h @@ -67,6 +67,7 @@ struct QQmlProfilerDefinitions { Complete, // end of transmission PixmapCacheEvent, SceneGraphFrame, + MemoryAllocation, MaximumMessage }; diff --git a/src/qml/debugger/qv4profileradapter.cpp b/src/qml/debugger/qv4profileradapter.cpp index e7b82566d6..cdceb0e533 100644 --- a/src/qml/debugger/qv4profileradapter.cpp +++ b/src/qml/debugger/qv4profileradapter.cpp @@ -58,26 +58,47 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>)), - this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>))); + connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>, + QList<QV4::Profiling::MemoryAllocationProperties>)), + this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>, + QList<QV4::Profiling::MemoryAllocationProperties>))); } +qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages) +{ + QByteArray message; + while (!memory_data.empty() && memory_data.front().timestamp <= until) { + QQmlDebugStream d(&message, QIODevice::WriteOnly); + QV4::Profiling::MemoryAllocationProperties &props = memory_data.front(); + d << props.timestamp << MemoryAllocation << props.type << props.size; + memory_data.pop_front(); + messages.append(message); + } + return memory_data.empty() ? -1 : memory_data.front().timestamp; +} qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { QByteArray message; while (true) { while (!stack.empty() && (data.empty() || stack.top() <= data.front().start)) { - if (stack.top() > until) - return stack.top(); + if (stack.top() > until) { + qint64 memory_next = appendMemoryEvents(until, messages); + return memory_next == -1 ? stack.top() : qMin(stack.top(), memory_next); + } + appendMemoryEvents(stack.top(), messages); QQmlDebugStream d(&message, QIODevice::WriteOnly); d << stack.pop() << RangeEnd << Javascript; messages.append(message); } while (!data.empty() && (stack.empty() || data.front().start < stack.top())) { - if (data.front().start > until) - return data.front().start; const QV4::Profiling::FunctionCallProperties &props = data.front(); + if (props.start > until) { + qint64 memory_next = appendMemoryEvents(until, messages); + return memory_next == -1 ? props.start : qMin(props.start, memory_next); + } + appendMemoryEvents(props.start, messages); + QQmlDebugStream d_start(&message, QIODevice::WriteOnly); d_start << props.start << RangeStart << Javascript; messages.push_back(message); @@ -95,13 +116,15 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message data.pop_front(); } if (stack.empty() && data.empty()) - return -1; + return appendMemoryEvents(until, messages); } } -void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data) +void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data, + const QList<QV4::Profiling::MemoryAllocationProperties> &new_memory_data) { data = new_data; + memory_data = new_memory_data; stack.clear(); service->dataReady(this); } diff --git a/src/qml/debugger/qv4profileradapter_p.h b/src/qml/debugger/qv4profileradapter_p.h index 922aedd828..29bdd606ef 100644 --- a/src/qml/debugger/qv4profileradapter_p.h +++ b/src/qml/debugger/qv4profileradapter_p.h @@ -71,11 +71,14 @@ public: virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages); public slots: - void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &); + void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &, + const QList<QV4::Profiling::MemoryAllocationProperties> &); private: QList<QV4::Profiling::FunctionCallProperties> data; + QList<QV4::Profiling::MemoryAllocationProperties> memory_data; QStack<qint64> stack; + qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages); }; QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8916cc597e..1eab157ecc 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -418,7 +418,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) ExecutionEngine::~ExecutionEngine() { delete debugger; + debugger = 0; delete profiler; + profiler = 0; delete m_multiplyWrappedQObjects; m_multiplyWrappedQObjects = 0; delete identifierTable; diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index ca2ccd33f7..472fa4071a 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -57,6 +57,7 @@ #include <cstdlib> #include <algorithm> #include "qv4alloca_p.h" +#include "qv4profiling_p.h" #ifdef V4_USE_VALGRIND #include <valgrind/valgrind.h> @@ -102,6 +103,7 @@ struct MemoryManager::Data struct LargeItem { LargeItem *next; + size_t size; void *data; Managed *managed() { @@ -149,8 +151,10 @@ struct MemoryManager::Data ~Data() { - for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) + for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) { + Q_V4_PROFILE_DEALLOC(engine, 0, i->memory.size(), Profiling::HeapPage); i->memory.deallocate(); + } } }; @@ -190,9 +194,12 @@ Managed *MemoryManager::alloc(std::size_t size) // doesn't fit into a small bucket if (size >= MemoryManager::Data::MaxItemSize) { // we use malloc for this - MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem))); + MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>( + malloc(Q_V4_PROFILE_ALLOC(engine(), size + sizeof(MemoryManager::Data::LargeItem), + Profiling::LargeItem))); memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem)); item->next = m_d->largeItems; + item->size = size; m_d->largeItems = item; return item->managed(); } @@ -218,7 +225,9 @@ Managed *MemoryManager::alloc(std::size_t size) std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift); allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize); Data::Chunk allocation; - allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages); + allocation.memory = PageAllocation::allocate( + Q_V4_PROFILE_ALLOC(engine(), allocSize, Profiling::HeapPage), + OSAllocator::JSGCHeapPages); allocation.chunkSize = int(size); m_d->heapChunks.append(allocation); std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end()); @@ -247,6 +256,7 @@ Managed *MemoryManager::alloc(std::size_t size) #ifdef V4_USE_VALGRIND VALGRIND_MEMPOOL_ALLOC(this, m, size); #endif + Q_V4_PROFILE_ALLOC(engine(), size, Profiling::SmallItem); ++m_d->allocCount[pos]; ++m_d->totalAlloc; @@ -363,7 +373,8 @@ void MemoryManager::sweep(bool lastSweep) m->internalClass->vtable->destroy(m); *last = i->next; - free(i); + free(Q_V4_PROFILE_DEALLOC(engine(), i, i->size + sizeof(Data::LargeItem), + Profiling::LargeItem)); i = *last; } @@ -409,6 +420,7 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size) VALGRIND_DISABLE_ERROR_REPORTING; VALGRIND_MEMPOOL_FREE(this, m); #endif + Q_V4_PROFILE_DEALLOC(engine(), m, size, Profiling::SmallItem); *f = m; } } diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index 8a0cc56448..f1c70c6b33 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -63,7 +63,9 @@ FunctionCallProperties FunctionCall::resolve() const Profiler::Profiler() : enabled(false) { static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >(); + static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >(); Q_UNUSED(metatype); + Q_UNUSED(metatype2); m_timer.start(); } @@ -87,7 +89,7 @@ void Profiler::reportData() FunctionCallProperties props = call.resolve(); resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); } - emit dataReady(resolved); + emit dataReady(resolved, m_memory_data); } void Profiler::startProfiling() diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 6869b3134d..cafe36861d 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -54,6 +54,12 @@ namespace QV4 { namespace Profiling { +enum MemoryType { + HeapPage, + LargeItem, + SmallItem +}; + struct FunctionCallProperties { qint64 start; qint64 end; @@ -63,6 +69,12 @@ struct FunctionCallProperties { int column; }; +struct MemoryAllocationProperties { + qint64 timestamp; + qint64 size; + MemoryType type; +}; + class FunctionCall { public: @@ -101,6 +113,14 @@ private: qint64 m_end; }; +#define Q_V4_PROFILE_ALLOC(engine, size, type)\ + (engine->profiler && engine->profiler->enabled ?\ + engine->profiler->trackAlloc(size, type) : size) + +#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \ + (engine->profiler && engine->profiler->enabled ?\ + engine->profiler->trackDealloc(pointer, size, type) : pointer) + #define Q_V4_PROFILE(engine, ctx, function)\ ((engine->profiler && engine->profiler->enabled) ?\ Profiling::FunctionCallProfiler::profileCall(engine->profiler, ctx, function) :\ @@ -112,6 +132,20 @@ class Q_QML_EXPORT Profiler : public QObject { public: Profiler(); + size_t trackAlloc(size_t size, MemoryType type) + { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; + m_memory_data.append(allocation); + return size; + } + + void *trackDealloc(void *pointer, size_t size, MemoryType type) + { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)-size, type}; + m_memory_data.append(allocation); + return pointer; + } + bool enabled; public slots: @@ -121,11 +155,13 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &); + void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &, + const QList<QV4::Profiling::MemoryAllocationProperties> &); private: QElapsedTimer m_timer; QVector<FunctionCall> m_data; + QList<MemoryAllocationProperties> m_memory_data; friend class FunctionCallProfiler; }; @@ -160,10 +196,12 @@ public: } // namespace Profiling } // namespace QV4 +Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); QT_END_NAMESPACE Q_DECLARE_METATYPE(QList<QV4::Profiling::FunctionCallProperties>) +Q_DECLARE_METATYPE(QList<QV4::Profiling::MemoryAllocationProperties>) #endif // QV4PROFILING_H diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 610bbcfe1e..f78cdbb970 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -585,9 +585,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - delete rootContext; - rootContext = 0; - for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) (*iter)->release(); for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) @@ -918,6 +915,9 @@ QQmlEngine::~QQmlEngine() QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes(); foreach (QQmlType *currType, singletonTypes) currType->singletonInstanceInfo()->destroy(this); + + delete d->rootContext; + d->rootContext = 0; } /*! \fn void QQmlEngine::quit() diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 5fd985f6d5..2b1b7ce6ec 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -79,6 +79,7 @@ public: Complete, // end of transmission PixmapCacheEvent, SceneGraphFrame, + MemoryAllocation, MaximumMessage }; @@ -131,6 +132,12 @@ public: MaximumSceneGraphFrameType }; + enum MemoryType { + HeapPage, + LargeItem, + SmallItem + }; + QQmlProfilerClient(QQmlDebugConnection *connection) : QQmlDebugClient(QLatin1String("CanvasFrameRate"), connection) { @@ -302,6 +309,12 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message) } break; } + case QQmlProfilerClient::MemoryAllocation: { + stream >> data.detailType; + qint64 amount; + stream >> amount; + return; + } default: QString failMsg = QString("Unknown message type:") + data.messageType; QFAIL(qPrintable(failMsg)); diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp index ce9ce0cf1e..bf2d05ed7b 100644 --- a/tools/qmlprofiler/qmlprofilerdata.cpp +++ b/tools/qmlprofiler/qmlprofilerdata.cpp @@ -69,7 +69,8 @@ static const char *MESSAGE_STRINGS[] = { "RangeEnd", "Complete", "PixmapCache", - "SceneGraph" + "SceneGraph", + "MemoryAllocation" }; Q_STATIC_ASSERT(sizeof(MESSAGE_STRINGS) == |