aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h1
-rw-r--r--src/qml/debugger/qv4profileradapter.cpp39
-rw-r--r--src/qml/debugger/qv4profileradapter_p.h5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp2
-rw-r--r--src/qml/jsruntime/qv4mm.cpp20
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp4
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h40
-rw-r--r--src/qml/qml/qqmlengine.cpp6
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp13
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp3
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) ==