2011-04-27 10:05:43 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
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
|
2016-01-19 11:23:05 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-09-20 05:21:40 +00:00
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
2012-02-16 04:43:03 +00:00
|
|
|
#include <QQmlEngine>
|
|
|
|
#include <QQmlComponent>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QDebug>
|
2015-01-06 18:29:08 +00:00
|
|
|
#include <QGuiApplication>
|
2019-06-12 16:32:38 +00:00
|
|
|
#include <QElapsedTimer>
|
2012-02-16 04:43:03 +00:00
|
|
|
#include <QQmlContext>
|
2015-01-06 18:29:08 +00:00
|
|
|
#include <QQuickView>
|
|
|
|
#include <QQuickItem>
|
|
|
|
|
|
|
|
#include <private/qquickview_p.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
class Timer : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2012-02-16 04:43:03 +00:00
|
|
|
Q_PROPERTY(QQmlComponent *component READ component WRITE setComponent)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
Timer();
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent *component() const;
|
|
|
|
void setComponent(QQmlComponent *);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
static Timer *timerInstance();
|
|
|
|
|
|
|
|
void run(uint);
|
|
|
|
|
|
|
|
bool willParent() const;
|
|
|
|
void setWillParent(bool p);
|
|
|
|
|
|
|
|
private:
|
2012-02-16 04:43:03 +00:00
|
|
|
void runTest(QQmlContext *, uint);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent *m_component;
|
2011-04-27 10:05:43 +00:00
|
|
|
static Timer *m_timer;
|
|
|
|
|
|
|
|
bool m_willparent;
|
2015-01-06 18:29:08 +00:00
|
|
|
QQuickView m_view;
|
|
|
|
QQuickItem *m_item;
|
2011-04-27 10:05:43 +00:00
|
|
|
};
|
|
|
|
QML_DECLARE_TYPE(Timer);
|
|
|
|
|
2018-02-21 09:41:54 +00:00
|
|
|
Timer *Timer::m_timer = nullptr;
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
Timer::Timer()
|
2018-02-21 09:41:54 +00:00
|
|
|
: m_component(nullptr)
|
2015-01-06 18:29:08 +00:00
|
|
|
, m_willparent(false)
|
|
|
|
, m_item(new QQuickItem)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
if (m_timer)
|
|
|
|
qWarning("Timer: Timer already registered");
|
2015-01-06 18:29:08 +00:00
|
|
|
QQuickViewPrivate::get(&m_view)->setRootObject(m_item);
|
2011-04-27 10:05:43 +00:00
|
|
|
m_timer = this;
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent *Timer::component() const
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
return m_component;
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
void Timer::setComponent(QQmlComponent *c)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
m_component = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer *Timer::timerInstance()
|
|
|
|
{
|
|
|
|
return m_timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Timer::run(uint iterations)
|
|
|
|
{
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlContext context(qmlContext(this));
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QObject *o = m_component->create(&context);
|
2015-01-06 18:29:08 +00:00
|
|
|
QQuickItem *i = qobject_cast<QQuickItem *>(o);
|
|
|
|
if (m_willparent && i)
|
|
|
|
i->setParentItem(m_item);
|
2011-04-27 10:05:43 +00:00
|
|
|
delete o;
|
2014-01-15 21:01:15 +00:00
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
runTest(&context, iterations);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timer::willParent() const
|
|
|
|
{
|
|
|
|
return m_willparent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Timer::setWillParent(bool p)
|
|
|
|
{
|
|
|
|
m_willparent = p;
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
void Timer::runTest(QQmlContext *context, uint iterations)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2019-06-12 16:32:38 +00:00
|
|
|
QElapsedTimer t;
|
2011-04-27 10:05:43 +00:00
|
|
|
t.start();
|
|
|
|
for (uint ii = 0; ii < iterations; ++ii) {
|
|
|
|
QObject *o = m_component->create(context);
|
2015-01-06 18:29:08 +00:00
|
|
|
QQuickItem *i = qobject_cast<QQuickItem *>(o);
|
|
|
|
if (m_willparent && i)
|
|
|
|
i->setParentItem(m_item);
|
2011-04-27 10:05:43 +00:00
|
|
|
delete o;
|
|
|
|
}
|
|
|
|
|
|
|
|
int e = t.elapsed();
|
|
|
|
|
|
|
|
qWarning() << "Total:" << e << "ms, Per iteration:" << qreal(e) / qreal(iterations) << "ms";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void usage(const char *name)
|
|
|
|
{
|
|
|
|
qWarning("Usage: %s [-iterations <count>] [-parent] <qml file>\n", name);
|
|
|
|
|
|
|
|
qWarning("qmltime is a tool for benchmarking the runtime cost of instantiating\n"
|
|
|
|
"a QML component. It is typically run as follows:\n"
|
|
|
|
"\n"
|
|
|
|
"%s path/to/benchmark.qml\n"
|
|
|
|
"\n"
|
|
|
|
"If the -parent option is specified, the component being measured will also\n"
|
|
|
|
"be parented to an item already in the scene.\n"
|
|
|
|
"\n"
|
|
|
|
"If the -iterations option is specified, the benchmark will run the specified\n"
|
|
|
|
"number of iterations. If -iterations is not specified, 1024 iterations\n"
|
|
|
|
"are performed.\n"
|
|
|
|
"\n"
|
|
|
|
"qmltime expects the file to be benchmarked to contain a certain structure.\n"
|
|
|
|
"Specifically, it requires the presence of a QmlTime.Timer element. For example,\n"
|
|
|
|
"say we wanted to benchmark the following list delegate:\n"
|
|
|
|
"\n"
|
|
|
|
"Rectangle {\n"
|
|
|
|
" color: \"green\"\n"
|
|
|
|
" width: 400; height: 100\n"
|
|
|
|
" Text {\n"
|
|
|
|
" anchors.centerIn: parent\n"
|
|
|
|
" text: name\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"we would create a benchmark file that looks like this:\n"
|
|
|
|
"\n"
|
2012-01-31 06:52:36 +00:00
|
|
|
"import QtQuick 2.0\n"
|
2011-04-27 10:05:43 +00:00
|
|
|
"import QmlTime 1.0 as QmlTime\n"
|
|
|
|
"\n"
|
|
|
|
"Item {\n"
|
|
|
|
"\n"
|
|
|
|
" property string name: \"Bob Smith\"\n"
|
|
|
|
"\n"
|
|
|
|
" QmlTime.Timer {\n"
|
|
|
|
" component: Rectangle {\n"
|
|
|
|
" color: \"green\"\n"
|
|
|
|
" width: 400; height: 100\n"
|
|
|
|
" Text {\n"
|
|
|
|
" anchors.centerIn: parent\n"
|
|
|
|
" text: name\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"The outer Item functions as a dummy data provider for any additional\n"
|
|
|
|
"data required by the bindings in the component being benchmarked (in the\n"
|
|
|
|
"example above we provide a \"name\" property).\n"
|
|
|
|
"\n"
|
|
|
|
"When started, the component is instantiated once before running\n"
|
|
|
|
"the benchmark, which means that the reported time does not include\n"
|
|
|
|
"compile time (as the results of compilation are cached internally).\n"
|
|
|
|
"In this sense the times reported by qmltime best correspond to the\n"
|
|
|
|
"costs associated with delegate creation in the view classes, where the\n"
|
|
|
|
"same delegate is instantiated over and over. Conversely, it is not a\n"
|
|
|
|
"good approximation for e.g. Loader, which typically only instantiates\n"
|
|
|
|
"an element once (and so for Loader the compile time is very relevant\n"
|
|
|
|
"to the overall cost).", name);
|
|
|
|
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char ** argv)
|
|
|
|
{
|
2015-01-06 18:29:08 +00:00
|
|
|
QGuiApplication app(argc, argv);
|
2016-11-08 12:09:54 +00:00
|
|
|
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
qmlRegisterType<Timer>("QmlTime", 1, 0, "Timer");
|
|
|
|
|
|
|
|
uint iterations = 1024;
|
|
|
|
QString filename;
|
|
|
|
bool willParent = false;
|
|
|
|
|
|
|
|
for (int ii = 1; ii < argc; ++ii) {
|
|
|
|
QByteArray arg(argv[ii]);
|
|
|
|
|
|
|
|
if (arg == "-iterations") {
|
|
|
|
if (ii + 1 < argc) {
|
|
|
|
++ii;
|
|
|
|
QByteArray its(argv[ii]);
|
|
|
|
bool ok = false;
|
|
|
|
iterations = its.toUInt(&ok);
|
2017-01-18 00:49:35 +00:00
|
|
|
if (!ok || iterations == 0)
|
2011-04-27 10:05:43 +00:00
|
|
|
usage(argv[0]);
|
|
|
|
} else {
|
|
|
|
usage(argv[0]);
|
|
|
|
}
|
|
|
|
} else if (arg == "-parent") {
|
|
|
|
willParent = true;
|
|
|
|
} else if (arg == "-help") {
|
|
|
|
usage(argv[0]);
|
|
|
|
} else {
|
|
|
|
filename = QLatin1String(argv[ii]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename.isEmpty())
|
|
|
|
usage(argv[0]);
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlEngine engine;
|
|
|
|
QQmlComponent component(&engine, filename);
|
2011-04-27 10:05:43 +00:00
|
|
|
if (component.isError()) {
|
|
|
|
qWarning() << component.errors();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
QObject *obj = component.create();
|
|
|
|
if (!obj) {
|
|
|
|
qWarning() << component.errors();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer *timer = Timer::timerInstance();
|
|
|
|
if (!timer) {
|
2015-01-06 18:36:02 +00:00
|
|
|
qWarning() << "A QmlTime.Timer instance is required.";
|
2011-04-27 10:05:43 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
timer->setWillParent(willParent);
|
|
|
|
|
|
|
|
if (!timer->component()) {
|
|
|
|
qWarning() << "The timer has no component";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
timer->run(iterations);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "qmltime.moc"
|