qmlprofiler: Allow specification of features to record

Task-number: QTBUG-43066
Change-Id: I963a5a483f961dd150f00de3d96c723c8b62edb8
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
Ulf Hermann 2015-05-21 10:35:42 +02:00 committed by Simon Hausmann
parent 08533d2659
commit db69cd87d3
4 changed files with 120 additions and 2 deletions

View File

@ -59,6 +59,20 @@ static const char commandTextC[] =
" Terminate the program if started from qmlprofiler,\n"
" and qmlprofiler itself.";
static const char *features[] = {
"javascript",
"memory",
"pixmapcache",
"scenegraph",
"animations",
"painting",
"compiling",
"creating",
"binding",
"handlingsignal",
"inputevents"
};
static const char TraceFileExtension[] = ".qtd";
QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) :
@ -172,6 +186,26 @@ void QmlProfilerApplication::parseArguments()
QLatin1String("on|off"), QLatin1String("on"));
parser.addOption(record);
QStringList featureList;
for (int i = 0; i < QQmlProfilerService::MaximumProfileFeature; ++i)
featureList << QLatin1String(features[i]);
QCommandLineOption include(QLatin1String("include"),
tr("Comma-separated list of features to record. By default all "
"features supported by the QML engine are recorded. If --include "
"is specified, only the given features will be recorded. "
"The following features are unserstood by qmlprofiler: %1").arg(
featureList.join(", ")),
QLatin1String("feature,..."));
parser.addOption(include);
QCommandLineOption exclude(QLatin1String("exclude"),
tr("Comma-separated list of features to exclude when recording. By "
"default all features supported by the QML engine are recorded. "
"See --include for the features understood by qmlprofiler."),
QLatin1String("feature,..."));
parser.addOption(exclude);
QCommandLineOption interactive(QLatin1String("interactive"),
tr("Manually control the recording from the command line. The "
"profiler will not terminate itself when the application "
@ -213,6 +247,23 @@ void QmlProfilerApplication::parseArguments()
m_recording = (parser.value(record) == QLatin1String("on"));
m_interactive = parser.isSet(interactive);
quint64 features = std::numeric_limits<quint64>::max();
if (parser.isSet(include)) {
if (parser.isSet(exclude)) {
logError(tr("qmlprofiler can only process either --include or --exclude, not both."));
parser.showHelp(4);
}
features = parseFeatures(featureList, parser.value(include), false);
}
if (parser.isSet(exclude))
features = parseFeatures(featureList, parser.value(exclude), true);
if (features == 0)
parser.showHelp(4);
m_qmlProfilerClient.setFeatures(features);
if (parser.isSet(verbose))
m_verbose = true;
@ -244,6 +295,27 @@ bool QmlProfilerApplication::isInteractive() const
return m_interactive;
}
quint64 QmlProfilerApplication::parseFeatures(const QStringList &featureList, const QString &values,
bool exclude)
{
quint64 features = exclude ? std::numeric_limits<quint64>::max() : 0;
QStringList givenFeatures = values.split(QLatin1Char(','));
foreach (const QString &f, givenFeatures) {
int index = featureList.indexOf(f);
if (index < 0) {
logError(tr("Unknown feature '%1'").arg(f));
return 0;
}
quint64 flag = static_cast<quint64>(1) << index;
features = (exclude ? (features ^ flag) : (features | flag));
}
if (features == 0) {
logError(exclude ? tr("No features remaining to record after processing --exclude.") :
tr("No features specified for --include."));
}
return features;
}
void QmlProfilerApplication::flush()
{
if (m_recording) {

View File

@ -90,6 +90,7 @@ private slots:
void v8Complete();
private:
quint64 parseFeatures(const QStringList &featureList, const QString &values, bool exclude);
bool checkOutputFile(PendingRequest pending);
void flush();
void output();

View File

@ -71,7 +71,7 @@ class QmlProfilerClientPrivate
{
public:
QmlProfilerClientPrivate()
: inProgressRanges(0)
: inProgressRanges(0) , features(std::numeric_limits<quint64>::max())
{
::memset(rangeCount, 0,
QQmlProfilerService::MaximumRangeType * sizeof(int));
@ -83,6 +83,8 @@ public:
QStack<QmlEventLocation> rangeLocations[QQmlProfilerService::MaximumRangeType];
QStack<QQmlProfilerService::BindingType> bindingTypes;
int rangeCount[QQmlProfilerService::MaximumRangeType];
quint64 features;
};
QmlProfilerClient::QmlProfilerClient(
@ -97,6 +99,11 @@ QmlProfilerClient::~QmlProfilerClient()
delete d;
}
void QmlProfilerClient::setFeatures(quint64 features)
{
d->features = features;
}
void QmlProfilerClient::clearData()
{
::memset(d->rangeCount, 0,
@ -109,15 +116,39 @@ void QmlProfilerClient::sendRecordingStatus(bool record)
{
QByteArray ba;
QDataStream stream(&ba, QIODevice::WriteOnly);
stream << record;
stream << record << -1 << d->features;
sendMessage(ba);
}
inline QQmlProfilerService::ProfileFeature featureFromRangeType(
QQmlProfilerService::RangeType range)
{
switch (range) {
case QQmlProfilerService::Painting:
return QQmlProfilerService::ProfilePainting;
case QQmlProfilerService::Compiling:
return QQmlProfilerService::ProfileCompiling;
case QQmlProfilerService::Creating:
return QQmlProfilerService::ProfileCreating;
case QQmlProfilerService::Binding:
return QQmlProfilerService::ProfileBinding;
case QQmlProfilerService::HandlingSignal:
return QQmlProfilerService::ProfileHandlingSignal;
case QQmlProfilerService::Javascript:
return QQmlProfilerService::ProfileJavaScript;
default:
return QQmlProfilerService::MaximumProfileFeature;
}
}
void QmlProfilerClient::messageReceived(const QByteArray &data)
{
QByteArray rwData = data;
QDataStream stream(&rwData, QIODevice::ReadOnly);
// 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;
@ -133,6 +164,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
if (event == QQmlProfilerService::EndTrace) {
emit this->traceFinished(time);
} else if (event == QQmlProfilerService::AnimationFrame) {
if (!(d->features & one << QQmlProfilerService::ProfileAnimations))
return;
int frameRate, animationCount;
int threadId = 0;
stream >> frameRate >> animationCount;
@ -149,6 +182,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
} else if (messageType == QQmlProfilerService::Complete) {
emit complete();
} else if (messageType == QQmlProfilerService::SceneGraphFrame) {
if (!(d->features & one << QQmlProfilerService::ProfileSceneGraph))
return;
int sgEventType;
int count = 0;
qint64 params[5];
@ -162,6 +197,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
emit sceneGraphFrame((QQmlProfilerService::SceneGraphFrameType)sgEventType, time,
params[0], params[1], params[2], params[3], params[4]);
} else if (messageType == QQmlProfilerService::PixmapCacheEvent) {
if (!(d->features & one << QQmlProfilerService::ProfilePixmapCache))
return;
int pixEvTy, width = 0, height = 0, refcount = 0;
QString pixUrl;
stream >> pixEvTy >> pixUrl;
@ -175,6 +212,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
emit pixmapCache((QQmlProfilerService::PixmapEventType)pixEvTy, time,
QmlEventLocation(pixUrl,0,0), width, height, refcount);
} else if (messageType == QQmlProfilerService::MemoryAllocation) {
if (!(d->features & one << QQmlProfilerService::ProfileMemory))
return;
int type;
qint64 delta;
stream >> type >> delta;
@ -186,6 +225,10 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
if (range >= QQmlProfilerService::MaximumRangeType)
return;
if (!(d->features & one << featureFromRangeType(
static_cast<QQmlProfilerService::RangeType>(range))))
return;
if (messageType == QQmlProfilerService::RangeStart) {
d->rangeStartTimes[range].push(time);
d->inProgressRanges |= (static_cast<qint64>(1) << range);

View File

@ -74,6 +74,8 @@ public:
QmlProfilerClient(QQmlDebugConnection *client);
~QmlProfilerClient();
void setFeatures(quint64 features);
public slots:
void clearData();
void sendRecordingStatus(bool record);