diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2016-04-21 16:57:10 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2016-05-02 09:03:20 +0000 |
commit | a2e64a20777867726b51a9c9196dc1b8dd68f512 (patch) | |
tree | 3c0462e5b5db214c42f58e3bd6d5e48ae9cc2eed | |
parent | d93daba909d0aeb8a32fe3b0e0a7145b60d77531 (diff) |
V4 profiler: Don't duplicate function locations
Saving the name/file/line/column over and over for each function call
is wasteful. We can instead key them by the pointer to the JS Function
object. Also, make sure we don't accidentally detach the data when
sending messages.
Task-number: QTBUG-52937
Change-Id: I8a03e4003dc3239f88b49c56424df05cd8b9ef8a
Reviewed-by: Anton Kudryavtsev <a.kudryavtsev@netris.ru>
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp | 46 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling.cpp | 40 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling_p.h | 14 |
4 files changed, 73 insertions, 31 deletions
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp index b50eef5545..68a71a5524 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp @@ -61,29 +61,35 @@ 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(QVector<QV4::Profiling::FunctionCallProperties>, + connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>)), - this, SLOT(receiveData(QVector<QV4::Profiling::FunctionCallProperties>, + this, SLOT(receiveData(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>))); } qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d) { - while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) { - QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos]; + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData = m_memoryData; + + while (memoryData.length() > m_memoryPos && memoryData[m_memoryPos].timestamp <= until) { + const QV4::Profiling::MemoryAllocationProperties &props = memoryData[m_memoryPos]; d << props.timestamp << MemoryAllocation << props.type << props.size; ++m_memoryPos; messages.append(d.squeezedData()); d.clear(); } - return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp; + return memoryData.length() == m_memoryPos ? -1 : memoryData[m_memoryPos].timestamp; } qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext, QQmlDebugPacket &d) { if (callNext == -1) { + m_functionLocations.clear(); m_functionCallData.clear(); m_functionCallPos = 0; } @@ -102,10 +108,15 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { QQmlDebugPacket d; + + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData; + const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations; + while (true) { while (!m_stack.isEmpty() && - (m_functionCallPos == m_functionCallData.length() || - m_stack.top() <= m_functionCallData[m_functionCallPos].start)) { + (m_functionCallPos == functionCallData.length() || + m_stack.top() <= functionCallData[m_functionCallPos].start)) { if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, m_stack.top(), d); @@ -114,39 +125,46 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message messages.append(d.squeezedData()); d.clear(); } - while (m_functionCallPos != m_functionCallData.length() && - (m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) { + while (m_functionCallPos != functionCallData.length() && + (m_stack.empty() || functionCallData[m_functionCallPos].start < m_stack.top())) { const QV4::Profiling::FunctionCallProperties &props = - m_functionCallData[m_functionCallPos]; + functionCallData[m_functionCallPos]; if (props.start > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, props.start, d); appendMemoryEvents(props.start, messages, d); + auto location = functionLocations.constFind(props.id); + Q_ASSERT(location != functionLocations.constEnd()); d << props.start << RangeStart << Javascript; messages.push_back(d.squeezedData()); d.clear(); - d << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; + d << props.start << RangeLocation << Javascript << location->file << location->line + << location->column; messages.push_back(d.squeezedData()); d.clear(); - d << props.start << RangeData << Javascript << props.name; + d << props.start << RangeData << Javascript << location->name; messages.push_back(d.squeezedData()); d.clear(); m_stack.push(props.end); ++m_functionCallPos; } - if (m_stack.empty() && m_functionCallPos == m_functionCallData.length()) + if (m_stack.empty() && m_functionCallPos == functionCallData.length()) return finalizeMessages(until, messages, -1, d); } } void QV4ProfilerAdapter::receiveData( + const QV4::Profiling::FunctionLocationHash &locations, const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData, const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData) { // In rare cases it could be that another flush or stop event is processed while data from // the previous one is still pending. In that case we just append the data. + if (m_functionLocations.isEmpty()) + m_functionLocations = locations; + else + m_functionLocations.unite(locations); if (m_functionCallData.isEmpty()) m_functionCallData = functionCallData; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h index f2985af98b..968825c346 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h @@ -74,7 +74,8 @@ signals: void v4ProfilingEnabledWhileWaiting(quint64 v4Features); public slots: - void receiveData(const QVector<QV4::Profiling::FunctionCallProperties> &, + void receiveData(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); private slots: @@ -82,6 +83,7 @@ private slots: void forwardEnabledWhileWaiting(quint64 features); private: + QV4::Profiling::FunctionLocationHash m_functionLocations; QVector<QV4::Profiling::FunctionCallProperties> m_functionCallData; QVector<QV4::Profiling::MemoryAllocationProperties> m_memoryData; int m_functionCallPos; diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index c0a4129d9d..a59190b846 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -46,26 +46,35 @@ QT_BEGIN_NAMESPACE namespace QV4 { namespace Profiling { -FunctionCallProperties FunctionCall::resolve() const +FunctionLocation FunctionCall::resolveLocation() const { - FunctionCallProperties props = { - m_start, - m_end, + FunctionLocation location = { m_function->name()->toQString(), m_function->compilationUnit->fileName(), m_function->compiledFunction->location.line, m_function->compiledFunction->location.column }; - return props; + return location; } +FunctionCallProperties FunctionCall::properties() const +{ + FunctionCallProperties props = { + m_start, + m_end, + reinterpret_cast<quintptr>(m_function) + }; + return props; +} Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine) { - static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(); - static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(); - Q_UNUSED(meta); - Q_UNUSED(meta2); + static const int metatypes[] = { + qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(), + qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(), + qRegisterMetaType<FunctionLocationHash>() + }; + Q_UNUSED(metatypes); m_timer.start(); } @@ -85,13 +94,16 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2) void Profiler::reportData() { std::sort(m_data.begin(), m_data.end()); - QVector<FunctionCallProperties> resolved; - resolved.reserve(m_data.size()); + QVector<FunctionCallProperties> properties; + QHash<qint64, FunctionLocation> locations; + properties.reserve(m_data.size()); - foreach (const FunctionCall &call, m_data) - resolved.append(call.resolve()); + foreach (const FunctionCall &call, m_data) { + properties.append(call.properties()); + locations[properties.constLast().id] = call.resolveLocation(); + } - emit dataReady(resolved, m_memory_data); + emit dataReady(locations, properties, m_memory_data); m_data.clear(); m_memory_data.clear(); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 25ef8223bf..0b4193204f 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -77,12 +77,18 @@ enum MemoryType { struct FunctionCallProperties { qint64 start; qint64 end; + quintptr id; +}; + +struct FunctionLocation { QString name; QString file; int line; int column; }; +typedef QHash<qint64, QV4::Profiling::FunctionLocation> FunctionLocationHash; + struct MemoryAllocationProperties { qint64 timestamp; qint64 size; @@ -118,7 +124,8 @@ public: return *this; } - FunctionCallProperties resolve() const; + FunctionLocation resolveLocation() const; + FunctionCallProperties properties() const; private: friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); @@ -173,7 +180,8 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &, + void dataReady(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); private: @@ -218,8 +226,10 @@ public: 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); +Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE); QT_END_NAMESPACE +Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash) Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>) Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>) |