2012-02-09 16:04:43 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
** Contact: http://www.qt.io/licensing/
|
2012-02-09 16:04:43 +00:00
|
|
|
**
|
2012-02-16 04:43:03 +00:00
|
|
|
** This file is part of the QtQml module of the Qt Toolkit.
|
2012-02-09 16:04:43 +00:00
|
|
|
**
|
2014-08-22 06:13:59 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
2012-09-20 05:21:40 +00:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-28 11:55:39 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
2012-09-20 05:21:40 +00:00
|
|
|
**
|
2012-02-09 16:04:43 +00:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-09-20 05:21:40 +00:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-08-22 06:13:59 +00:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-02-09 16:04:43 +00:00
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2012-02-09 16:04:43 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2012-03-08 15:50:14 +00:00
|
|
|
#include "qmlprofilerclient.h"
|
2012-02-09 16:04:43 +00:00
|
|
|
|
|
|
|
#include <QtCore/QStack>
|
|
|
|
#include <QtCore/QStringList>
|
2015-07-08 14:03:51 +00:00
|
|
|
#include <QtCore/QDataStream>
|
2012-02-09 16:04:43 +00:00
|
|
|
|
2015-07-28 13:58:07 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2012-03-08 15:50:14 +00:00
|
|
|
class QmlProfilerClientPrivate
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
|
|
|
public:
|
2012-03-08 15:50:14 +00:00
|
|
|
QmlProfilerClientPrivate()
|
2015-09-15 13:14:40 +00:00
|
|
|
: inProgressRanges(0) , features(std::numeric_limits<quint64>::max()), enabled(false)
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
2015-07-08 14:03:51 +00:00
|
|
|
::memset(rangeCount, 0, QQmlProfilerDefinitions::MaximumRangeType * sizeof(int));
|
2012-02-09 16:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 inProgressRanges;
|
2015-07-08 14:03:51 +00:00
|
|
|
QStack<qint64> rangeStartTimes[QQmlProfilerDefinitions::MaximumRangeType];
|
|
|
|
QStack<QStringList> rangeDatas[QQmlProfilerDefinitions::MaximumRangeType];
|
|
|
|
QStack<QmlEventLocation> rangeLocations[QQmlProfilerDefinitions::MaximumRangeType];
|
|
|
|
int rangeCount[QQmlProfilerDefinitions::MaximumRangeType];
|
2015-05-21 08:35:42 +00:00
|
|
|
|
|
|
|
quint64 features;
|
2015-09-15 13:14:40 +00:00
|
|
|
bool enabled;
|
2012-02-09 16:04:43 +00:00
|
|
|
};
|
|
|
|
|
2015-09-15 13:14:40 +00:00
|
|
|
QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *client)
|
|
|
|
: QQmlDebugClient(QStringLiteral("CanvasFrameRate"), client),
|
2012-03-08 15:50:14 +00:00
|
|
|
d(new QmlProfilerClientPrivate)
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-03-08 15:50:14 +00:00
|
|
|
QmlProfilerClient::~QmlProfilerClient()
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
2015-05-21 08:35:42 +00:00
|
|
|
void QmlProfilerClient::setFeatures(quint64 features)
|
|
|
|
{
|
|
|
|
d->features = features;
|
|
|
|
}
|
|
|
|
|
2012-03-08 15:50:14 +00:00
|
|
|
void QmlProfilerClient::clearData()
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
2015-09-15 13:14:40 +00:00
|
|
|
for (int i = 0; i < QQmlProfilerDefinitions::MaximumRangeType; ++i) {
|
|
|
|
d->rangeCount[i] = 0;
|
|
|
|
d->rangeDatas[i].clear();
|
|
|
|
d->rangeLocations[i].clear();
|
|
|
|
}
|
2012-02-09 16:04:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 12:50:06 +00:00
|
|
|
void QmlProfilerClient::sendRecordingStatus(bool record)
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
|
|
|
QByteArray ba;
|
|
|
|
QDataStream stream(&ba, QIODevice::WriteOnly);
|
2015-05-21 08:35:42 +00:00
|
|
|
stream << record << -1 << d->features;
|
2012-02-09 16:04:43 +00:00
|
|
|
sendMessage(ba);
|
|
|
|
}
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
inline QQmlProfilerDefinitions::ProfileFeature featureFromRangeType(
|
|
|
|
QQmlProfilerDefinitions::RangeType range)
|
2015-05-21 08:35:42 +00:00
|
|
|
{
|
|
|
|
switch (range) {
|
2015-07-08 14:03:51 +00:00
|
|
|
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;
|
2015-05-21 08:35:42 +00:00
|
|
|
default:
|
2015-07-08 14:03:51 +00:00
|
|
|
return QQmlProfilerDefinitions::MaximumProfileFeature;
|
2015-05-21 08:35:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 13:14:40 +00:00
|
|
|
void QmlProfilerClient::stateChanged(State state)
|
|
|
|
{
|
|
|
|
if ((d->enabled && state != Enabled) || (!d->enabled && state == Enabled)) {
|
|
|
|
d->enabled = (state == Enabled);
|
|
|
|
emit enabledChanged(d->enabled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-08 15:50:14 +00:00
|
|
|
void QmlProfilerClient::messageReceived(const QByteArray &data)
|
2012-02-09 16:04:43 +00:00
|
|
|
{
|
|
|
|
QByteArray rwData = data;
|
|
|
|
QDataStream stream(&rwData, QIODevice::ReadOnly);
|
|
|
|
|
2015-05-21 08:35:42 +00:00
|
|
|
// Force all the 1 << <FLAG> expressions to be done in 64 bit, to silence some warnings
|
|
|
|
const quint64 one = static_cast<quint64>(1);
|
|
|
|
|
2012-02-09 16:04:43 +00:00
|
|
|
qint64 time;
|
|
|
|
int messageType;
|
|
|
|
|
|
|
|
stream >> time >> messageType;
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
if (messageType >= QQmlProfilerDefinitions::MaximumMessage)
|
2012-02-09 16:04:43 +00:00
|
|
|
return;
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
if (messageType == QQmlProfilerDefinitions::Event) {
|
2012-02-09 16:04:43 +00:00
|
|
|
int event;
|
|
|
|
stream >> event;
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
if (event == QQmlProfilerDefinitions::EndTrace) {
|
2012-02-09 16:04:43 +00:00
|
|
|
emit this->traceFinished(time);
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (event == QQmlProfilerDefinitions::AnimationFrame) {
|
|
|
|
if (!(d->features & one << QQmlProfilerDefinitions::ProfileAnimations))
|
2015-05-21 08:35:42 +00:00
|
|
|
return;
|
2012-02-09 16:04:43 +00:00
|
|
|
int frameRate, animationCount;
|
2014-03-17 13:52:01 +00:00
|
|
|
int threadId = 0;
|
2012-02-09 16:04:43 +00:00
|
|
|
stream >> frameRate >> animationCount;
|
2014-03-17 13:52:01 +00:00
|
|
|
if (!stream.atEnd())
|
|
|
|
stream >> threadId;
|
|
|
|
emit this->frame(time, frameRate, animationCount, threadId);
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (event == QQmlProfilerDefinitions::StartTrace) {
|
2012-02-09 16:04:43 +00:00
|
|
|
emit this->traceStarted(time);
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (event == QQmlProfilerDefinitions::Key ||
|
|
|
|
event == QQmlProfilerDefinitions::Mouse) {
|
|
|
|
if (!(d->features & one << QQmlProfilerDefinitions::ProfileInputEvents))
|
2015-05-21 15:48:58 +00:00
|
|
|
return;
|
2015-07-08 14:03:51 +00:00
|
|
|
emit this->inputEvent((QQmlProfilerDefinitions::EventType)event, time);
|
2012-02-09 16:04:43 +00:00
|
|
|
}
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::Complete) {
|
2012-02-09 16:04:43 +00:00
|
|
|
emit complete();
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::SceneGraphFrame) {
|
|
|
|
if (!(d->features & one << QQmlProfilerDefinitions::ProfileSceneGraph))
|
2015-05-21 08:35:42 +00:00
|
|
|
return;
|
2014-02-19 17:11:41 +00:00
|
|
|
int sgEventType;
|
|
|
|
int count = 0;
|
|
|
|
qint64 params[5];
|
|
|
|
|
|
|
|
stream >> sgEventType;
|
|
|
|
while (!stream.atEnd()) {
|
|
|
|
stream >> params[count++];
|
|
|
|
}
|
|
|
|
while (count<5)
|
|
|
|
params[count++] = 0;
|
2015-07-08 14:03:51 +00:00
|
|
|
emit sceneGraphFrame((QQmlProfilerDefinitions::SceneGraphFrameType)sgEventType, time,
|
2014-02-19 17:11:41 +00:00
|
|
|
params[0], params[1], params[2], params[3], params[4]);
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::PixmapCacheEvent) {
|
|
|
|
if (!(d->features & one << QQmlProfilerDefinitions::ProfilePixmapCache))
|
2015-05-21 08:35:42 +00:00
|
|
|
return;
|
2014-02-19 17:11:41 +00:00
|
|
|
int pixEvTy, width = 0, height = 0, refcount = 0;
|
|
|
|
QString pixUrl;
|
|
|
|
stream >> pixEvTy >> pixUrl;
|
2015-07-08 14:03:51 +00:00
|
|
|
if (pixEvTy == (int)QQmlProfilerDefinitions::PixmapReferenceCountChanged ||
|
|
|
|
pixEvTy == (int)QQmlProfilerDefinitions::PixmapCacheCountChanged) {
|
2014-02-19 17:11:41 +00:00
|
|
|
stream >> refcount;
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (pixEvTy == (int)QQmlProfilerDefinitions::PixmapSizeKnown) {
|
2014-02-19 17:11:41 +00:00
|
|
|
stream >> width >> height;
|
|
|
|
refcount = 1;
|
|
|
|
}
|
2015-07-08 14:03:51 +00:00
|
|
|
emit pixmapCache((QQmlProfilerDefinitions::PixmapEventType)pixEvTy, time,
|
2014-02-19 17:11:41 +00:00
|
|
|
QmlEventLocation(pixUrl,0,0), width, height, refcount);
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::MemoryAllocation) {
|
|
|
|
if (!(d->features & one << QQmlProfilerDefinitions::ProfileMemory))
|
2015-05-21 08:35:42 +00:00
|
|
|
return;
|
2014-06-16 11:33:33 +00:00
|
|
|
int type;
|
|
|
|
qint64 delta;
|
|
|
|
stream >> type >> delta;
|
2015-07-08 14:03:51 +00:00
|
|
|
emit memoryAllocation((QQmlProfilerDefinitions::MemoryType)type, time, delta);
|
2012-02-09 16:04:43 +00:00
|
|
|
} else {
|
|
|
|
int range;
|
|
|
|
stream >> range;
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
if (range >= QQmlProfilerDefinitions::MaximumRangeType)
|
2012-02-09 16:04:43 +00:00
|
|
|
return;
|
|
|
|
|
2015-05-21 08:35:42 +00:00
|
|
|
if (!(d->features & one << featureFromRangeType(
|
2015-07-08 14:03:51 +00:00
|
|
|
static_cast<QQmlProfilerDefinitions::RangeType>(range))))
|
2015-05-21 08:35:42 +00:00
|
|
|
return;
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
if (messageType == QQmlProfilerDefinitions::RangeStart) {
|
2012-02-09 16:04:43 +00:00
|
|
|
d->rangeStartTimes[range].push(time);
|
|
|
|
d->inProgressRanges |= (static_cast<qint64>(1) << range);
|
|
|
|
++d->rangeCount[range];
|
2012-05-02 15:32:57 +00:00
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::RangeData) {
|
2012-02-09 16:04:43 +00:00
|
|
|
QString data;
|
|
|
|
stream >> data;
|
|
|
|
|
|
|
|
int count = d->rangeCount[range];
|
|
|
|
if (count > 0) {
|
|
|
|
while (d->rangeDatas[range].count() < count)
|
|
|
|
d->rangeDatas[range].push(QStringList());
|
|
|
|
d->rangeDatas[range][count-1] << data;
|
|
|
|
}
|
|
|
|
|
2015-07-08 14:03:51 +00:00
|
|
|
} else if (messageType == QQmlProfilerDefinitions::RangeLocation) {
|
2012-02-09 16:04:43 +00:00
|
|
|
QString fileName;
|
|
|
|
int line;
|
|
|
|
int column = -1;
|
|
|
|
stream >> fileName >> line;
|
|
|
|
|
|
|
|
if (!stream.atEnd())
|
|
|
|
stream >> column;
|
|
|
|
|
|
|
|
if (d->rangeCount[range] > 0) {
|
2012-03-08 15:50:14 +00:00
|
|
|
d->rangeLocations[range].push(QmlEventLocation(fileName, line,
|
2012-02-09 16:04:43 +00:00
|
|
|
column));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (d->rangeCount[range] > 0) {
|
|
|
|
--d->rangeCount[range];
|
|
|
|
if (d->inProgressRanges & (static_cast<qint64>(1) << range))
|
|
|
|
d->inProgressRanges &= ~(static_cast<qint64>(1) << range);
|
|
|
|
|
|
|
|
QStringList data = d->rangeDatas[range].count() ?
|
|
|
|
d->rangeDatas[range].pop() : QStringList();
|
2012-03-08 15:50:14 +00:00
|
|
|
QmlEventLocation location = d->rangeLocations[range].count() ?
|
|
|
|
d->rangeLocations[range].pop() : QmlEventLocation();
|
2012-02-09 16:04:43 +00:00
|
|
|
|
|
|
|
qint64 startTime = d->rangeStartTimes[range].pop();
|
2015-07-08 14:03:51 +00:00
|
|
|
emit this->range((QQmlProfilerDefinitions::RangeType)range,
|
2015-10-23 15:15:44 +00:00
|
|
|
QQmlProfilerDefinitions::QmlBinding, startTime, time - startTime,
|
|
|
|
data, location);
|
2012-02-09 16:04:43 +00:00
|
|
|
if (d->rangeCount[range] == 0) {
|
|
|
|
int count = d->rangeDatas[range].count() +
|
|
|
|
d->rangeStartTimes[range].count() +
|
|
|
|
d->rangeLocations[range].count();
|
|
|
|
if (count != 0)
|
|
|
|
qWarning() << "incorrectly nested data";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|