Details
-
Bug
-
Resolution: Done
-
P2: Important
-
4.7.3
-
None
-
PC Ubuntu + ARM9 Embedded Linux
-
752cd2aca42f6625f1cfc364937e0d39828cf954
Description
Accessing a QVariantMap/QVariantList is very slow in QML.
This applies to every single QVariantMap/QVariantList acess, even if it is the same access. Around 150 ms on ARM9 200MHz.
Accessing a QList<QObject*> is 15 times faster on a ARM9.
Of course, a QList is accessed by indexes and QVariantMap by "string indexes". I could reach an even better access time with "string indexes" by associating a "QHash<QString, int> m_prgVarCode2Idx" and a "QList<QObject > m_sublist". This is 15 times faster than accessing a QList<QObject> and 30 times faster than accessing a QVariantMap:
Q_INVOKABLE QObject* getParameterFromCode(QString code) { QObject *retval = NULL; if (m_prgVarCode2Idx.contains(code)) retval = m_sublist.at(m_prgVarCode2Idx.value(code)); return retval; }
Let's consider this code
#ifndef PARAMETERTEST_H #define PARAMETERTEST_H #include <QtDeclarative> #include <QObject> class ParameterCode: public QObject { Q_OBJECT Q_PROPERTY(QString code READ code WRITE setCode NOTIFY notifyChanged); public: ParameterCode(QString & code):m_code(code){}; QString &code() { return m_code; } void setCode(QString code) { m_code = code; emit notifyChanged(); } signals: void notifyChanged(); private: QString m_code; }; class ParameterTest : public QObject { Q_OBJECT Q_PROPERTY(QList<QObject*> sublist READ sublist NOTIFY parametersNotifyChanged) Q_PROPERTY(QVariantList vsubparams READ vsubparams NOTIFY parametersNotifyChanged) Q_PROPERTY(QVariantMap variantMapParameters READ variantMapParameters NOTIFY parametersNotifyChanged); public: ParameterTest() { for (int i = 0; i < 500; i++) { QString code("TESTCODE"); code += QString::number(i); m_prgVarCode2Idx[code] = i; ParameterCode *newParameter = new ParameterCode(code); m_vsubparams.append(QVariant::fromValue((QObject*)newParameter)); m_vProgramParameters[code] = QVariant::fromValue((QObject*)newParameter); m_sublist.append((QObject*)newParameter); } } Q_INVOKABLE QObject* getParameterFromCode(QString code) { QObject *retval = NULL; if (m_prgVarCode2Idx.contains(code)) retval = m_sublist.at(m_prgVarCode2Idx.value(code)); return retval; } QVariantList & vsubparams() { return m_vsubparams; } QVariantMap & variantMapParameters() { return m_vProgramParameters; } QList<QObject*> & sublist() { return m_sublist; } signals: void parametersNotifyChanged(); private: QVariantMap m_vProgramParameters; QVariantList m_vsubparams; QList<QObject*> m_sublist; QHash<QString, int> m_prgVarCode2Idx; }; #endif // PARAMETERTEST_H
int main(int argc, char *argv[]) { QApplication a(argc, argv); QDeclarativeView *mHomeView = new QDeclarativeView(); QDeclarativeContext *context = mHomeView->rootContext(); context->setContextProperty("parametertest", new ParameterTest()); mHomeView->setSource(QUrl("qrc:/programSelectionPage.qml")); mHomeView->show(); return a.exec(); }
import QtQuick 1.0 Item { width: 320 height: 240 focus: true function test_1() //around 150 msecs per access on arm { var inittime = new Date(); var val; for (var i = 0; i < 10; i++) val = parametertest.variantMapParameters["TESTCODE50"].code; var duration = new Date() - inittime; console.log("1--parameter value:"+ val) console.log(" called in "+duration+" msecs. "); } function test_2() //around 150 msecs per access on arm { var inittime = new Date(); var val; for (var i = 0; i < 10; i++) val = parametertest.variantMapParameters.TESTCODE50.code; var duration = new Date() - inittime; console.log("2--parameter value:"+ val); console.log(" called in "+duration+" msecs. "); } function test_3() //around 125 msecs per access on arm { var inittime = new Date(); var val; for (var i = 0; i < 10; i++) val = parametertest.vsubparams[50].code; var duration = new Date() - inittime; console.log("3--parameter value:"+ val); console.log(" called in "+duration+" msecs. "); } function test_4() //around 9 msecs per access on arm { var inittime = new Date(); var val; for (var i = 0; i < 100; i++) val = parametertest.sublist[50].code; var duration = new Date() - inittime; console.log("4--parameter value:"+ val); console.log(" called in "+duration+" msecs. "); } function test_5() //around 0.6 msecs per access on arm { var inittime = new Date(); for (var i = 0; i < 100; i++) var val = parametertest.getParameterFromCode("TESTCODE50").code; var duration = new Date() - inittime; console.log("5--parameter value:"+ val); console.log(" called in "+duration+" msecs. "); } Keys.onPressed:{ test_1(); test_2(); test_3(); test_4(); test_5(); } }
On a PC:
1--parameter value:TESTCODE50 called in 187 msecs. 2--parameter value:TESTCODE50 called in 197 msecs. 3--parameter value:TESTCODE50 called in 68 msecs. 4--parameter value:TESTCODE50 called in 31 msecs. 5--parameter value:TESTCODE50 called in 4 msecs.
On a ARM9 200MHz:
1--parameter value:TESTCODE50 called in 1439 msecs. 2--parameter value:TESTCODE50 called in 1510 msecs. 3--parameter value:TESTCODE50 called in 1263 msecs. 4--parameter value:TESTCODE50 called in 956 msecs. 5--parameter value:TESTCODE50 called in 57 msecs.
Why is it so slow with a QVariantMap ? It seems the hash table between "string indexes" and indexes are constructed at every single access.