369 lines
12 KiB
C
369 lines
12 KiB
C
|
/****************************************************************************
|
||
|
**
|
||
|
** 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
|