diff options
Diffstat (limited to 'src/qmldebug/qqmlprofilerclient.cpp')
-rw-r--r-- | src/qmldebug/qqmlprofilerclient.cpp | 509 |
1 files changed, 244 insertions, 265 deletions
diff --git a/src/qmldebug/qqmlprofilerclient.cpp b/src/qmldebug/qqmlprofilerclient.cpp index 3676bd933c..d2a2d24f13 100644 --- a/src/qmldebug/qqmlprofilerclient.cpp +++ b/src/qmldebug/qqmlprofilerclient.cpp @@ -43,337 +43,316 @@ QT_BEGIN_NAMESPACE -QQmlProfilerClient::QQmlProfilerClient(QQmlDebugConnection *connection) : - QQmlDebugClient(*(new QQmlProfilerClientPrivate(connection))) +int QQmlProfilerClientPrivate::resolveType(const QQmlProfilerTypedEvent &event) { -} + int typeIndex = -1; + if (event.serverTypeId != 0) { + QHash<qint64, int>::ConstIterator it = serverTypeIds.constFind(event.serverTypeId); -QQmlProfilerClient::QQmlProfilerClient(QQmlProfilerClientPrivate &dd) : - QQmlDebugClient(dd) -{ + if (it != serverTypeIds.constEnd()) { + typeIndex = it.value(); + } else { + typeIndex = eventReceiver->numLoadedEventTypes(); + eventReceiver->addEventType(event.type); + serverTypeIds[event.serverTypeId] = typeIndex; + } + } else { + QHash<QQmlProfilerEventType, int>::ConstIterator it = eventTypeIds.constFind(event.type); + + if (it != eventTypeIds.constEnd()) { + typeIndex = it.value(); + } else { + typeIndex = eventReceiver->numLoadedEventTypes(); + eventReceiver->addEventType(event.type); + eventTypeIds[event.type] = typeIndex; + } + } + return typeIndex; } -QQmlProfilerClientPrivate::QQmlProfilerClientPrivate(QQmlDebugConnection *connection) : - QQmlDebugClientPrivate(QQmlProfilerService::s_key, connection), - features(std::numeric_limits<quint64>::max()) +int QQmlProfilerClientPrivate::resolveStackTop() { + if (rangesInProgress.isEmpty()) + return -1; + + QQmlProfilerTypedEvent &typedEvent = rangesInProgress.top(); + int typeIndex = typedEvent.event.typeIndex(); + if (typeIndex >= 0) + return typeIndex; + + typeIndex = resolveType(typedEvent); + typedEvent.event.setTypeIndex(typeIndex); + while (!pendingMessages.isEmpty() + && pendingMessages.head().timestamp() < typedEvent.event.timestamp()) { + forwardEvents(pendingMessages.dequeue()); + } + forwardEvents(typedEvent.event); + return typeIndex; } -void QQmlProfilerClient::setFeatures(quint64 features) +void QQmlProfilerClientPrivate::forwardEvents(const QQmlProfilerEvent &last) { - Q_D(QQmlProfilerClient); - d->features = features; + while (!pendingDebugMessages.isEmpty() + && pendingDebugMessages.front().timestamp() <= last.timestamp()) { + eventReceiver->addEvent(pendingDebugMessages.dequeue()); + } + eventReceiver->addEvent(last); } -void QQmlProfilerClient::sendRecordingStatus(bool record, int engineId, quint32 flushInterval) +void QQmlProfilerClientPrivate::processCurrentEvent() { - Q_D(const QQmlProfilerClient); - - QPacket stream(d->connection->currentDataStreamVersion()); - stream << record << engineId << d->features << flushInterval << true; - sendMessage(stream.data()); + // RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore, + // all ranges are perfectly nested. This is why we can defer the type resolution until either + // the range ends or a child range starts. With only the information in RangeStart we wouldn't + // be able to uniquely identify the event type. + Message rangeStage = currentEvent.type.rangeType() == MaximumRangeType ? + currentEvent.type.message() : currentEvent.event.rangeStage(); + switch (rangeStage) { + case RangeStart: + resolveStackTop(); + rangesInProgress.push(currentEvent); + break; + case RangeEnd: { + int typeIndex = resolveStackTop(); + if (typeIndex == -1) + break; + currentEvent.event.setTypeIndex(typeIndex); + while (!pendingMessages.isEmpty()) + forwardEvents(pendingMessages.dequeue()); + forwardEvents(currentEvent.event); + rangesInProgress.pop(); + break; + } + case RangeData: + if (!rangesInProgress.isEmpty()) + rangesInProgress.top().type.setData(currentEvent.type.data()); + break; + case RangeLocation: + if (!rangesInProgress.isEmpty()) + rangesInProgress.top().type.setLocation(currentEvent.type.location()); + break; + case DebugMessage: + currentEvent.event.setTypeIndex(resolveType(currentEvent)); + pendingDebugMessages.enqueue(currentEvent.event); + break; + default: { + int typeIndex = resolveType(currentEvent); + currentEvent.event.setTypeIndex(typeIndex); + if (rangesInProgress.isEmpty()) + eventReceiver->addEvent(currentEvent.event); + else + pendingMessages.enqueue(currentEvent.event); + break; + } + } } -void QQmlProfilerClient::traceStarted(qint64 time, int engineId) +void QQmlProfilerClientPrivate::sendRecordingStatus(int engineId) { - Q_UNUSED(time); - Q_UNUSED(engineId); + Q_Q(QQmlProfilerClient); + QPacket stream(connection->currentDataStreamVersion()); + stream << recording << engineId; // engineId -1 is OK. It means "all of them" + if (recording) { + stream << requestedFeatures << flushInterval; + stream << true; // yes, we support type IDs + } + q->sendMessage(stream.data()); } -void QQmlProfilerClient::traceFinished(qint64 time, int engineId) +QQmlProfilerClient::QQmlProfilerClient(QQmlDebugConnection *connection, + QQmlProfilerEventReceiver *eventReceiver, + quint64 features) + : QQmlDebugClient(*(new QQmlProfilerClientPrivate(connection, eventReceiver))) { - Q_UNUSED(time); - Q_UNUSED(engineId); + Q_D(QQmlProfilerClient); + setRequestedFeatures(features); + connect(d->engineControl.data(), &QQmlEngineControlClient::engineAboutToBeAdded, + this, &QQmlProfilerClient::sendRecordingStatus); + connect(d->engineControl.data(), &QQmlEngineControlClient::engineAboutToBeRemoved, + this, [d](int engineId) { + // We may already be done with that engine. Then we don't need to block it. + if (d->trackedEngines.contains(engineId)) + d->engineControl->blockEngine(engineId); + }); + connect(this, &QQmlProfilerClient::traceFinished, + d->engineControl.data(), [d](qint64 timestamp, const QList<int> &engineIds) { + Q_UNUSED(timestamp); + // The engines might not be blocked because the trace can get finished before engine control + // sees them. + for (int blocked : d->engineControl->blockedEngines()) { + if (engineIds.contains(blocked)) + d->engineControl->releaseEngine(blocked); + } + }); } -void QQmlProfilerClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) +QQmlProfilerClient::~QQmlProfilerClient() { - Q_UNUSED(type); - Q_UNUSED(startTime); + //Disable profiling if started by client + //Profiling data will be lost!! + if (isRecording()) + setRecording(false); } -void QQmlProfilerClient::rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QString &data) +void QQmlProfilerClient::clearEvents() { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(data); + Q_D(QQmlProfilerClient); + d->rangesInProgress.clear(); + d->pendingMessages.clear(); + d->pendingDebugMessages.clear(); + if (d->recordedFeatures != 0) { + d->recordedFeatures = 0; + emit recordedFeaturesChanged(0); + } + emit cleared(); } -void QQmlProfilerClient::rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QQmlEventLocation &location) +void QQmlProfilerClient::clearAll() { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(location); + Q_D(QQmlProfilerClient); + d->serverTypeIds.clear(); + d->eventTypeIds.clear(); + d->trackedEngines.clear(); + clearEvents(); } -void QQmlProfilerClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) +void QQmlProfilerClientPrivate::finalize() { - Q_UNUSED(type); - Q_UNUSED(endTime); + while (!rangesInProgress.isEmpty()) { + currentEvent = rangesInProgress.top(); + currentEvent.event.setRangeStage(RangeEnd); + currentEvent.event.setTimestamp(maximumTime); + processCurrentEvent(); + } + while (!pendingDebugMessages.isEmpty()) + eventReceiver->addEvent(pendingDebugMessages.dequeue()); } -void QQmlProfilerClient::animationFrame(qint64 time, int frameRate, int animationCount, - int threadId) + +void QQmlProfilerClient::sendRecordingStatus(int engineId) { - Q_UNUSED(time); - Q_UNUSED(frameRate); - Q_UNUSED(animationCount); - Q_UNUSED(threadId); + Q_D(QQmlProfilerClient); + d->sendRecordingStatus(engineId); } -void QQmlProfilerClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, - qint64 time, qint64 numericData1, qint64 numericData2, - qint64 numericData3, qint64 numericData4, - qint64 numericData5) +bool QQmlProfilerClient::isRecording() const { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(numericData1); - Q_UNUSED(numericData2); - Q_UNUSED(numericData3); - Q_UNUSED(numericData4); - Q_UNUSED(numericData5); + Q_D(const QQmlProfilerClient); + return d->recording; } -void QQmlProfilerClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, - qint64 time, const QString &url, int numericData1, - int numericData2) +void QQmlProfilerClient::setRecording(bool v) { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(url); - Q_UNUSED(numericData1); - Q_UNUSED(numericData2); + Q_D(QQmlProfilerClient); + if (v == d->recording) + return; + + d->recording = v; + + if (state() == Enabled) + sendRecordingStatus(); + + emit recordingChanged(v); } -void QQmlProfilerClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, - qint64 amount) +quint64 QQmlProfilerClient::recordedFeatures() const { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(amount); + Q_D(const QQmlProfilerClient); + return d->recordedFeatures; } -void QQmlProfilerClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, - int a, int b) +void QQmlProfilerClient::setRequestedFeatures(quint64 features) { - Q_UNUSED(type); - Q_UNUSED(time); - Q_UNUSED(a); - Q_UNUSED(b); + Q_D(QQmlProfilerClient); + d->requestedFeatures = features; + if (features & static_cast<quint64>(1) << ProfileDebugMessages) { + if (d->messageClient.isNull()) { + d->messageClient.reset(new QQmlDebugMessageClient(connection())); + connect(d->messageClient.data(), &QQmlDebugMessageClient::message, this, + [this](QtMsgType type, const QString &text, const QQmlDebugContextInfo &context) + { + Q_D(QQmlProfilerClient); + d->updateFeatures(ProfileDebugMessages); + d->currentEvent.event.setTimestamp(context.timestamp > 0 ? context.timestamp : 0); + d->currentEvent.event.setTypeIndex(-1); + d->currentEvent.event.setString(text); + d->currentEvent.type = QQmlProfilerEventType( + DebugMessage, MaximumRangeType, type, + QQmlProfilerEventLocation(context.file, context.line, 1)); + d->currentEvent.serverTypeId = 0; + d->processCurrentEvent(); + }); + } + } else { + d->messageClient.reset(); + } } -void QQmlProfilerClient::complete() +void QQmlProfilerClient::setFlushInterval(quint32 flushInterval) { + Q_D(QQmlProfilerClient); + d->flushInterval = flushInterval; } -void QQmlProfilerClient::unknownEvent(QQmlProfilerDefinitions::Message messageType, qint64 time, - int detailType) +QQmlProfilerClient::QQmlProfilerClient(QQmlProfilerClientPrivate &dd) : + QQmlDebugClient(dd) { - Q_UNUSED(messageType); - Q_UNUSED(time); - Q_UNUSED(detailType); + Q_D(QQmlProfilerClient); + connect(d->engineControl.data(), &QQmlEngineControlClient::engineAboutToBeAdded, + this, &QQmlProfilerClient::sendRecordingStatus); } -void QQmlProfilerClient::unknownData(QPacket &stream) +bool QQmlProfilerClientPrivate::updateFeatures(ProfileFeature feature) { - Q_UNUSED(stream); + Q_Q(QQmlProfilerClient); + quint64 flag = 1ULL << feature; + if (!(requestedFeatures & flag)) + return false; + if (!(recordedFeatures & flag)) { + recordedFeatures |= flag; + emit q->recordedFeaturesChanged(recordedFeatures); + } + return true; } -inline QQmlProfilerDefinitions::ProfileFeature featureFromRangeType( - QQmlProfilerDefinitions::RangeType range) +void QQmlProfilerClient::stateChanged(State status) { - switch (range) { - case QQmlProfilerDefinitions::Painting: - return QQmlProfilerDefinitions::ProfilePainting; - case QQmlProfilerDefinitions::Compiling: - return QQmlProfilerDefinitions::ProfileCompiling; - case QQmlProfilerDefinitions::Creating: - return QQmlProfilerDefinitions::ProfileCreating; - case QQmlProfilerDefinitions::Binding: - return QQmlProfilerDefinitions::ProfileBinding; - case QQmlProfilerDefinitions::HandlingSignal: - return QQmlProfilerDefinitions::ProfileHandlingSignal; - case QQmlProfilerDefinitions::Javascript: - return QQmlProfilerDefinitions::ProfileJavaScript; - default: - return QQmlProfilerDefinitions::MaximumProfileFeature; + if (status == Enabled) { + sendRecordingStatus(-1); + } else { + Q_D(QQmlProfilerClient); + d->finalize(); } + } void QQmlProfilerClient::messageReceived(const QByteArray &data) { Q_D(QQmlProfilerClient); - QPacket stream(d->connection->currentDataStreamVersion(), data); - // Force all the 1 << <FLAG> expressions to be done in 64 bit, to silence some warnings - const quint64 one = static_cast<quint64>(1); - - qint64 time; - int messageType; - - stream >> time >> messageType; - - if (messageType >= QQmlProfilerDefinitions::MaximumMessage) { - unknownEvent(static_cast<QQmlProfilerDefinitions::Message>(messageType), time, -1); - return; + stream >> d->currentEvent; + + d->maximumTime = qMax(d->currentEvent.event.timestamp(), d->maximumTime); + if (d->currentEvent.type.message() == Complete) { + d->finalize(); + emit complete(d->maximumTime); + } else if (d->currentEvent.type.message() == Event + && d->currentEvent.type.detailType() == StartTrace) { + const QList<int> engineIds = d->currentEvent.event.numbers<QList<int>, qint32>(); + d->trackedEngines.append(engineIds); + emit traceStarted(d->currentEvent.event.timestamp(), engineIds); + } else if (d->currentEvent.type.message() == Event + && d->currentEvent.type.detailType() == EndTrace) { + const QList<int> engineIds = d->currentEvent.event.numbers<QList<int>, qint32>(); + for (int engineId : engineIds) + d->trackedEngines.removeAll(engineId); + emit traceFinished(d->currentEvent.event.timestamp(), engineIds); + } else if (d->updateFeatures(d->currentEvent.type.feature())) { + d->processCurrentEvent(); } - - if (messageType == QQmlProfilerDefinitions::Event) { - int type; - stream >> type; - - QQmlProfilerDefinitions::EventType eventType = - static_cast<QQmlProfilerDefinitions::EventType>(type); - - if (eventType == QQmlProfilerDefinitions::EndTrace) { - int engineId = -1; - if (!stream.atEnd()) - stream >> engineId; - traceFinished(time, engineId); - } else if (eventType == QQmlProfilerDefinitions::AnimationFrame) { - if (!(d->features & one << QQmlProfilerDefinitions::ProfileAnimations)) - return; - - int frameRate, animationCount; - int threadId = 0; - stream >> frameRate >> animationCount; - if (!stream.atEnd()) - stream >> threadId; - - animationFrame(time, frameRate, animationCount, threadId); - } else if (type == QQmlProfilerDefinitions::StartTrace) { - int engineId = -1; - if (!stream.atEnd()) - stream >> engineId; - traceStarted(time, engineId); - } else if (eventType == QQmlProfilerDefinitions::Key || - eventType == QQmlProfilerDefinitions::Mouse) { - - if (!(d->features & one << QQmlProfilerDefinitions::ProfileInputEvents)) - return; - - int type; - if (!stream.atEnd()) { - stream >> type; - } else { - type = (eventType == QQmlProfilerDefinitions::Key) ? - QQmlProfilerDefinitions::InputKeyUnknown : - QQmlProfilerDefinitions::InputMouseUnknown; - } - - int a = 0; - if (!stream.atEnd()) - stream >> a; - - int b = 0; - if (!stream.atEnd()) - stream >> b; - - inputEvent(static_cast<QQmlProfilerDefinitions::InputEventType>(type), time, a, b); - } else { - unknownEvent(QQmlProfilerDefinitions::Event, time, type); - } - } else if (messageType == QQmlProfilerDefinitions::Complete) { - complete(); - } else if (messageType == QQmlProfilerDefinitions::SceneGraphFrame) { - if (!(d->features & one << QQmlProfilerDefinitions::ProfileSceneGraph)) - return; - - int type; - int count = 0; - qint64 params[5]; - - stream >> type; - while (!stream.atEnd()) - stream >> params[count++]; - - while (count < 5) - params[count++] = 0; - - sceneGraphEvent(static_cast<QQmlProfilerDefinitions::SceneGraphFrameType>(type), time, - params[0], params[1], params[2], params[3], params[4]); - } else if (messageType == QQmlProfilerDefinitions::PixmapCacheEvent) { - if (!(d->features & one << QQmlProfilerDefinitions::ProfilePixmapCache)) - return; - - int type, param1 = 0, param2 = 0; - QString pixUrl; - stream >> type >> pixUrl; - - QQmlProfilerDefinitions::PixmapEventType pixmapEventType = - static_cast<QQmlProfilerDefinitions::PixmapEventType>(type); - - if (pixmapEventType == QQmlProfilerDefinitions::PixmapReferenceCountChanged || - pixmapEventType == QQmlProfilerDefinitions::PixmapCacheCountChanged) { - stream >> param1; - } else if (pixmapEventType == QQmlProfilerDefinitions::PixmapSizeKnown) { - stream >> param1 >> param2; - } - - pixmapCacheEvent(pixmapEventType, time, pixUrl, param1, param2); - } else if (messageType == QQmlProfilerDefinitions::MemoryAllocation) { - if (!(d->features & one << QQmlProfilerDefinitions::ProfileMemory)) - return; - int type; - qint64 delta; - stream >> type >> delta; - memoryAllocation((QQmlProfilerDefinitions::MemoryType)type, time, delta); - } else { - int range; - stream >> range; - - QQmlProfilerDefinitions::RangeType rangeType = - static_cast<QQmlProfilerDefinitions::RangeType>(range); - - if (range >= QQmlProfilerDefinitions::MaximumRangeType || - !(d->features & one << featureFromRangeType(rangeType))) - return; - - qint64 typeId = 0; - if (messageType == QQmlProfilerDefinitions::RangeStart) { - rangeStart(rangeType, time); - if (!stream.atEnd()) { - stream >> typeId; - auto i = d->types.constFind(typeId); - if (i != d->types.constEnd()) { - rangeLocation(rangeType, time, i->location); - rangeData(rangeType, time, i->name); - } - } - } else if (messageType == QQmlProfilerDefinitions::RangeData) { - QString data; - stream >> data; - rangeData(rangeType, time, data); - if (!stream.atEnd()) { - stream >> typeId; - d->types[typeId].name = data; - } - } else if (messageType == QQmlProfilerDefinitions::RangeLocation) { - QQmlEventLocation location; - stream >> location.filename >> location.line; - - if (!stream.atEnd()) - stream >> location.column; - - rangeLocation(rangeType, time, location); - if (!stream.atEnd()) { - stream >> typeId; - d->types[typeId].location = location; - } - } else if (messageType == QQmlProfilerDefinitions::RangeEnd) { - rangeEnd(rangeType, time); - } else { - unknownEvent(static_cast<QQmlProfilerDefinitions::Message>(messageType), time, range); - } - } - - if (!stream.atEnd()) - unknownData(stream); } + QT_END_NAMESPACE #include "moc_qqmlprofilerclient_p.cpp" |