From 83044621103a12906394a35fbdcba966171bb507 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 8 Jan 2010 13:34:10 +1000 Subject: Basic QML JS benchmark --- src/declarative/qml/qmlengine_p.h | 2 +- src/declarative/qml/qmlobjectscriptclass_p.h | 2 +- tests/benchmarks/declarative/script/script.pro | 11 + tests/benchmarks/declarative/script/tst_script.cpp | 451 +++++++++++++++++++++ 4 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 tests/benchmarks/declarative/script/script.pro create mode 100644 tests/benchmarks/declarative/script/tst_script.cpp diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 8f2f0fb..ad81f4e 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -127,7 +127,7 @@ public: QUrl baseUrl; }; -class QmlEnginePrivate : public QObjectPrivate +class Q_AUTOTEST_EXPORT QmlEnginePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QmlEngine) public: diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index 923be73..ca50688 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -66,7 +66,7 @@ class QmlEngine; class QScriptContext; class QScriptEngine; class QmlContext; -class QmlObjectScriptClass : public QScriptDeclarativeClass +class Q_AUTOTEST_EXPORT QmlObjectScriptClass : public QScriptDeclarativeClass { public: QmlObjectScriptClass(QmlEngine *); diff --git a/tests/benchmarks/declarative/script/script.pro b/tests/benchmarks/declarative/script/script.pro new file mode 100644 index 0000000..48fea81 --- /dev/null +++ b/tests/benchmarks/declarative/script/script.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_script +QT += declarative script +macx:CONFIG -= app_bundle +CONFIG += release + +SOURCES += tst_script.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" + diff --git a/tests/benchmarks/declarative/script/tst_script.cpp b/tests/benchmarks/declarative/script/tst_script.cpp new file mode 100644 index 0000000..2aa7a9f --- /dev/null +++ b/tests/benchmarks/declarative/script/tst_script.cpp @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +class tst_script : public QObject +{ + Q_OBJECT +public: + tst_script() {} + +private slots: + void property_js(); + void property_getter(); + void property_getter_js(); + void property_getter_qobject(); + void property_getter_qmetaproperty(); + void property_qobject(); + void property_qmlobject(); + + void function_js(); + void function_cpp(); + void function_qobject(); + void function_qmlobject(); + + void function_args_js(); + void function_args_cpp(); + void function_args_qobject(); + void function_args_qmlobject(); + +private: +}; + +class TestObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int x READ x) + +public: + TestObject(QObject *parent = 0); + + int x(); + +public slots: + int method() { + return x(); + } + + int methodArgs(int val) { + return val + x(); + } + +private: + int m_x; +}; + +TestObject::TestObject(QObject *parent) +: QObject(parent), m_x(0) +{ +} + +int TestObject::x() +{ + return m_x++; +} + +#define PROPERTY_PROGRAM \ + "(function(testObject) { return (function() { " \ + " var test = 0; " \ + " for (var ii = 0; ii < 10000; ++ii) { " \ + " test += testObject.x; " \ + " } " \ + " return test; " \ + "}); })" + +void tst_script::property_js() +{ + QScriptEngine engine; + + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("x"), 10); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call().toNumber(); + } +} + +static QScriptValue property_getter_method(QScriptContext *, QScriptEngine *) +{ + static int x = 0; + return QScriptValue(x++); +} + +void tst_script::property_getter() +{ + QScriptEngine engine; + + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("x"), engine.newFunction(property_getter_method), + QScriptValue::PropertyGetter); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +static TestObject *property_getter_qobject_object = 0; +static QScriptValue property_getter_qobject_method(QScriptContext *, QScriptEngine *) +{ + static int idx = -1; + if (idx == -1) + idx = TestObject::staticMetaObject.indexOfProperty("x"); + + int value = 0; + void *args[] = { &value, 0 }; + QMetaObject::metacall(property_getter_qobject_object, QMetaObject::ReadProperty, idx, args); + + return QScriptValue(value); +} + +static QScriptValue property_getter_qmetaproperty_method(QScriptContext *, QScriptEngine *) +{ + static int idx = -1; + if (idx == -1) + idx = TestObject::staticMetaObject.indexOfProperty("x"); + + int value = 0; + value = property_getter_qobject_object->metaObject()->property(idx).read(property_getter_qobject_object).toInt(); + + return QScriptValue(value); +} + +void tst_script::property_getter_qobject() +{ + QScriptEngine engine; + + TestObject to; + property_getter_qobject_object = &to; + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("x"), engine.newFunction(property_getter_qobject_method), + QScriptValue::PropertyGetter); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } + property_getter_qobject_object = 0; +} + +void tst_script::property_getter_qmetaproperty() +{ + QScriptEngine engine; + + TestObject to; + property_getter_qobject_object = &to; + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("x"), engine.newFunction(property_getter_qmetaproperty_method), + QScriptValue::PropertyGetter); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } + property_getter_qobject_object = 0; +} + + +void tst_script::property_getter_js() +{ + QScriptEngine engine; + + QScriptValue v = engine.evaluate("(function() { var o = new Object; o._x = 0; o.__defineGetter__(\"x\", function() { return this._x++; }); return o; })").call(); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::property_qobject() +{ + QScriptEngine engine; + + TestObject to; + QScriptValue v = engine.newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(PROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::property_qmlobject() +{ + QmlEngine qmlengine; + + QScriptEngine *engine = QmlEnginePrivate::getScriptEngine(&qmlengine); + TestObject to; + + QScriptValue v = QmlEnginePrivate::get(&qmlengine)->objectClass->newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine->evaluate(PROPERTY_PROGRAM).call(engine->globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +#define FUNCTION_PROGRAM \ + "(function(testObject) { return (function() { " \ + " var test = 0; " \ + " for (var ii = 0; ii < 10000; ++ii) { " \ + " test += testObject.method(); " \ + " } " \ + " return test; " \ + "}); })" + +void tst_script::function_js() +{ + QScriptEngine engine; + + QScriptValue v = engine.evaluate("(function() { var o = new Object; o._x = 0; o.method = (function() { return this._x++; }); return o; })").call(); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +static QScriptValue function_method(QScriptContext *, QScriptEngine *) +{ + static int x = 0; + return QScriptValue(x++); +} + +void tst_script::function_cpp() +{ + QScriptEngine engine; + + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("method"), engine.newFunction(function_method)); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::function_qobject() +{ + QScriptEngine engine; + + TestObject to; + QScriptValue v = engine.newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::function_qmlobject() +{ + QmlEngine qmlengine; + + QScriptEngine *engine = QmlEnginePrivate::getScriptEngine(&qmlengine); + TestObject to; + + QScriptValue v = QmlEnginePrivate::get(&qmlengine)->objectClass->newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine->evaluate(FUNCTION_PROGRAM).call(engine->globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +#define FUNCTION_ARGS_PROGRAM \ + "(function(testObject) { return (function() { " \ + " var test = 0; " \ + " for (var ii = 0; ii < 10000; ++ii) { " \ + " test += testObject.methodArgs(ii); " \ + " } " \ + " return test; " \ + "}); })" + +void tst_script::function_args_js() +{ + QScriptEngine engine; + + QScriptValue v = engine.evaluate("(function() { var o = new Object; o._x = 0; o.methodArgs = (function(a) { return a + this._x++; }); return o; })").call(); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_ARGS_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +static QScriptValue function_args_method(QScriptContext *ctxt, QScriptEngine *) +{ + static int x = 0; + return QScriptValue(ctxt->argument(0).toNumber() + x++); +} + +void tst_script::function_args_cpp() +{ + QScriptEngine engine; + + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("methodArgs"), engine.newFunction(function_args_method)); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_ARGS_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::function_args_qobject() +{ + QScriptEngine engine; + + TestObject to; + QScriptValue v = engine.newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(FUNCTION_ARGS_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::function_args_qmlobject() +{ + QmlEngine qmlengine; + + QScriptEngine *engine = QmlEnginePrivate::getScriptEngine(&qmlengine); + TestObject to; + + QScriptValue v = QmlEnginePrivate::get(&qmlengine)->objectClass->newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine->evaluate(FUNCTION_ARGS_PROGRAM).call(engine->globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +QTEST_MAIN(tst_script) + +#include "tst_script.moc" -- cgit v0.12 From 6db0dd65bdb9d999f5f5bbb54808517d3d212315 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 8 Jan 2010 14:22:07 +1000 Subject: Optimization: Improve property read speed --- src/declarative/qml/qmlengine.cpp | 15 +++++------ src/declarative/qml/qmlengine_p.h | 1 + src/declarative/qml/qmlexpression.cpp | 3 +++ src/declarative/qml/qmlobjectscriptclass.cpp | 37 +++++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index c44f6b6..3b95558 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -116,11 +116,11 @@ struct StaticQtMetaObject : public QObject }; QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) -: rootContext(0), currentExpression(0), - isDebugging(false), contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), globalClass(0), - cleanup(0), erroredBindings(0), - inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), - inBeginCreate(false), networkAccessManager(0), typeManager(e), uniqueId(1) +: captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false), + contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), + globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0), + scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), inBeginCreate(false), + networkAccessManager(0), typeManager(e), uniqueId(1) { globalClass = new QmlGlobalScriptClass(&scriptEngine); } @@ -136,10 +136,7 @@ QUrl QmlScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url) } QmlScriptEngine::QmlScriptEngine(QmlEnginePrivate *priv) - : p(priv), - sqlQueryClass(0), - namedNodeMapClass(0), - nodeListClass(0) +: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0) { // Note that all documentation for stuff put on the global object goes in // doc/src/declarative/globalobject.qdoc diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index ad81f4e..2f177a2 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -144,6 +144,7 @@ public: int coreIndex; int notifyIndex; }; + bool captureProperties; QPODVector capturedProperties; QmlContext *rootContext; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 652c5f8..1321601 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -436,10 +436,12 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) QmlEnginePrivate *ep = QmlEnginePrivate::get(q->engine()); QmlExpression *lastCurrentExpression = ep->currentExpression; + bool lastCaptureProperties = ep->captureProperties; QPODVector lastCapturedProperties; ep->capturedProperties.copyAndClear(lastCapturedProperties); ep->currentExpression = q; + ep->captureProperties = data->trackChange; // This object might be deleted during the eval QmlExpressionData *localData = data; @@ -452,6 +454,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) } ep->currentExpression = lastCurrentExpression; + ep->captureProperties = lastCaptureProperties; // Check if we were deleted if (localData->q) { diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 7f95b8f..73dfd75 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -220,7 +220,7 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QScriptValue sobj = scriptEngine->newQObject(obj); return sobj.property(toString(name)); } else { - if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + if (enginePriv->captureProperties && !(lastData->flags & QmlPropertyCache::Data::IsConstant)) { enginePriv->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); } @@ -247,6 +247,41 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name void *args[] = { &rv, 0 }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); return rv; + } else if (lastData->propType == QMetaType::QReal) { + qreal rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::Int) { + int rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::Bool) { + bool rv = false; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::QString) { + QString rv; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::UInt) { + uint rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::Float) { + float rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); + } else if (lastData->propType == QMetaType::Double) { + double rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return QScriptValue(rv); } else { QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); return enginePriv->scriptValueFromVariant(var); -- cgit v0.12