1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qmltime.h"
30
31#include <QQmlEngine>
32#include <QDebug>
33#include <QGuiApplication>
34#include <QElapsedTimer>
35#include <QQmlContext>
36#include <QQuickItem>
37
38#include <private/qquickview_p.h>
39
40Timer *Timer::m_timer = nullptr;
41
42Timer::Timer()
43 : m_component(nullptr)
44 , m_willparent(false)
45 , m_item(new QQuickItem)
46{
47 if (m_timer)
48 qWarning(msg: "Timer: Timer already registered");
49 QQuickViewPrivate::get(view: &m_view)->setRootObject(m_item);
50 m_timer = this;
51}
52
53QQmlComponent *Timer::component() const
54{
55 return m_component;
56}
57
58void Timer::setComponent(QQmlComponent *c)
59{
60 m_component = c;
61}
62
63Timer *Timer::timerInstance()
64{
65 return m_timer;
66}
67
68void Timer::run(uint iterations)
69{
70 QQmlContext context(qmlContext(this));
71
72 QObject *o = m_component->create(context: &context);
73 QQuickItem *i = qobject_cast<QQuickItem *>(object: o);
74 if (m_willparent && i)
75 i->setParentItem(m_item);
76 delete o;
77
78 runTest(&context, iterations);
79}
80
81bool Timer::willParent() const
82{
83 return m_willparent;
84}
85
86void Timer::setWillParent(bool p)
87{
88 m_willparent = p;
89}
90
91void Timer::runTest(QQmlContext *context, uint iterations)
92{
93 QElapsedTimer t;
94 t.start();
95 for (uint ii = 0; ii < iterations; ++ii) {
96 QObject *o = m_component->create(context);
97 QQuickItem *i = qobject_cast<QQuickItem *>(object: o);
98 if (m_willparent && i)
99 i->setParentItem(m_item);
100 delete o;
101 }
102
103 int e = t.elapsed();
104
105 qWarning() << "Total:" << e << "ms, Per iteration:" << qreal(e) / qreal(iterations) << "ms";
106
107}
108
109void usage(const char *name)
110{
111 qWarning(msg: "Usage: %s [-iterations <count>] [-parent] <qml file>\n", name);
112
113 qWarning(msg: "qmltime is a tool for benchmarking the runtime cost of instantiating\n"
114 "a QML component. It is typically run as follows:\n"
115 "\n"
116 "%s path/to/benchmark.qml\n"
117 "\n"
118 "If the -parent option is specified, the component being measured will also\n"
119 "be parented to an item already in the scene.\n"
120 "\n"
121 "If the -iterations option is specified, the benchmark will run the specified\n"
122 "number of iterations. If -iterations is not specified, 1024 iterations\n"
123 "are performed.\n"
124 "\n"
125 "qmltime expects the file to be benchmarked to contain a certain structure.\n"
126 "Specifically, it requires the presence of a QmlTime.Timer element. For example,\n"
127 "say we wanted to benchmark the following list delegate:\n"
128 "\n"
129 "Rectangle {\n"
130 " color: \"green\"\n"
131 " width: 400; height: 100\n"
132 " Text {\n"
133 " anchors.centerIn: parent\n"
134 " text: name\n"
135 " }\n"
136 "}\n"
137 "\n"
138 "we would create a benchmark file that looks like this:\n"
139 "\n"
140 "import QtQuick 2.0\n"
141 "import QmlTime 1.0 as QmlTime\n"
142 "\n"
143 "Item {\n"
144 "\n"
145 " property string name: \"Bob Smith\"\n"
146 "\n"
147 " QmlTime.Timer {\n"
148 " component: Rectangle {\n"
149 " color: \"green\"\n"
150 " width: 400; height: 100\n"
151 " Text {\n"
152 " anchors.centerIn: parent\n"
153 " text: name\n"
154 " }\n"
155 " }\n"
156 " }\n"
157 "}\n"
158 "\n"
159 "The outer Item functions as a dummy data provider for any additional\n"
160 "data required by the bindings in the component being benchmarked (in the\n"
161 "example above we provide a \"name\" property).\n"
162 "\n"
163 "When started, the component is instantiated once before running\n"
164 "the benchmark, which means that the reported time does not include\n"
165 "compile time (as the results of compilation are cached internally).\n"
166 "In this sense the times reported by qmltime best correspond to the\n"
167 "costs associated with delegate creation in the view classes, where the\n"
168 "same delegate is instantiated over and over. Conversely, it is not a\n"
169 "good approximation for e.g. Loader, which typically only instantiates\n"
170 "an element once (and so for Loader the compile time is very relevant\n"
171 "to the overall cost).", name);
172
173 exit(status: -1);
174}
175
176int main(int argc, char ** argv)
177{
178 QGuiApplication app(argc, argv);
179 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
180
181 uint iterations = 1024;
182 QString filename;
183 bool willParent = false;
184
185 for (int ii = 1; ii < argc; ++ii) {
186 QByteArray arg(argv[ii]);
187
188 if (arg == "-iterations") {
189 if (ii + 1 < argc) {
190 ++ii;
191 QByteArray its(argv[ii]);
192 bool ok = false;
193 iterations = its.toUInt(ok: &ok);
194 if (!ok || iterations == 0)
195 usage(name: argv[0]);
196 } else {
197 usage(name: argv[0]);
198 }
199 } else if (arg == "-parent") {
200 willParent = true;
201 } else if (arg == "-help") {
202 usage(name: argv[0]);
203 } else {
204 filename = QLatin1String(argv[ii]);
205 }
206 }
207
208 if (filename.isEmpty())
209 usage(name: argv[0]);
210
211 QQmlEngine engine;
212 QQmlComponent component(&engine, filename);
213 if (component.isError()) {
214 qWarning() << component.errors();
215 return -1;
216 }
217
218 QObject *obj = component.create();
219 if (!obj) {
220 qWarning() << component.errors();
221 return -1;
222 }
223
224 Timer *timer = Timer::timerInstance();
225 if (!timer) {
226 qWarning() << "A QmlTime.Timer instance is required.";
227 return -1;
228 }
229
230 timer->setWillParent(willParent);
231
232 if (!timer->component()) {
233 qWarning() << "The timer has no component";
234 return -1;
235 }
236
237 timer->run(iterations);
238
239 return 0;
240}
241

source code of qtdeclarative/tools/qmltime/qmltime.cpp