1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** GNU Free Documentation License
10 ** Alternatively, this file may be used under the terms of the GNU Free
11 ** Documentation License version 1.3 as published by the Free Software
12 ** Foundation and appearing in the file included in the packaging of
16 ** Alternatively, this file may be used in accordance with the terms
17 ** and conditions contained in a signed written agreement between you
26 ****************************************************************************/
29 \page qtquick2-performance.html
30 \inqmlmodule QtQuick 2
31 \title QML Performance
35 \section1 Timing Considerations
37 As an application developer, you must strive to allow the rendering engine
38 to achieve a consistent 60 frames-per-second refresh rate. 60 FPS means
39 that there is approximately 16 milliseconds between each frame in which
40 processing can be done, which includes the processing required to upload
41 the draw primitives to the graphics hardware.
43 In practice, this means that the application developer should use asynchronous,
44 event driven programming wherever possible, should use worker threads to do
45 significant processing, should never manually spin the event loop, and should
46 never spend more than a couple of milliseconds per frame within blocking functions.
47 Failure to do so will result in skipped frames, which has a drastic effect on the
52 The most important tip is: use the QML profiler included with Qt Creator. Knowing
53 where time is spent in an application will allow you to focus on problem areas which
54 actually exist, rather than problem areas which potentially exist. See the Qt Creator
55 manual for more information on how to use the QML profiling tool.
57 Determining which bindings are being run the most often, or which functions your
58 application is spending the most time in, will allow you to decide whether you need
59 to optimize the problem areas, or redesign some implementation details of your
60 application so that the performance is improved. Attempting to optimize code without
61 profiling is likely to result in very minor rather than significant performance
66 Most QML applications will have a large amount of JavaScript code in them, in the
67 form of dynamic functions, signal handlers, and property binding expressions.
68 This is not generally a problem (in fact, due to some optimizations in the QML engine
69 (bindings compiler, etc) it can for some use-cases be faster than calling a C++ function)
70 however care must be taken to ensure that unnecessary processing isn't triggered
73 \section2 Type-Conversion
75 One major cost of using JavaScript is that in most cases when a property from a QML
76 element is accessed, a JavaScript object with an external resource containing the
77 underlying C++ data (or a reference to it) is created. In most cases, this is fairly
78 inexpensive, but in others it can be quite expensive. One example of where it is
79 expensive is assigning a C++ QVariantMap Q_PROPERTY to a QML "variant" property.
80 Lists can also be expensive, although sequences of specific types (QList of int,
81 qreal, bool, QString, and QUrl) should be inexpensive; other list types involve an
82 expensive conversion cost (creating a new JavaScript Array, and adding new elements
83 one by one, with per-element conversion from C++ type instance to JavaScript value).
85 Converting between some basic property types (such as "string" and "url" properties)
86 can also be expensive. Using the closest matching property type will avoid unnecessary
89 If you must expose a QVariantMap to QML, use a "var" property rather than a "variant"
90 property. In general, "property var" should be considered to be superior to
91 "property variant" for every use-case in QtQuick 2.0 (note that "property variant"
92 is marked as obsolete in the QtQuick 2.0 documentation), as it allows a true JavaScript
93 reference to be stored (which can reduce the number of conversions required in certain
96 \section2 Resolving Properties
98 Property resolution takes time. While in some cases the result of a lookup can be
99 cached and reused, it is always best to avoid doing unnecessary work altogether, if
102 In the following example, we have a block of code which is run often (in this case, it
103 is the contents of an explicit loop; but it could be a commonly-evaluated binding expression,
104 for example) and in it, we resolve the element with the "rect" id and its "color" property
120 function printValue(which, value) {
121 console.log(which + " = " + value);
124 Component.onCompleted: {
126 for (var i = 0; i < 1000; ++i) {
127 printValue("red", rect.color.r);
128 printValue("green", rect.color.g);
129 printValue("blue", rect.color.b);
130 printValue("alpha", rect.color.a);
133 console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
138 We could instead resolve the common base just once in the block:
153 function printValue(which, value) {
154 console.log(which + " = " + value);
157 Component.onCompleted: {
159 for (var i = 0; i < 1000; ++i) {
160 var rectColor = rect.color; // resolve the common base.
161 printValue("red", rectColor.r);
162 printValue("green", rectColor.g);
163 printValue("blue", rectColor.b);
164 printValue("alpha", rectColor.a);
167 console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
173 Just this simple change results in a significant performance improvement.
175 \section2 Property Bindings
177 A property binding expression will be re-evaluated if any of the properties
178 it references are changed. As such, binding expressions should be kept as
181 If you have a loop where you do some processing, but only the final result
182 of the processing is important, it is often better to update a temporary
183 accumulator which you afterwards assign to the property you need to update,
184 rather than incrementally updating the property itself, in order to avoid
185 triggering re-evaluation of binding expressions during the intermediate
186 stages of accumulation.
188 The following contrived example illustrates this point:
198 property int accumulatedValue: 0
202 text: root.accumulatedValue.toString()
203 onTextChanged: console.log("text binding re-evaluated")
206 Component.onCompleted: {
207 var someData = [ 1, 2, 3, 4, 5, 20 ];
208 for (var i = 0; i < someData.length; ++i) {
209 accumulatedValue = accumulatedValue + someData[i];
215 The loop in the onCompleted handler causes the "text" property binding to
216 be re-evaluated six times (which then results in any other property bindings
217 which rely on the text value, as well as the onTextChanged signal handler,
218 to be re-evaluated each time, and lays out the text for display each time).
219 This is clearly unnecessary in this case, since we really only care about
220 the final value of the accumulation.
222 It could be rewritten as follows:
232 property int accumulatedValue: 0
236 text: root.accumulatedValue.toString()
237 onTextChanged: console.log("text binding re-evaluated")
240 Component.onCompleted: {
241 var someData = [ 1, 2, 3, 4, 5, 20 ];
242 var temp = accumulatedValue;
243 for (var i = 0; i < someData.length; ++i) {
244 temp = temp + someData[i];
246 accumulatedValue = temp;
251 \section2 Sequence tips
253 As mentioned earlier, some sequence types are fast (eg, QList<int>, QList<qreal>,
254 QList<bool>, QList<QString>, QStringList and QList<QUrl>) while others will be
255 much slower. Aside from using these types wherever possible instead of slower types,
256 there are some other performance-related semantics you need to be aware of to achieve
257 the best performance.
259 Firstly, there are two different implementations for sequence types: one for where
260 the sequence is a Q_PROPERTY of a QObject (we'll call this a reference sequence),
261 and another for where the sequence is returned from a Q_INVOKABLE function of a
262 QObject (we'll call this a copy sequence).
264 A reference sequence is read and written via QMetaObject::property() and thus is read
265 and written as a QVariant. This means that changing the value of any element in the
266 sequence from JavaScript will result in three steps occurring: the complete sequence
267 will be read from the QObject (as a QVariant, but then cast to a sequence of the correct
268 type); the element at the specified index will be changed in that sequence; and the
269 complete sequence will be written back to the QObject (as a QVariant).
271 A copy sequence is far simpler as the actual sequence is stored in the JavaScript
272 object's resource data, so no read/modify/write cycle occurs (instead, the resource
273 data is modified directly).
275 Therefore, writes to elements of a reference sequence will be much slower than writes
276 to elements of a copy sequence. In fact, writing to a single element of an N-element
277 reference sequence is equivalent in cost to assigning a N-element copy sequence to that
278 reference sequence, so you're usually better off modifying a temporary copy sequence
279 and then assigning the result to a reference sequence, during computation.
281 Assume the existence (and prior registration into the "Qt.example 1.0" namespace) of the
285 class SequenceTypeExample : public QQuickItem
288 Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
291 SequenceTypeExample() : QQuickItem() { m_list << 1.1 << 2.2 << 3.3; }
292 ~SequenceTypeExample() {}
294 QList<qreal> qrealListProperty() const { return m_list; }
295 void setQrealListProperty(const QList<qreal> &list) { m_list = list; emit qrealListPropertyChanged(); }
298 void qrealListPropertyChanged();
305 The following example writes to elements of a reference sequence in a
306 tight loop, resulting in bad performance:
311 import Qt.example 1.0
313 SequenceTypeExample {
318 Component.onCompleted: {
320 qrealListProperty.length = 100;
321 for (var i = 0; i < 500; ++i) {
322 for (var j = 0; j < 100; ++j) {
323 qrealListProperty[j] = j;
327 console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
332 The QObject property read and write in the inner loop caused by the
333 \c{"qrealListProperty[j] = j"} expression makes this code very suboptimal. Instead,
334 something functionally equivalent but much faster would be:
339 import Qt.example 1.0
341 SequenceTypeExample {
346 Component.onCompleted: {
348 var someData = [1.1, 2.2, 3.3]
349 someData.length = 100;
350 for (var i = 0; i < 500; ++i) {
351 for (var j = 0; j < 100; ++j) {
354 qrealListProperty = someData;
357 console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
362 Secondly, a change signal for the property is emitted if any element in it changes.
363 If you have many bindings to a particular element in a sequence property, it is better
364 to create a dynamic property which is bound to that element, and use that dynamic
365 property as the symbol in the binding expressions instead of the sequence element,
366 as it will only cause re-evaluation of bindings if its value changes.
368 This is an unusual use-case which most clients should never hit, but is worth being
369 aware of, in case you find yourself doing something like this:
374 import Qt.example 1.0
376 SequenceTypeExample {
379 property int firstBinding: qrealListProperty[1] + 10;
380 property int secondBinding: qrealListProperty[1] + 20;
381 property int thirdBinding: qrealListProperty[1] + 30;
383 Component.onCompleted: {
385 for (var i = 0; i < 1000; ++i) {
386 qrealListProperty[2] = i;
389 console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
394 Note that even though only the element at index 2 is modified in the loop, the three
395 bindings will all be re-evaluated since the granularity of the change signal is that
396 the entire property has changed. As such, adding an intermediate binding can
397 sometimes be beneficial:
402 import Qt.example 1.0
404 SequenceTypeExample {
407 property int intermediateBinding: qrealListProperty[1]
408 property int firstBinding: intermediateBinding + 10;
409 property int secondBinding: intermediateBinding + 20;
410 property int thirdBinding: intermediateBinding + 30;
412 Component.onCompleted: {
414 for (var i = 0; i < 1000; ++i) {
415 qrealListProperty[2] = i;
418 console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
423 In the above example, only the intermediate binding will be re-evaluated each time,
424 resulting in a significant performance increase.
426 \section2 Value-Type tips
428 Value-type properties (font, color, vector3d, etc) have similar QObject property
429 and change notification semantics to sequence type properties. As such, the tips
430 given above for sequences are also applicable for value-type properties. While
431 they are usually less of a problem with value-types (since the number of
432 sub-properties of a value-type is usually far less than the number of elements
433 in a sequence), any increase in the number of bindings being re-evaluated needlessly
434 will have a negative impact on performance.
436 \section2 Other JavaScript Objects
438 Different JavaScript engines provide different optimizations. The JavaScript engine
439 which QtQuick 2 uses is optimized for object instantiation and property lookup, but
440 the optimizations which it provides relies on certain criteria. If your application
441 does not meet the criteria, the JavaScript engine falls back to a "slow-path" mode
442 with much worse performance. As such, always try to ensure you meet the following
446 \o Avoid using eval() if at all possible
447 \o Do not delete properties of objects
448 \o Try to maintain property-assignment order in different constructor functions
451 \section1 Common Interface Elements
453 \section2 Text Elements
455 Calculating text layouts can be a slow operation. Consider using the \c PlainText
456 format instead of \c StyledText wherever possible, as this reduces the amount of work
457 required of the layout engine. If you cannot use \c PlainText (as you need to embed
458 images, or use tags to specify ranges of characters to have certain formatting (bold,
459 italic, etc) as opposed to the entire text) then you should use \c StyledText.
461 You should only use \c AutoText if the text might be (but probably isn't)
462 \c StyledText as this mode will incur a parsing cost. The \c RichText mode should
463 not be used, as \c StyledText provides almost all of its features at a fraction of
468 Images are a vital part of any user interface. Unfortunately, they are also a big
469 source of problems due to the time it takes to load them, the amount of memory they
470 consume, and the way in which they are used.
472 \section3 Asynchronous Loading
474 Images are often quite large, and so it is wise to ensure that loading an image doesn't
475 block the UI thread. Set the "asynchronous" property of the QML Image element to
476 \c true to enable asynchronous loading of images from the local file system (remote
477 images are always loaded asynchronously) where this would not result in a negative impact
478 upon the aesthetics of the user interface.
480 Image elements with the "asynchronous" property set to \c true will load images in
481 a low-priority worker thread.
483 \section3 Explicit Source Size
485 If your application loads a large image but displays it in a small-sized element, set
486 the "sourceSize" property to the size of the element being rendered to ensure that the
487 smaller-scaled version of the image is kept in memory, rather than the large one.
489 Beware that changing the sourceSize will cause the image to be reloaded.
491 \section3 Avoid Run-time Composition
493 Also remember that you can avoid doing composition work at run-time by providing the
494 pre-composed image resource with your application (e.g., providing elements with shadow
497 \section2 Position Elements With Anchors
499 It is more efficient to use anchors rather than bindings to position items
500 relative to each other. Consider this use of bindings to position rect2
507 width: 200; height: 200
512 y: rect1.y + rect1.height
513 width: rect1.width - 20
518 This is achieved more efficiently using anchors:
524 width: 200; height: 200
529 anchors.left: rect1.left
530 anchors.top: rect1.bottom
531 anchors.right: rect1.right
532 anchors.rightMargin: 20
536 \section1 Models and Views
538 Most applications will have at least one model feeding data to a view. There are
539 some semantics which application developers need to be aware of, in order to achieve
542 \section2 Custom C++ Models
544 It is often desirable to write your own custom model in C++ for use with a view in
545 QML. While the optimal implementation of any such model will depend heavily on the
546 use-case it must fulfil, some general guidelines are as follows:
549 \o Be as asynchronous as possible
550 \o Do all processing in a (low priority) worker thread
551 \o Batch up backend operations so that (potentially slow) I/O and IPC is minimised
552 \o Use a sliding slice window to cache results, whose parameters are determined with the help of profiling
555 It is important to note that using a low-priority worker thread is recommended to
556 minimise the risk of starving the GUI thread (which could result in worse perceived
557 performance). Also, remember that synchronisation and locking mechanisms can be a
558 significant cause of slow performance, and so care should be taken to avoid
563 QML provides a ListModel element which can be used to feed data to a ListView.
564 It should suffice for most use-cases and be relatively performant so long as
565 it is used correctly.
567 \section3 Populate Within A Worker Thread
569 ListModel elements can be populated in a (low priority) worker thread in JavaScript. The
570 developer must explicitly call "sync()" on the ListModel from within the WorkerScript to
571 have the changes synchronised to the main thread. See the WorkerScript documentation
572 for more information.
574 \section3 Don't Use Dynamic Roles
576 The ListModel element in QtQuick 2.0 is much more performant than in QtQuick 1.0. The
577 performance improvements mainly come from assumptions about the type of roles within each
578 element in a given model - if the type doesn't change, the caching performance improves
579 dramatically. If the type can change dynamically from element to element, this optimization
580 becomes impossible, and the performance of the model will be an order of magnitude worse.
582 Therefore, dynamic typing is disabled by default; the developer must specifically set
583 the boolean "dynamicRoles" property of the model to enable dynamic typing (and suffer
584 the attendant performance degradation). We recommend that you do not use dynamic typing
585 if it is possible to redesign your application to avoid it.
589 View delegates should be kept as simple as possible. Have just enough QML in the delegate
590 to display the necessary information. Any additional functionality which is not immediately
591 required (e.g., if it displays more information when clicked) should not be created until
592 needed (see the upcoming section on lazy initialisation).
594 The following list is a good summary of things to keep in mind when designing a delegate:
596 \o The fewer elements that are in a delegate, the faster they can be created, and thus
597 the faster the view can be scrolled.
598 \o Keep the number of bindings in a delegate to a minimum; in particular, use anchors
599 rather than bindings for relative positioning within a delegate.
600 \o Set a cacheBuffer to allow asynchronous creation of delegates outside the visible area.
601 Be mindful that this creates additional delegates and therefore the size of the
602 cacheBuffer must be balanced against additional memory usage.
603 \o Avoid using ShaderEffect elements within delegates.
604 \o Never enable clipping on a delegate.
607 \section1 Visual Effects
609 QtQuick 2 includes several features which allow developers and designers to create
610 exceptionally appealing user interfaces. Fluidity and dynamic transitions as well
611 as visual effects can be used to great effect in an application, but some care must
612 be taken when using some of the features in QML as they can have performance implications.
616 In general, animating a property will cause any bindings which reference that property
617 to be re-evaluated. Usually, this is what is desired but in other cases it may be better
618 to disable the binding prior to performing the animation, and then reassign the binding
619 once the animation has completed.
621 Avoid running JavaScript during animation. For example, running a complex JavaScript
622 expression for each frame of an x property animation should be avoided.
624 Developers should be especially careful using script animations, as these are run in the main
625 thread (and therefore can cause frames to be skipped if they take too long to complete).
629 The QtQuick 2.0 Particles module allows beautiful particle effects to be integrated
630 seamlessly into user interfaces. However every platform has different graphics hardware
631 capabilities, and the Particles module is unable to limit parameters to what your hardware
632 can gracefully support. The more particles you attempt to render (and the larger they are),
633 the faster your graphics hardware will need to be in order to render at 60 FPS. Affecting
634 more particles requires a faster CPU. It is therefore important to test all
635 particle effects on your target platform carefully, to calibrate the number and size of
636 particles you can render at 60 FPS.
638 It should be noted that a particle system can be disabled when not in use
639 (e.g., on a non-visible element) to avoid doing unnecessary simulation.
641 See the \l{Qt Quick Particle System Performance Guide} for more in-depth information.
645 Shaders written in GLSL allow for complex transformations and visual effects to be written,
646 however they should be used with care. Using a ShaderEffectSource causes a scene to
647 prerendered into an FBO before it can be drawn. This extra overhead is quite expensive.
649 A ShaderEffect element can imply a ShaderEffectSource (and the indirect rendering costs
650 associated with that) and also involves uploading a vertex and fragment shader program
651 (which is then compiled into a GLSL shader). Each fragment shader runs once for every
652 pixel of the scene, and so these should be kept as simple as possible.
654 \section1 Controlling Element Lifetime
656 By partitioning an application into simple, modular components, each contained in a single
657 QML file, you can achieve faster application startup time and better control over memory
658 usage, and reduce the number of active-but-invisible elements in your application.
660 \section2 Lazy Initialisation
662 The QML engine does some tricky things to try to ensure that loading and initialisation of
663 components doesn't cause frames to be skipped, however there is no better way to reduce
664 startup time than to avoid doing work you don't need to do, and delaying the work until
665 it is necessary. This may be achieved by using either \l Loader or creating components
666 \l {Dynamic Object Management in QML}{dynamically}.
668 \section3 Using Loader
670 The Loader is an element which allows dynamic loading and unloading of components.
673 \o Using the "active" property of a Loader, initialisation can be delayed until required.
674 \o Using the overloaded version of the "setSource()" function, initial property values can
676 \o Setting the Loader \l {Loader::asynchronous}{asynchronous} property to true may also
677 improve fluidity while a component is instantiated.
680 \section3 Using Dynamic Creation
682 Developers can use the Qt.createComponent() function to create a component dynamically at
683 runtime from within JavaScript, and then call createObject() to instantiate it. Depending
684 on the ownership semantics specified in the call, the developer may have to delete the
685 created object manually. See \l {Dynamic Object Management in QML} for more information.
687 \section2 Destroy Unused Elements
689 Elements which are invisible because they are a child of a non-visible element (e.g., the
690 second tab in a tab-widget, while the first tab is shown) should be initialised lazily in
691 most cases, and deleted when no longer in use, to avoid the ongoing cost of leaving them
692 active (e.g., rendering, animations, property binding evaluation, etc).
694 An item loaded with a Loader element may be released by resetting the "source" or
695 "sourceComponent" property of the Loader, while other items may be explicitly
696 released by calling destroy() on them. In some cases, it may be necessary to
697 leave the item active, in which case it should be made invisible at the very least.
699 See the upcoming section on Rendering for more information on active but invisible elements.
703 The scene graph used for rendering in QtQuick 2.0 allows highly dynamic, animated user
704 interfaces to be rendered fluidly at 60 FPS. There are some things which can
705 dramatically decrease rendering performance, however, and developers should be careful
706 to avoid these pitfalls wherever possible.
710 Clipping is disabled by default, and should only be enabled when required.
712 Clipping is a visual effect, NOT an optimization. It increases (rather than reduces)
713 complexity for the renderer. If clipping is enabled, an item will clip its own painting,
714 as well as the painting of its children, to its bounding rectangle. This stops the renderer
715 from being able to reorder the drawing order of elements freely, resulting in a sub-optimal
716 best-case scene graph traversal.
718 Clipping inside a delegate is especially bad and should be avoided at all costs.
720 \section2 Over-drawing and Invisible Elements
722 If you have elements which are totally covered by other (opaque) elements, it is best to
723 set their "visible" property to \c false or they will be needlessly drawn.
725 Similarly, elements which are invisible (e.g., the second tab in a tab widget, while the
726 first tab is shown) but need to be initialised at startup time (e.g., if the cost of
727 instantiating the second tab takes too long to be able to do it only when the tab is
728 activated), should have their "visible" property set to \c false, in order to avoid the
729 cost of drawing them (although as previously explained, they will still incur the cost of
730 any animations or bindings evaluation since they are still active).
732 \section2 Manual Layouts
734 The scene graph renderer is able to batch up certain operations to minimise the number of
735 OpenGL state changes required. However, this optimization is only possible for the
736 built-in layout elements provided by QtQuick 2.0, and cannot be applied to manual layouts.
738 Therefore, application developers should use the Row, Column, Grid, GridView and ListView
739 elements instead of manual layouts wherever possible.