qtdeclarative/src/qml/debugger/qqmlprofiler_p.h

369 lines
12 KiB
C
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QQMLPROFILER_P_H
#define QQMLPROFILER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qv4function_p.h>
#include <private/qqmlboundsignal_p.h>
#include "qqmlprofilerdefinitions_p.h"
#include "qqmlabstractprofileradapter_p.h"
#include <QUrl>
#include <QString>
QT_BEGIN_NAMESPACE
#define Q_QML_PROFILE_IF_ENABLED(profiler, Code)\
if (profiler && profiler->enabled) {\
Code;\
} else\
(void)0
#define Q_QML_PROFILE(profiler, Method)\
Q_QML_PROFILE_IF_ENABLED(profiler, profiler->Method)
// This struct is somewhat dangerous to use:
// The messageType is a bit field. You can pack multiple messages into
// one object, e.g. RangeStart and RangeLocation. Each one will be read
// independently by toByteArrays. Thus you can only pack messages if their data
// doesn't overlap. It's up to you to figure that out.
struct Q_AUTOTEST_EXPORT QQmlProfilerData
{
QQmlProfilerData() {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QUrl &url,
int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType), detailUrl(url),
x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str,
int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType),detailString(str),
x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str,
const QUrl &url, int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType), detailString(str),
detailUrl(url), x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType) :
time(time), messageType(messageType), detailType(detailType) {}
qint64 time;
int messageType; //bit field of QQmlProfilerService::Message
int detailType;
QString detailString; //used by RangeData and possibly by RangeLocation
QUrl detailUrl; //used by RangeLocation, overrides detailString
int x; //used by RangeLocation
int y; //used by RangeLocation
void toByteArrays(QList<QByteArray> &messages) const;
};
Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
class QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
void startBinding(const QString &fileName, int line, int column)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), 1 << Binding,
fileName, line, column));
}
// Have toByteArrays() construct another RangeData event from the same QString later.
// This is somewhat pointless but important for backwards compatibility.
void startCompiling(const QString &name)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData),
1 << Compiling, name, 1, 1));
}
void startHandlingSignal(const QString &fileName, int line, int column)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), 1 << HandlingSignal,
fileName, line, column));
}
void startCreating(const QString &typeName, const QUrl &fileName, int line, int column)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData),
1 << Creating, typeName, fileName, line, column));
}
void startCreating(const QString &typeName)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeData),
1 << Creating, typeName));
}
void creatingLocation(const QUrl &fileName, int line, int column)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeLocation, 1 << Creating,
fileName, line, column));
}
template<RangeType Range>
void endRange()
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, 1 << Range));
}
QQmlProfiler();
bool enabled;
public slots:
void startProfiling();
void stopProfiling();
void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
void dataReady(const QList<QQmlProfilerData> &);
protected:
QElapsedTimer m_timer;
QVarLengthArray<QQmlProfilerData> m_data;
};
class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
Q_OBJECT
public:
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine);
qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
public slots:
void receiveData(const QList<QQmlProfilerData> &new_data);
private:
QList<QQmlProfilerData> data;
};
//
// RAII helper structs
//
struct QQmlProfilerHelper : public QQmlProfilerDefinitions {
QQmlProfiler *profiler;
QQmlProfilerHelper(QQmlProfiler *profiler) : profiler(profiler) {}
};
struct QQmlBindingProfiler : public QQmlProfilerHelper {
QQmlBindingProfiler(QQmlProfiler *profiler, const QString &url, int line, int column) :
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE(profiler, startBinding(url, line, column));
}
~QQmlBindingProfiler()
{
Q_QML_PROFILE(profiler, endRange<Binding>());
}
};
struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper {
QQmlHandlingSignalProfiler(QQmlProfiler *profiler, QQmlBoundSignalExpression *expression) :
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE_IF_ENABLED(profiler, {
QV4::Function *function;
if (expression->sourceFile().isEmpty() && (function = expression->function())) {
profiler->startHandlingSignal(
function->sourceFile(), function->compiledFunction->location.line,
function->compiledFunction->location.column);
} else {
profiler->startHandlingSignal(
expression->sourceFile(), expression->lineNumber(),
expression->columnNumber());
}
});
}
~QQmlHandlingSignalProfiler()
{
Q_QML_PROFILE(profiler, endRange<QQmlProfiler::HandlingSignal>());
}
};
struct QQmlCompilingProfiler : public QQmlProfilerHelper {
QQmlCompilingProfiler(QQmlProfiler *profiler, const QString &name) :
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE(profiler, startCompiling(name));
}
~QQmlCompilingProfiler()
{
Q_QML_PROFILE(profiler, endRange<Compiling>());
}
};
#define Q_QML_VME_PROFILE(profiler, Method) Q_QML_PROFILE_IF_ENABLED(profiler.profiler, profiler.Method)
struct QQmlVmeProfiler : public QQmlProfilerDefinitions {
public:
struct Data {
Data() : line(0), column(0) {}
QUrl url;
int line;
int column;
QString typeName;
};
QQmlVmeProfiler() : profiler(0), running(false) {}
void clear(bool stopProfiling = false)
{
ranges.clear();
if (running)
profiler->endRange<Creating>();
for (int i = 0; i < backgroundRanges.count(); ++i) {
profiler->endRange<Creating>();
}
backgroundRanges.clear();
running = false;
if (stopProfiling) profiler = 0;
}
void startBackground(const QString &typeName)
{
if (running) {
profiler->endRange<Creating>();
running = false;
}
profiler->startCreating(typeName);
backgroundRanges.push(typeName);
}
void start(const QString &typeName, const QUrl &url, int line, int column)
{
switchRange();
setCurrentRange(typeName, url, line, column);
profiler->startCreating(typeName, url, line, column);
}
void stop()
{
if (running) {
profiler->endRange<Creating>();
running = false;
}
}
void pop()
{
if (ranges.count() > 0) {
switchRange();
currentRange = ranges.pop();
profiler->startCreating(currentRange.typeName, currentRange.url,
currentRange.line, currentRange.column);
}
}
void push()
{
if (running)
ranges.push(currentRange);
}
void foreground(const QUrl &url, int line, int column)
{
if (backgroundRanges.count() > 0) {
switchRange();
setCurrentRange(backgroundRanges.pop(), url, line, column);
profiler->creatingLocation(url, line, column);
}
}
QQmlProfiler *profiler;
private:
void switchRange()
{
if (running)
profiler->endRange<Creating>();
else
running = true;
}
void setCurrentRange(const QString &typeName, const QUrl &url, int line, int column)
{
currentRange.typeName = typeName;
currentRange.url = url;
currentRange.line = line;
currentRange.column = column;
}
Data currentRange;
QStack<Data> ranges;
QStack<QString> backgroundRanges;
bool running;
};
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QList<QQmlProfilerData>)
#endif // QQMLPROFILER_P_H