aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/doc/src/performance.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/doc/src/performance.qdoc')
-rw-r--r--src/qml/doc/src/performance.qdoc1089
1 files changed, 1089 insertions, 0 deletions
diff --git a/src/qml/doc/src/performance.qdoc b/src/qml/doc/src/performance.qdoc
new file mode 100644
index 0000000000..91c9bbbbd7
--- /dev/null
+++ b/src/qml/doc/src/performance.qdoc
@@ -0,0 +1,1089 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtquick2-performance.html
+\title QML Performance
+\brief performance issues and suggestions
+
+\tableofcontents
+
+\section1 Timing Considerations
+
+As an application developer, you must strive to allow the rendering engine
+to achieve a consistent 60 frames-per-second refresh rate. 60 FPS means
+that there is approximately 16 milliseconds between each frame in which
+processing can be done, which includes the processing required to upload
+the draw primitives to the graphics hardware.
+
+In practice, this means that the application developer should use asynchronous,
+event driven programming wherever possible, should use worker threads to do
+significant processing, should never manually spin the event loop, and should
+never spend more than a couple of milliseconds per frame within blocking functions.
+Failure to do so will result in skipped frames, which has a drastic effect on the
+user experience.
+
+\section1 Profiling
+
+The most important tip is: use the QML profiler included with Qt Creator. Knowing
+where time is spent in an application will allow you to focus on problem areas which
+actually exist, rather than problem areas which potentially exist. See the Qt Creator
+manual for more information on how to use the QML profiling tool.
+
+Determining which bindings are being run the most often, or which functions your
+application is spending the most time in, will allow you to decide whether you need
+to optimize the problem areas, or redesign some implementation details of your
+application so that the performance is improved. Attempting to optimize code without
+profiling is likely to result in very minor rather than significant performance
+improvements.
+
+\section1 JavaScript
+
+Most QML applications will have a large amount of JavaScript code in them, in the
+form of dynamic functions, signal handlers, and property binding expressions.
+This is not generally a problem (in fact, due to some optimizations in the QML engine
+(bindings compiler, etc) it can for some use-cases be faster than calling a C++ function)
+however care must be taken to ensure that unnecessary processing isn't triggered
+accidentally.
+
+\section2 Bindings
+
+There are two types of bindings in QML: optimized and non-optimized bindings.
+It is a good idea to keep binding expressions as simple as possible, since the
+QML engine makes use of an optimized binding expression evaluator which can
+evaluate simple binding expressions without needing to switch into a full
+JavaScript execution environment. These optimized bindings are evaluated far
+more efficiently than more complex (non-optimized) bindings.
+
+Things to avoid in binding expressions to maximize optimizability:
+\list
+ \li declaring intermediate JavaScript variables
+ \li calling JavaScript functions
+ \li constructing closures or defining functions within the binding expression
+ \li accessing properties outside of the immediate context (generally, this means outside the component)
+ \li writing to other properties as side effects
+\endlist
+
+The QML_COMPILER_STATS environment variable may be set when running a QML application
+to print statistics about how many bindings were able to be optimized.
+
+Bindings are quickest when they know the type of objects and properties they are working
+with. This means that non-final property lookup in a binding expression can be slower
+in some cases, where it is possible that the type of the property being looked up has
+been changed (for example, by a derived type).
+
+Note that if a binding cannot be optimized by the QML engine's optimized binding
+expression evaluator, and thus must be evaluated by the full JavaScript environment,
+some of the tips listed above will no longer apply. For example, it can sometimes be
+beneficial to cache the result of property resolution in an intermediate JavaScript
+variable, in a very complex binding. Upcoming sections have more information on these
+sorts of optimizations.
+
+\section2 Type-Conversion
+
+One major cost of using JavaScript is that in most cases when a property from a QML
+element is accessed, a JavaScript object with an external resource containing the
+underlying C++ data (or a reference to it) is created. In most cases, this is fairly
+inexpensive, but in others it can be quite expensive. One example of where it is
+expensive is assigning a C++ QVariantMap Q_PROPERTY to a QML "variant" property.
+Lists can also be expensive, although sequences of specific types (QList of int,
+qreal, bool, QString, and QUrl) should be inexpensive; other list types involve an
+expensive conversion cost (creating a new JavaScript Array, and adding new elements
+one by one, with per-element conversion from C++ type instance to JavaScript value).
+
+Converting between some basic property types (such as "string" and "url" properties)
+can also be expensive. Using the closest matching property type will avoid unnecessary
+conversion.
+
+If you must expose a QVariantMap to QML, use a "var" property rather than a "variant"
+property. In general, "property var" should be considered to be superior to
+"property variant" for every use-case in QtQuick 2.0 (note that "property variant"
+is marked as obsolete in the QtQuick 2.0 documentation), as it allows a true JavaScript
+reference to be stored (which can reduce the number of conversions required in certain
+expressions).
+
+\section2 Resolving Properties
+
+Property resolution takes time. While in some cases the result of a lookup can be
+cached and reused, it is always best to avoid doing unnecessary work altogether, if
+possible.
+
+In the following example, we have a block of code which is run often (in this case, it
+is the contents of an explicit loop; but it could be a commonly-evaluated binding expression,
+for example) and in it, we resolve the element with the "rect" id and its "color" property
+multiple times:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 200
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ function printValue(which, value) {
+ console.log(which + " = " + value);
+ }
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ printValue("red", rect.color.r);
+ printValue("green", rect.color.g);
+ printValue("blue", rect.color.b);
+ printValue("alpha", rect.color.a);
+ }
+ var t1 = new Date();
+ console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
+ }
+}
+\endqml
+
+We could instead resolve the common base just once in the block:
+
+\qml
+// good.qml
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 200
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ function printValue(which, value) {
+ console.log(which + " = " + value);
+ }
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ var rectColor = rect.color; // resolve the common base.
+ printValue("red", rectColor.r);
+ printValue("green", rectColor.g);
+ printValue("blue", rectColor.b);
+ printValue("alpha", rectColor.a);
+ }
+ var t1 = new Date();
+ console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
+ }
+}
+\endqml
+
+Just this simple change results in a significant performance improvement.
+Note that the code above can be improved even further (since the property
+being looked up never changes during the loop processing), by hoisting the
+property resolution out of the loop, as follows:
+
+\qml
+// better.qml
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 200
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ function printValue(which, value) {
+ console.log(which + " = " + value);
+ }
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ var rectColor = rect.color; // resolve the common base outside the tight loop.
+ for (var i = 0; i < 1000; ++i) {
+ printValue("red", rectColor.r);
+ printValue("green", rectColor.g);
+ printValue("blue", rectColor.b);
+ printValue("alpha", rectColor.a);
+ }
+ var t1 = new Date();
+ console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
+ }
+}
+\endqml
+
+\section2 Property Bindings
+
+A property binding expression will be re-evaluated if any of the properties
+it references are changed. As such, binding expressions should be kept as
+simple as possible.
+
+If you have a loop where you do some processing, but only the final result
+of the processing is important, it is often better to update a temporary
+accumulator which you afterwards assign to the property you need to update,
+rather than incrementally updating the property itself, in order to avoid
+triggering re-evaluation of binding expressions during the intermediate
+stages of accumulation.
+
+The following contrived example illustrates this point:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+ property int accumulatedValue: 0
+
+ Text {
+ anchors.fill: parent
+ text: root.accumulatedValue.toString()
+ onTextChanged: console.log("text binding re-evaluated")
+ }
+
+ Component.onCompleted: {
+ var someData = [ 1, 2, 3, 4, 5, 20 ];
+ for (var i = 0; i < someData.length; ++i) {
+ accumulatedValue = accumulatedValue + someData[i];
+ }
+ }
+}
+\endqml
+
+The loop in the onCompleted handler causes the "text" property binding to
+be re-evaluated six times (which then results in any other property bindings
+which rely on the text value, as well as the onTextChanged signal handler,
+to be re-evaluated each time, and lays out the text for display each time).
+This is clearly unnecessary in this case, since we really only care about
+the final value of the accumulation.
+
+It could be rewritten as follows:
+
+\qml
+// good.qml
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+ property int accumulatedValue: 0
+
+ Text {
+ anchors.fill: parent
+ text: root.accumulatedValue.toString()
+ onTextChanged: console.log("text binding re-evaluated")
+ }
+
+ Component.onCompleted: {
+ var someData = [ 1, 2, 3, 4, 5, 20 ];
+ var temp = accumulatedValue;
+ for (var i = 0; i < someData.length; ++i) {
+ temp = temp + someData[i];
+ }
+ accumulatedValue = temp;
+ }
+}
+\endqml
+
+\section2 Sequence tips
+
+As mentioned earlier, some sequence types are fast (eg, QList<int>, QList<qreal>,
+QList<bool>, QList<QString>, QStringList and QList<QUrl>) while others will be
+much slower. Aside from using these types wherever possible instead of slower types,
+there are some other performance-related semantics you need to be aware of to achieve
+the best performance.
+
+Firstly, there are two different implementations for sequence types: one for where
+the sequence is a Q_PROPERTY of a QObject (we'll call this a reference sequence),
+and another for where the sequence is returned from a Q_INVOKABLE function of a
+QObject (we'll call this a copy sequence).
+
+A reference sequence is read and written via QMetaObject::property() and thus is read
+and written as a QVariant. This means that changing the value of any element in the
+sequence from JavaScript will result in three steps occurring: the complete sequence
+will be read from the QObject (as a QVariant, but then cast to a sequence of the correct
+type); the element at the specified index will be changed in that sequence; and the
+complete sequence will be written back to the QObject (as a QVariant).
+
+A copy sequence is far simpler as the actual sequence is stored in the JavaScript
+object's resource data, so no read/modify/write cycle occurs (instead, the resource
+data is modified directly).
+
+Therefore, writes to elements of a reference sequence will be much slower than writes
+to elements of a copy sequence. In fact, writing to a single element of an N-element
+reference sequence is equivalent in cost to assigning a N-element copy sequence to that
+reference sequence, so you're usually better off modifying a temporary copy sequence
+and then assigning the result to a reference sequence, during computation.
+
+Assume the existence (and prior registration into the "Qt.example 1.0" namespace) of the
+following C++ type:
+
+\code
+class SequenceTypeExample : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
+
+public:
+ SequenceTypeExample() : QQuickItem() { m_list << 1.1 << 2.2 << 3.3; }
+ ~SequenceTypeExample() {}
+
+ QList<qreal> qrealListProperty() const { return m_list; }
+ void setQrealListProperty(const QList<qreal> &list) { m_list = list; emit qrealListPropertyChanged(); }
+
+signals:
+ void qrealListPropertyChanged();
+
+private:
+ QList<qreal> m_list;
+};
+\endcode
+
+The following example writes to elements of a reference sequence in a
+tight loop, resulting in bad performance:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+ width: 200
+ height: 200
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ qrealListProperty.length = 100;
+ for (var i = 0; i < 500; ++i) {
+ for (var j = 0; j < 100; ++j) {
+ qrealListProperty[j] = j;
+ }
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+The QObject property read and write in the inner loop caused by the
+\c{"qrealListProperty[j] = j"} expression makes this code very suboptimal. Instead,
+something functionally equivalent but much faster would be:
+
+\qml
+// good.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+ width: 200
+ height: 200
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ var someData = [1.1, 2.2, 3.3]
+ someData.length = 100;
+ for (var i = 0; i < 500; ++i) {
+ for (var j = 0; j < 100; ++j) {
+ someData[j] = j;
+ }
+ qrealListProperty = someData;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+Secondly, a change signal for the property is emitted if any element in it changes.
+If you have many bindings to a particular element in a sequence property, it is better
+to create a dynamic property which is bound to that element, and use that dynamic
+property as the symbol in the binding expressions instead of the sequence element,
+as it will only cause re-evaluation of bindings if its value changes.
+
+This is an unusual use-case which most clients should never hit, but is worth being
+aware of, in case you find yourself doing something like this:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+
+ property int firstBinding: qrealListProperty[1] + 10;
+ property int secondBinding: qrealListProperty[1] + 20;
+ property int thirdBinding: qrealListProperty[1] + 30;
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ qrealListProperty[2] = i;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+Note that even though only the element at index 2 is modified in the loop, the three
+bindings will all be re-evaluated since the granularity of the change signal is that
+the entire property has changed. As such, adding an intermediate binding can
+sometimes be beneficial:
+
+\qml
+// good.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+
+ property int intermediateBinding: qrealListProperty[1]
+ property int firstBinding: intermediateBinding + 10;
+ property int secondBinding: intermediateBinding + 20;
+ property int thirdBinding: intermediateBinding + 30;
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ qrealListProperty[2] = i;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+In the above example, only the intermediate binding will be re-evaluated each time,
+resulting in a significant performance increase.
+
+\section2 Value-Type tips
+
+Value-type properties (font, color, vector3d, etc) have similar QObject property
+and change notification semantics to sequence type properties. As such, the tips
+given above for sequences are also applicable for value-type properties. While
+they are usually less of a problem with value-types (since the number of
+sub-properties of a value-type is usually far less than the number of elements
+in a sequence), any increase in the number of bindings being re-evaluated needlessly
+will have a negative impact on performance.
+
+\section2 Other JavaScript Objects
+
+Different JavaScript engines provide different optimizations. The JavaScript engine
+which QtQuick 2 uses is optimized for object instantiation and property lookup, but
+the optimizations which it provides relies on certain criteria. If your application
+does not meet the criteria, the JavaScript engine falls back to a "slow-path" mode
+with much worse performance. As such, always try to ensure you meet the following
+criteria:
+
+\list
+\li Avoid using eval() if at all possible
+\li Do not delete properties of objects
+\endlist
+
+\section1 Common Interface Elements
+
+\section2 Text Elements
+
+Calculating text layouts can be a slow operation. Consider using the \c PlainText
+format instead of \c StyledText wherever possible, as this reduces the amount of work
+required of the layout engine. If you cannot use \c PlainText (as you need to embed
+images, or use tags to specify ranges of characters to have certain formatting (bold,
+italic, etc) as opposed to the entire text) then you should use \c StyledText.
+
+You should only use \c AutoText if the text might be (but probably isn't)
+\c StyledText as this mode will incur a parsing cost. The \c RichText mode should
+not be used, as \c StyledText provides almost all of its features at a fraction of
+its cost.
+
+\section2 Images
+
+Images are a vital part of any user interface. Unfortunately, they are also a big
+source of problems due to the time it takes to load them, the amount of memory they
+consume, and the way in which they are used.
+
+\section3 Asynchronous Loading
+
+Images are often quite large, and so it is wise to ensure that loading an image doesn't
+block the UI thread. Set the "asynchronous" property of the QML Image element to
+\c true to enable asynchronous loading of images from the local file system (remote
+images are always loaded asynchronously) where this would not result in a negative impact
+upon the aesthetics of the user interface.
+
+Image elements with the "asynchronous" property set to \c true will load images in
+a low-priority worker thread.
+
+\section3 Explicit Source Size
+
+If your application loads a large image but displays it in a small-sized element, set
+the "sourceSize" property to the size of the element being rendered to ensure that the
+smaller-scaled version of the image is kept in memory, rather than the large one.
+
+Beware that changing the sourceSize will cause the image to be reloaded.
+
+\section3 Avoid Run-time Composition
+
+Also remember that you can avoid doing composition work at run-time by providing the
+pre-composed image resource with your application (e.g., providing elements with shadow
+effects).
+
+\section2 Position Elements With Anchors
+
+It is more efficient to use anchors rather than bindings to position items
+relative to each other. Consider this use of bindings to position rect2
+relative to rect1:
+
+\code
+Rectangle {
+ id: rect1
+ x: 20
+ width: 200; height: 200
+}
+Rectangle {
+ id: rect2
+ x: rect1.x
+ y: rect1.y + rect1.height
+ width: rect1.width - 20
+ height: 200
+}
+\endcode
+
+This is achieved more efficiently using anchors:
+
+\code
+Rectangle {
+ id: rect1
+ x: 20
+ width: 200; height: 200
+}
+Rectangle {
+ id: rect2
+ height: 200
+ anchors.left: rect1.left
+ anchors.top: rect1.bottom
+ anchors.right: rect1.right
+ anchors.rightMargin: 20
+}
+\endcode
+
+\section1 Models and Views
+
+Most applications will have at least one model feeding data to a view. There are
+some semantics which application developers need to be aware of, in order to achieve
+maximal performance.
+
+\section2 Custom C++ Models
+
+It is often desirable to write your own custom model in C++ for use with a view in
+QML. While the optimal implementation of any such model will depend heavily on the
+use-case it must fulfil, some general guidelines are as follows:
+
+\list
+\li Be as asynchronous as possible
+\li Do all processing in a (low priority) worker thread
+\li Batch up backend operations so that (potentially slow) I/O and IPC is minimized
+\li Use a sliding slice window to cache results, whose parameters are determined with the help of profiling
+\endlist
+
+It is important to note that using a low-priority worker thread is recommended to
+minimise the risk of starving the GUI thread (which could result in worse perceived
+performance). Also, remember that synchronization and locking mechanisms can be a
+significant cause of slow performance, and so care should be taken to avoid
+unnecessary locking.
+
+\section2 ListModel
+
+QML provides a ListModel element which can be used to feed data to a ListView.
+It should suffice for most use-cases and be relatively performant so long as
+it is used correctly.
+
+\section3 Populate Within A Worker Thread
+
+ListModel elements can be populated in a (low priority) worker thread in JavaScript. The
+developer must explicitly call "sync()" on the ListModel from within the WorkerScript to
+have the changes synchronized to the main thread. See the WorkerScript documentation
+for more information.
+
+Please note that using a WorkerScript element will result in a separate JavaScript engine
+being created (as the JavaScript engine is per-thread). This will result in increased
+memory usage. Multiple WorkerScript elements will all use the same worker thread, however,
+so the memory impact of using a second or third WorkerScript element is negligible once
+an application already uses one.
+
+\section3 Don't Use Dynamic Roles
+
+The ListModel element in QtQuick 2.0 is much more performant than in QtQuick 1.0. The
+performance improvements mainly come from assumptions about the type of roles within each
+element in a given model - if the type doesn't change, the caching performance improves
+dramatically. If the type can change dynamically from element to element, this optimization
+becomes impossible, and the performance of the model will be an order of magnitude worse.
+
+Therefore, dynamic typing is disabled by default; the developer must specifically set
+the boolean "dynamicRoles" property of the model to enable dynamic typing (and suffer
+the attendant performance degradation). We recommend that you do not use dynamic typing
+if it is possible to redesign your application to avoid it.
+
+\section2 Views
+
+View delegates should be kept as simple as possible. Have just enough QML in the delegate
+to display the necessary information. Any additional functionality which is not immediately
+required (e.g., if it displays more information when clicked) should not be created until
+needed (see the upcoming section on lazy initialization).
+
+The following list is a good summary of things to keep in mind when designing a delegate:
+\list
+\li The fewer elements that are in a delegate, the faster they can be created, and thus
+ the faster the view can be scrolled.
+\li Keep the number of bindings in a delegate to a minimum; in particular, use anchors
+ rather than bindings for relative positioning within a delegate.
+\li Avoid using ShaderEffect elements within delegates.
+\li Never enable clipping on a delegate.
+\endlist
+
+You may set the \c cacheBuffer property of a view to allow asynchronous creation and
+buffering of delegates outside of the visible area. Utilizing a \c cacheBuffer is
+recommended for view delegates that are non-trivial and unlikely to be created within a
+single frame.
+
+Be mindful that a \c cacheBuffer keeps additional delegates in-memory and therefore the
+value derived from utilizing the \c cacheBuffer must be balanced against additional memory
+usage. Developers should use benchmarking to find the best value for their use-case, since
+the increased memory pressure caused by utilizing a \c cacheBuffer can, in some rare cases,
+cause reduced frame rate when scrolling.
+
+\section1 Visual Effects
+
+QtQuick 2 includes several features which allow developers and designers to create
+exceptionally appealing user interfaces. Fluidity and dynamic transitions as well
+as visual effects can be used to great effect in an application, but some care must
+be taken when using some of the features in QML as they can have performance implications.
+
+\section2 Animations
+
+In general, animating a property will cause any bindings which reference that property
+to be re-evaluated. Usually, this is what is desired but in other cases it may be better
+to disable the binding prior to performing the animation, and then reassign the binding
+once the animation has completed.
+
+Avoid running JavaScript during animation. For example, running a complex JavaScript
+expression for each frame of an x property animation should be avoided.
+
+Developers should be especially careful using script animations, as these are run in the main
+thread (and therefore can cause frames to be skipped if they take too long to complete).
+
+\section2 Particles
+
+The QtQuick 2.0 Particles module allows beautiful particle effects to be integrated
+seamlessly into user interfaces. However every platform has different graphics hardware
+capabilities, and the Particles module is unable to limit parameters to what your hardware
+can gracefully support. The more particles you attempt to render (and the larger they are),
+the faster your graphics hardware will need to be in order to render at 60 FPS. Affecting
+more particles requires a faster CPU. It is therefore important to test all
+particle effects on your target platform carefully, to calibrate the number and size of
+particles you can render at 60 FPS.
+
+It should be noted that a particle system can be disabled when not in use
+(e.g., on a non-visible element) to avoid doing unnecessary simulation.
+
+See the \l{Particle System Performance Guide} for more in-depth information.
+
+\section2 Shaders
+
+Shaders written in GLSL allow for complex transformations and visual effects to be written,
+however they should be used with care. Using a ShaderEffectSource causes a scene to
+prerendered into an FBO before it can be drawn. This extra overhead is quite expensive.
+
+A ShaderEffect element can imply a ShaderEffectSource (and the indirect rendering costs
+associated with that) and also involves uploading a vertex and fragment shader program
+(which is then compiled into a GLSL shader). Each fragment shader runs once for every
+pixel of the scene, and so these should be kept as simple as possible.
+
+\section1 Controlling Element Lifetime
+
+By partitioning an application into simple, modular components, each contained in a single
+QML file, you can achieve faster application startup time and better control over memory
+usage, and reduce the number of active-but-invisible elements in your application.
+
+\section2 Lazy Initialization
+
+The QML engine does some tricky things to try to ensure that loading and initialization of
+components doesn't cause frames to be skipped, however there is no better way to reduce
+startup time than to avoid doing work you don't need to do, and delaying the work until
+it is necessary. This may be achieved by using either \l Loader or creating components
+\l {Dynamic Object Management in QML}{dynamically}.
+
+\section3 Using Loader
+
+The Loader is an element which allows dynamic loading and unloading of components.
+
+\list
+\li Using the "active" property of a Loader, initialization can be delayed until required.
+\li Using the overloaded version of the "setSource()" function, initial property values can
+ be supplied.
+\li Setting the Loader \l {Loader::asynchronous}{asynchronous} property to true may also
+ improve fluidity while a component is instantiated.
+\endlist
+
+\section3 Using Dynamic Creation
+
+Developers can use the Qt.createComponent() function to create a component dynamically at
+runtime from within JavaScript, and then call createObject() to instantiate it. Depending
+on the ownership semantics specified in the call, the developer may have to delete the
+created object manually. See \l {Dynamic Object Management in QML} for more information.
+
+\section2 Destroy Unused Elements
+
+Elements which are invisible because they are a child of a non-visible element (e.g., the
+second tab in a tab-widget, while the first tab is shown) should be initialized lazily in
+most cases, and deleted when no longer in use, to avoid the ongoing cost of leaving them
+active (e.g., rendering, animations, property binding evaluation, etc).
+
+An item loaded with a Loader element may be released by resetting the "source" or
+"sourceComponent" property of the Loader, while other items may be explicitly
+released by calling destroy() on them. In some cases, it may be necessary to
+leave the item active, in which case it should be made invisible at the very least.
+
+See the upcoming section on Rendering for more information on active but invisible elements.
+
+\section1 Rendering
+
+The scene graph used for rendering in QtQuick 2.0 allows highly dynamic, animated user
+interfaces to be rendered fluidly at 60 FPS. There are some things which can
+dramatically decrease rendering performance, however, and developers should be careful
+to avoid these pitfalls wherever possible.
+
+\section2 Clipping
+
+Clipping is disabled by default, and should only be enabled when required.
+
+Clipping is a visual effect, NOT an optimization. It increases (rather than reduces)
+complexity for the renderer. If clipping is enabled, an item will clip its own painting,
+as well as the painting of its children, to its bounding rectangle. This stops the renderer
+from being able to reorder the drawing order of elements freely, resulting in a sub-optimal
+best-case scene graph traversal.
+
+Clipping inside a delegate is especially bad and should be avoided at all costs.
+
+\section2 Over-drawing and Invisible Elements
+
+If you have elements which are totally covered by other (opaque) elements, it is best to
+set their "visible" property to \c false or they will be needlessly drawn.
+
+Similarly, elements which are invisible (e.g., the second tab in a tab widget, while the
+first tab is shown) but need to be initialized at startup time (e.g., if the cost of
+instantiating the second tab takes too long to be able to do it only when the tab is
+activated), should have their "visible" property set to \c false, in order to avoid the
+cost of drawing them (although as previously explained, they will still incur the cost of
+any animations or bindings evaluation since they are still active).
+
+\section2 Manual Layouts
+
+The scene graph renderer is able to batch up certain operations to minimise the number of
+OpenGL state changes required. However, this optimization is only possible for the
+built-in layout elements provided by QtQuick 2.0, and cannot be applied to manual layouts.
+
+Therefore, application developers should use the Row, Column, Grid, GridView and ListView
+elements instead of manual layouts wherever possible.
+
+\section1 Memory Allocation And Collection
+
+The amount of memory which will be allocated by an application and the way in which that
+memory will be allocated are very important considerations. Aside from the obvious
+concerns about out-of-memory conditions on memory-constrained devices, allocating memory
+on the heap is a fairly computationally expensive operation, and certain allocation
+strategies can result in increased fragmentation of data across pages. JavaScript uses
+a managed memory heap which is automatically garbage collected, and this provides some
+advantages but also has some important implications.
+
+An application written in QML uses memory from both the C++ heap and an automatically
+managed JavaScript heap. The application developer needs to be aware of the subtleties
+of each in order to maximise performance.
+
+\section2 Tips For QML Application Developers
+
+The tips and suggestions contained in this section are guidelines only, and may not be
+applicable in all circumstances. Be sure to benchmark and analyse your application
+carefully using empirical metrics, in order to make the best decisions possible.
+
+\section3 Instantiate and initialize components lazily
+
+If your application consists of multiple views (for example, multiple tabs) but only
+one is required at any one time, you can use lazy instantiation to minimize the
+amount of memory you need to have allocated at any given time. See the prior section
+on \l{Lazy Initialization} for more information.
+
+\section3 Destroy unused objects
+
+If you lazily instantiate components, or dynamically create objects during a JavaScript
+expression, it is often better to manually \c{destroy()} them rather than waiting for
+automatic garbage collection to do so. See the prior section on
+\l{Controlling Element Lifetime} for more information.
+
+\section3 Don't manually invoke the garbage collector
+
+In most cases, it is not wise to manually invoke the garbage collector, as it will block
+the GUI thread for a substantial period of time. This can result in skipped frames and
+jerky animations, which should be avoided at all costs.
+
+There are some cases where manually invoking the garbage collector is acceptable (and
+this is explained in greater detail in an upcoming section), but in most cases, invoking
+the garbage collector is unnecessary and counter-productive.
+
+\section3 Avoid complex bindings
+
+Aside from the reduced performance of complex bindings (for example, due to having to
+enter the JavaScript execution context to perform evaluation), they also take up more
+memory both on the C++ heap and the JavaScript heap than bindings which can be
+evaluated by QML's optimized binding expression evaluator.
+
+\section3 Avoid defining multiple identical implicit types
+
+If a QML element has a custom property defined in QML, it becomes its own implicit type.
+This is explained in greater detail in an upcoming section. If multiple identical
+implicit types are defined inline in a component, some memory will be wasted. In that
+situation it is usually better to explicitly define a new component which can then be
+reused.
+
+Defining a custom property can often be a beneficial performance optimization (for
+example, to reduce the number of bindings which are required or re-evaluated), or it
+can improve the modularity and maintainability of a component. In those cases, using
+custom properties is encouraged; however, the new type should, if it is used more than
+once, be split into its own component (.qml file) in order to conserve memory.
+
+\section3 Re-use existing components
+
+If you are considering defining a new component, it's worth double checking that such a
+component doesn't already exist in the component set for your platform. Otherwise, you
+will be forcing the QML engine to generate and store type-data for a type which is
+essentially a duplicate of another pre-existing and potentially already loaded component.
+
+\section3 Use module APIs instead of pragma library scripts
+
+If you are using a pragma library script to store application-wide instance data,
+consider using a QObject module API instead. This should result in better performance,
+and will result in less JavaScript heap memory being used.
+
+\section2 Memory Allocation in a QML Application
+
+The memory usage of a QML application may be split into two parts: its C++ heap usage,
+and its JavaScript heap usage. Some of the memory allocated in each will be unavoidable,
+as it is allocated by the QML engine or the JavaScript engine, while the rest is
+dependent upon decisions made by the application developer.
+
+The C++ heap will contain:
+\list
+ \li the fixed and unavoidable overhead of the QML engine (implementation data
+ structures, context information, and so on)
+ \li per-component compiled data and type information, including per-type property
+ metadata, which is generated by the QML engine depending on which modules are
+ imported by the application and which components the application loads
+ \li per-object C++ data (including property values) plus a per-element metaobject
+ hierarchy, depending on which components the application instantiates
+ \li any data which is allocated specifically by QML imports (libraries)
+\endlist
+
+The JavaScript heap will contain:
+\list
+ \li the fixed and unavoidable overhead of the JavaScript engine itself (including
+ built-in JavaScript types)
+ \li the fixed and unavoidable overhead of our JavaScript integration (constructor
+ functions for loaded types, function templates, and so on)
+ \li per-type layout information and other internal type-data generated by the JavaScript
+ engine at runtime, for each type (see note below, regarding types)
+ \li per-object JavaScript data ("var" properties, JavaScript functions and signal
+ handlers, and non-optimized binding expressions)
+ \li variables allocated during expression evaluation
+\endlist
+
+Furthermore, there will be one JavaScript heap allocated for use in the main thread, and
+optionally one other JavaScript heap allocated for use in the WorkerScript thread. If an
+application does not use a WorkerScript element, that overhead will not be incurred. The
+JavaScript heap can be several megabytes in size, and so applications written for
+memory-constrained devices may be best served to avoid using the WorkerScript element
+despite its usefulness in populating list models asynchronously.
+
+Note that both the QML engine and the JavaScript engine will automatically generate their
+own caches of type-data about observed types. Every component loaded by an application
+is a distinct (explicit) type, and every element (component instance) which defines its
+own custom properties in QML is an implicit type. Any element (instance of a component)
+which does not define any custom properties is considered by the JavaScript and QML engines
+to be of the type explicitly defined by the component, rather than its own implicit type.
+
+Consider the following example:
+\qml
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ Rectangle {
+ id: r0
+ color: "red"
+ }
+
+ Rectangle {
+ id: r1
+ color: "blue"
+ width: 50
+ }
+
+ Rectangle {
+ id: r2
+ property int customProperty: 5
+ }
+
+ Rectangle {
+ id: r3
+ property string customProperty: "hello"
+ }
+
+ Rectangle {
+ id: r4
+ property string customProperty: "hello"
+ }
+}
+\endqml
+
+In the previous example, the rectangles \c r0 and \c r1 do not have any custom properties,
+and thus the JavaScript and QML engines consider them both to be of the same type. That
+is, \c r0 and \c r1 are both considered to be of the explicitly defined \c Rectangle type.
+The rectangles \c r2, \c r3 and \c r4 each have custom properties and are each considered
+to be different (implicit) types. Note that \c r3 and \c r4 are each considered to be of
+different types, even though they have identical property information, simply because the
+custom property was not declared in the component which they are instances of.
+
+If \c r3 and \c r4 were both instances of a \c RectangleWithString component, and that
+component definition included the declaration of a string property named \c customProperty,
+then \c r3 and \c r4 would be considered to be the same type (that is, they would be
+instances of the \c RectangleWithString type, rather than defining their own implicit type).
+
+\section2 In-Depth Memory Allocation Considerations
+
+Whenever making decisions regarding memory allocation or performance trade-offs, it is
+important to keep in mind the impact of CPU-cache performance, operating system paging,
+and JavaScript engine garbage collection. Potential solutions should be benchmarked
+carefully in order to ensure that the best one is selected.
+
+No set of general guidelines can replace a solid understanding of the underlying
+principles of computer science combined with a practical knowledge of the implementation
+details of the platform for which the application developer is developing. Furthermore,
+no amount of theoretical calculation can replace a good set of benchmarks and analysis
+tools when making trade-off decisions.
+
+\section3 Fragmentation
+
+Fragmentation is a C++ development issue. If the application developer is not defining
+any C++ types or plugins, they may safely ignore this section.
+
+Over time, an application will allocate large portions of memory, write data to that
+memory, and subsequently free some portions of that memory once it has finished using
+some of the data. This can result in "free" memory being located in non-contiguous
+chunks, which cannot be returned to the operating system for other applications to use.
+It also has an impact on the caching and access characteristics of the application, as
+the "living" data may be spread across many different pages of physical memory. This
+in turn could force the operating system to swap which can cause filesystem I/O - which
+is, comparatively speaking, an extremely slow operation.
+
+Fragmentation can be avoided by utilizing pool allocators (and other contiguous memory
+allocators), by reducing the amount of memory which is allocated at any one time by
+carefully managing object lifetimes, by periodically cleansing and rebuilding caches,
+or by utilizing a memory-managed runtime with garbage collection (such as JavaScript).
+
+\section3 Garbage Collection
+
+JavaScript provides garbage collection. Memory which is allocated on the JavaScript
+heap (as opposed to the C++ heap) is owned by the JavaScript engine. The engine will
+periodically collect all unreferenced data on the JavaScript heap, and if fragmentation
+becomes an issue, it will compact its heap by moving all "living" data into a contiguous
+region of memory (allowing the freed memory to be returned to the operating system).
+
+\section4 Implications of Garbage Collection
+
+Garbage collection has advantages and disadvantages. It ensures that fragmentation is
+less of an issue, and it means that manually managing object lifetime is less important.
+However, it also means that a potentially long-lasting operation may be initiated by the
+JavaScript engine at a time which is out of the application developer's control. Unless
+JavaScript heap usage is considered carefully by the application developer, the frequency
+and duration of garbage collection may have a negative impact upon the application
+experience.
+
+\section4 Manually Invoking the Garbage Collector
+
+An application written in QML will (most likely) require garbage collection to be
+performed at some stage. While garbage collection will be automatically triggered by
+the JavaScript engine when the amount of available free memory is low, it is occasionally
+better if the application developer makes decisions about when to invoke the garbage
+collector manually (although usually this is not the case).
+
+The application developer is likely to have the best understanding of when an application
+is going to be idle for substantial periods of time. If a QML application uses a lot
+of JavaScript heap memory, causing regular and disruptive garbage collection cycles
+during particularly performance-sensitive tasks (for example, list scrolling, animations,
+and so forth), the application developer may be well served to manually invoke the
+garbage collector during periods of zero activity. Idle periods are ideal for performing
+garbage collection since the user will not notice any degradation of user experience
+(skipped frames, jerky animations, and so on) which would result from invoking the garbage
+collector while activity is occurring.
+
+The garbage collector may be invoked manually by calling \c{gc()} within JavaScript.
+This will cause a comprehensive collection and compaction cycle to be performed, which
+may take from between a few hundred to more than a thousand milliseconds to complete, and
+so should be avoided if at all possible.
+
+\section3 Memory vs Performance Trade-offs
+
+In some situations, it is possible to trade-off increased memory usage for decreased
+processing time. For example, caching the result of a symbol lookup used in a tight loop
+to a temporary variable in a JavaScript expression will result in a significant performance
+improvement when evaluating that expression, but it involves allocating a temporary variable.
+In some cases, these trade-offs are sensible (such as the case above, which is almost always
+sensible), but in other cases it may be better to allow processing to take slightly longer
+in order to avoid increasing the memory pressure on the system.
+
+In some cases, the impact of increased memory pressure can be extreme. In some situations,
+trading off memory usage for an assumed performance gain can result in increased page-thrash
+or cache-thrash, causing a huge reduction in performance. It is always necessary to benchmark
+the impact of trade-offs carefully in order to determine which solution is best in a given
+situation.
+
+For in-depth information on cache performance and memory-time trade-offs, please see
+Ulrich Drepper's excellent article "What Every Programmer Should Know About Memory"
+(available at http://ftp.linux.org.ua/pub/docs/developer/general/cpumemory.pdf as at 18th
+April 2012), and for information on C++-specific optimizations, please see Agner Fog's
+excellent manuals on optimizing C++ applications (available at
+http://www.agner.org/optimize/ as at 18th April 2012).
+
+*/