aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp3
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h20
-rw-r--r--src/qml/memory/qv4mm.cpp27
-rw-r--r--src/qml/memory/qv4mm_p.h10
-rw-r--r--src/qml/memory/qv4mmdefs_p.h4
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml17
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro3
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp21
8 files changed, 84 insertions, 21 deletions
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index bedcb5b164..5fd200efc1 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -120,7 +120,8 @@ void Profiler::startProfiling(quint64 features)
if (features & (1 << FeatureMemoryAllocation)) {
qint64 timestamp = m_timer.nsecsElapsed();
MemoryAllocationProperties heap = {timestamp,
- (qint64)m_engine->memoryManager->getAllocatedMem(),
+ (qint64)m_engine->memoryManager->getAllocatedMem() -
+ (qint64)m_engine->memoryManager->getLargeItemsMem(),
HeapPage};
m_memory_data.append(heap);
MemoryAllocationProperties small = {timestamp,
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 9de597ad0e..08b4ba6c76 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -230,16 +230,24 @@ public:
bool trackAlloc(size_t size, MemoryType type)
{
- MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type};
- m_memory_data.append(allocation);
- return true;
+ if (size) {
+ MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type};
+ m_memory_data.append(allocation);
+ return true;
+ } else {
+ return false;
+ }
}
bool trackDealloc(size_t size, MemoryType type)
{
- MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type};
- m_memory_data.append(allocation);
- return true;
+ if (size) {
+ MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type};
+ m_memory_data.append(allocation);
+ return true;
+ } else {
+ return false;
+ }
}
quint64 featuresEnabled;
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 56f1254421..538be0d16a 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -275,7 +275,7 @@ QString binary(quintptr) { return QString(); }
#define SDUMP if (1) ; else qDebug
#endif
-bool Chunk::sweep()
+bool Chunk::sweep(ExecutionEngine *engine)
{
bool hasUsedSlots = false;
SDUMP() << "sweeping chunk" << this;
@@ -316,6 +316,9 @@ bool Chunk::sweep()
b->_checkIsDestroyed();
}
}
+ Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i])
+ - (blackBitmap[i] | e)) * Chunk::SlotSize,
+ Profiling::SmallItem);
objectBitmap[i] = blackBitmap[i];
hasUsedSlots |= (blackBitmap[i] != 0);
blackBitmap[i] = 0;
@@ -330,7 +333,7 @@ bool Chunk::sweep()
return hasUsedSlots;
}
-void Chunk::freeAll()
+void Chunk::freeAll(ExecutionEngine *engine)
{
// DEBUG << "sweeping chunk" << this << (*freeList);
HeapItem *o = realBase();
@@ -361,6 +364,8 @@ void Chunk::freeAll()
b->_checkIsDestroyed();
}
}
+ Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i])
+ - qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem);
objectBitmap[i] = 0;
blackBitmap[i] = 0;
extendsBitmap[i] = e;
@@ -560,6 +565,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
if (!forceAllocation)
return 0;
Chunk *newChunk = chunkAllocator->allocate();
+ Q_V4_PROFILE_ALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
chunks.push_back(newChunk);
nextFree = newChunk->first();
nFree = Chunk::AvailableSlots;
@@ -570,6 +576,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
done:
m->setAllocatedSlots(slotsRequired);
+ Q_V4_PROFILE_ALLOC(engine, slotsRequired * Chunk::SlotSize, Profiling::SmallItem);
// DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase());
return m;
}
@@ -584,12 +591,13 @@ void BlockAllocator::sweep()
usedSlotsAfterLastSweep = 0;
auto isFree = [this] (Chunk *c) {
- bool isUsed = c->sweep();
+ bool isUsed = c->sweep(engine);
if (isUsed) {
c->sortIntoBins(freeBins, NumBins);
usedSlotsAfterLastSweep += c->nUsedSlots();
} else {
+ Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
chunkAllocator->free(c);
}
return !isUsed;
@@ -602,7 +610,8 @@ void BlockAllocator::sweep()
void BlockAllocator::freeAll()
{
for (auto c : chunks) {
- c->freeAll();
+ c->freeAll(engine);
+ Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
chunkAllocator->free(c);
}
}
@@ -642,6 +651,7 @@ HeapItem *HugeItemAllocator::allocate(size_t size) {
Chunk *c = chunkAllocator->allocate(size);
chunks.push_back(HugeChunk{c, size});
Chunk::setBit(c->objectBitmap, c->first() - c->realBase());
+ Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem);
return c->first();
}
@@ -660,8 +670,10 @@ void HugeItemAllocator::sweep() {
auto isBlack = [this] (const HugeChunk &c) {
bool b = c.chunk->first()->isBlack();
Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
- if (!b)
+ if (!b) {
+ Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem);
freeHugeChunk(chunkAllocator, c);
+ }
return !b;
};
@@ -672,6 +684,7 @@ void HugeItemAllocator::sweep() {
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
+ Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem);
freeHugeChunk(chunkAllocator, c);
}
}
@@ -681,8 +694,8 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
: engine(engine)
, chunkAllocator(new ChunkAllocator)
, stackAllocator(chunkAllocator)
- , blockAllocator(chunkAllocator)
- , hugeItemAllocator(chunkAllocator)
+ , blockAllocator(chunkAllocator, engine)
+ , hugeItemAllocator(chunkAllocator, engine)
, m_persistentValues(new PersistentValueStorage(engine))
, m_weakValues(new PersistentValueStorage(engine))
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 77c5885dfe..e3cccb6aa0 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -117,8 +117,8 @@ struct StackAllocator {
};
struct BlockAllocator {
- BlockAllocator(ChunkAllocator *chunkAllocator)
- : chunkAllocator(chunkAllocator)
+ BlockAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine)
+ : chunkAllocator(chunkAllocator), engine(engine)
{
memset(freeBins, 0, sizeof(freeBins));
#if MM_DEBUG
@@ -161,6 +161,7 @@ struct BlockAllocator {
size_t usedSlotsAfterLastSweep = 0;
HeapItem *freeBins[NumBins];
ChunkAllocator *chunkAllocator;
+ ExecutionEngine *engine;
std::vector<Chunk *> chunks;
#if MM_DEBUG
uint allocations[NumBins];
@@ -168,8 +169,8 @@ struct BlockAllocator {
};
struct HugeItemAllocator {
- HugeItemAllocator(ChunkAllocator *chunkAllocator)
- : chunkAllocator(chunkAllocator)
+ HugeItemAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine)
+ : chunkAllocator(chunkAllocator), engine(engine)
{}
HeapItem *allocate(size_t size);
@@ -184,6 +185,7 @@ struct HugeItemAllocator {
}
ChunkAllocator *chunkAllocator;
+ ExecutionEngine *engine;
struct HugeChunk {
Chunk *chunk;
size_t size;
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index ef93971ab8..7c82fef056 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -179,8 +179,8 @@ struct Chunk {
return usedSlots;
}
- bool sweep();
- void freeAll();
+ bool sweep(ExecutionEngine *engine);
+ void freeAll(ExecutionEngine *engine);
void sortIntoBins(HeapItem **bins, uint nBins);
};
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml
new file mode 100644
index 0000000000..f39dcdf16a
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml
@@ -0,0 +1,17 @@
+import QtQml 2.0
+
+Timer {
+ interval: 1
+ running: true
+
+ function recurse(i) {
+ var x = { t: [1, 2, 3, 4] }
+ console.log(x.t[i]);
+ if (i < 3)
+ recurse(i + 1);
+ else
+ Qt.quit();
+ }
+
+ onTriggered: recurse(0)
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
index f5e3dbdc2f..56840d5c8f 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
@@ -21,4 +21,5 @@ OTHER_FILES += \
data/TestImage_2x2.png \
data/signalSourceLocation.qml \
data/javascript.qml \
- data/timer.qml
+ data/timer.qml \
+ data/memory.qml
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index b8e1f1f21d..bc6c51707a 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -312,6 +312,7 @@ private slots:
void signalSourceLocation();
void javascript();
void flushInterval();
+ void memory();
};
#define VERIFY(type, position, expected, checks) QVERIFY(verify(type, position, expected, checks))
@@ -756,6 +757,26 @@ void tst_QQmlProfilerService::flushInterval()
checkJsHeap();
}
+void tst_QQmlProfilerService::memory()
+{
+ connect(true, "memory.qml");
+ if (QTest::currentTestFailed() || QTestResult::skipCurrentTest())
+ return;
+
+ m_client->sendRecordingStatus(true);
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ int smallItems = 0;
+ for (auto message : m_client->jsHeapMessages) {
+ if (message.detailType == QV4::Profiling::SmallItem)
+ ++smallItems;
+ }
+
+ QVERIFY(smallItems > 5);
+}
+
QTEST_MAIN(tst_QQmlProfilerService)
#include "tst_qqmlprofilerservice.moc"