aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/doc/src/appdevguide/performance.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/doc/src/appdevguide/performance.qdoc')
-rw-r--r--src/quick/doc/src/appdevguide/performance.qdoc1143
1 files changed, 0 insertions, 1143 deletions
diff --git a/src/quick/doc/src/appdevguide/performance.qdoc b/src/quick/doc/src/appdevguide/performance.qdoc
deleted file mode 100644
index 28217e06d6..0000000000
--- a/src/quick/doc/src/appdevguide/performance.qdoc
+++ /dev/null
@@ -1,1143 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** 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. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: http://www.gnu.org/copyleft/fdl.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
-\page qtquick-performance.html
-\title Performance Considerations And Suggestions
-\brief Discussion of performance-related tradeoffs and best-practices
-
-\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.
-
-\note A pattern which is tempting, but should \e never be used, is creating your
-own QEventLoop or calling QCoreApplication::processEvents() in order to avoid
-blocking within a C++ code block invoked from QML. This is dangerous because
-when an event loop is entered in a signal handler or binding, the QML engine
-continues to run other bindings, animations, transitions, etc. Those bindings
-can then cause side effects which, for example, destroy the hierarchy containing
-your event loop.
-
-\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 Code
-
-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. The basic
-requirement for optimization of bindings is that the type information of every
-symbol accessed must be known at compile time.
-
-Things to avoid in binding expressions to maximize optimizability:
-\list
- \li declaring intermediate JavaScript variables
- \li accessing "var" properties
- \li calling JavaScript functions
- \li constructing closures or defining functions within the binding expression
- \li accessing properties outside of the immediate evaluation scope
- \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).
-
-The immediate evaluation scope can be summarized by saying that it contains:
-\list
- \li the properties of the expression scope object (for binding expressions, this is
- the object to which the property binding belongs)
- \li ids of any objects in the component
- \li the properties of the root item in the component
-\endlist
-
-Ids of objects from other components and properties of any such objects, as
-well as symbols defined in or included from a JavaScript import, are not in the
-immediate evaluation scope, and thus bindings which access any of those things
-will not be optimized.
-
-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
-type 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 types
-one by one, with per-type 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 object 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
-
-Positioning with bindings (by assigning binding expressions to the x, y, width
-and height properties of visual objects, rather than using anchors) is
-relatively slow, although it allows maximum flexibility.
-
-If the layout is not dynamic, the most performant way to specify the layout is
-via static initialization of the x, y, width and height properties. Item
-coordinates are always relative to their parent, so if you wanted to be a fixed
-offset from your parent's 0,0 coordinate you should not use anchors. In the
-following example the child Rectangle objects are in the same place, but the
-anchors code shown is not as resource efficient as the code which
-uses fixed positioning via static initialization:
-
-\code
-Rectangle {
- width: 60
- height: 60
- Rectangle {
- id: fixedPositioning
- x: 20
- y: 20
- width: 20
- height: 20
- }
- Rectangle {
- id: anchorPositioning
- anchors.fill: parent
- anchors.margins: 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 {qtqml-javascript-dynamicobjects.html}{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{qtqml-javascript-dynamicobjects.html}
-{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 singleton types instead of pragma library scripts
-
-If you are using a pragma library script to store application-wide instance data,
-consider using a QObject singleton type 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).
-
-*/