/**************************************************************************** ** ** 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 #include #include "qqmlprofilerdefinitions_p.h" #include "qqmlabstractprofileradapter_p.h" #include #include 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 &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 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 &); protected: QElapsedTimer m_timer; QVarLengthArray m_data; }; class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter { Q_OBJECT public: QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine); qint64 sendMessages(qint64 until, QList &messages); public slots: void receiveData(const QList &new_data); private: QList 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()); } }; 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()); } }; struct QQmlCompilingProfiler : public QQmlProfilerHelper { QQmlCompilingProfiler(QQmlProfiler *profiler, const QString &name) : QQmlProfilerHelper(profiler) { Q_QML_PROFILE(profiler, startCompiling(name)); } ~QQmlCompilingProfiler() { Q_QML_PROFILE(profiler, endRange()); } }; #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(); for (int i = 0; i < backgroundRanges.count(); ++i) { profiler->endRange(); } backgroundRanges.clear(); running = false; if (stopProfiling) profiler = 0; } void startBackground(const QString &typeName) { if (running) { profiler->endRange(); 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(); 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(); 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 ranges; QStack backgroundRanges; bool running; }; QT_END_NAMESPACE Q_DECLARE_METATYPE(QList) #endif // QQMLPROFILER_P_H