From 214e031d56714ba69ef929f1e763e243b393e460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Tue, 20 Dec 2011 17:11:46 +0100 Subject: Implement new static less API for QMetaType. Currently QMetaType API contains almost only static methods. This works nice until someone needs more information or needs to do more operations on a type. In this case every function call has to do type dispatch. This API allows to avoid redundant type dispatching, by caching a type information in a QMetaType instance. It gives significant performance boost especially for custom types (up to 9x). Change-Id: I223d066268402e072e41ca1d0a3e7bc160655d7f Reviewed-by: Stephen Kelly Reviewed-by: Bradley T. Hughes --- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 156 ++++++++++++++++++--- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 54 ++++++- 2 files changed, 186 insertions(+), 24 deletions(-) (limited to 'tests') diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f90e7f463f..72913d10f2 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -78,8 +78,12 @@ private slots: void createCopy(); void sizeOf_data(); void sizeOf(); + void sizeOfStaticLess_data(); + void sizeOfStaticLess(); void flags_data(); void flags(); + void flagsStaticLess_data(); + void flagsStaticLess(); void construct_data(); void construct(); void constructCopy_data(); @@ -88,6 +92,8 @@ private slots: void registerType(); void isRegistered_data(); void isRegistered(); + void isRegisteredStaticLess_data(); + void isRegisteredStaticLess(); void registerStreamBuiltin(); void automaticTemplateRegistration(); }; @@ -125,6 +131,9 @@ class MetaTypeTorturer: public QThread protected: void run() { + Bar space[1]; + space[0].~Bar(); + for (int i = 0; i < 1000; ++i) { const QByteArray name = QString("Bar%1_%2").arg(i).arg((size_t)QThread::currentThreadId()).toLatin1(); const char *nm = name.constData(); @@ -132,6 +141,15 @@ protected: #ifdef Q_OS_LINUX pthread_yield(); #endif + QMetaType info(tp); + if (!info.isValid()) { + ++failureCount; + qWarning() << "Wrong typeInfo returned for" << tp; + } + if (!info.isRegistered()) { + ++failureCount; + qWarning() << name << "is not a registered metatype"; + } if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) { ++failureCount; qWarning() << "Wrong typeInfo returned for" << tp; @@ -148,9 +166,22 @@ protected: ++failureCount; qWarning() << "Wrong typeName returned for" << tp; } - void *buf = QMetaType::create(tp, 0); - void *buf2 = QMetaType::create(tp, buf); - if (!buf) { + void *buf1 = QMetaType::create(tp, 0); + void *buf2 = QMetaType::create(tp, buf1); + void *buf3 = info.create(tp, 0); + void *buf4 = info.create(tp, buf1); + + QMetaType::construct(tp, space, 0); + QMetaType::destruct(tp, space); + QMetaType::construct(tp, space, buf1); + QMetaType::destruct(tp, space); + + info.construct(space, 0); + info.destruct(space); + info.construct(space, buf1); + info.destruct(space); + + if (!buf1) { ++failureCount; qWarning() << "Null buffer returned by QMetaType::create(tp, 0)"; } @@ -158,9 +189,20 @@ protected: ++failureCount; qWarning() << "Null buffer returned by QMetaType::create(tp, buf)"; } - QMetaType::destroy(tp, buf); + if (!buf3) { + ++failureCount; + qWarning() << "Null buffer returned by info.create(tp, 0)"; + } + if (!buf4) { + ++failureCount; + qWarning() << "Null buffer returned by infocreate(tp, buf)"; + } + QMetaType::destroy(tp, buf1); QMetaType::destroy(tp, buf2); + info.destroy(buf3); + info.destroy(buf4); } + new (space) Bar; } public: MetaTypeTorturer() : failureCount(0) { } @@ -480,13 +522,17 @@ template static void testCreateHelper() { typedef typename MetaEnumToType::Type Type; - void *actual = QMetaType::create(ID); + QMetaType info(ID); + void *actual1 = QMetaType::create(ID); + void *actual2 = info.create(); if (DefaultValueTraits::IsInitialized) { Type *expected = DefaultValueFactory::create(); - QCOMPARE(*static_cast(actual), *expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); delete expected; } - QMetaType::destroy(ID, actual); + QMetaType::destroy(ID, actual1); + info.destroy(actual2); } template<> @@ -529,9 +575,13 @@ static void testCreateCopyHelper() { typedef typename MetaEnumToType::Type Type; Type *expected = TestValueFactory::create(); - void *actual = QMetaType::create(ID, expected); - QCOMPARE(*static_cast(actual), *expected); - QMetaType::destroy(ID, actual); + QMetaType info(ID); + void *actual1 = QMetaType::create(ID, expected); + void *actual2 = info.create(expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); + QMetaType::destroy(ID, actual1); + info.destroy(actual2); delete expected; } @@ -588,6 +638,18 @@ void tst_QMetaType::sizeOf() QCOMPARE(QMetaType::sizeOf(type), size); } +void tst_QMetaType::sizeOfStaticLess_data() +{ + sizeOf_data(); +} + +void tst_QMetaType::sizeOfStaticLess() +{ + QFETCH(QMetaType::Type, type); + QFETCH(int, size); + QCOMPARE(QMetaType(type).sizeOf(), size); +} + struct CustomMovable {}; QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE); @@ -653,6 +715,23 @@ void tst_QMetaType::flags() QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject); } +void tst_QMetaType::flagsStaticLess_data() +{ + flags_data(); +} + +void tst_QMetaType::flagsStaticLess() +{ + QFETCH(int, type); + QFETCH(bool, isMovable); + QFETCH(bool, isComplex); + + int flags = QMetaType(type).flags(); + QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex); + QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex); + QCOMPARE(bool(flags & QMetaType::MovableType), isMovable); +} + void tst_QMetaType::construct_data() { create_data(); @@ -688,20 +767,30 @@ template static void testConstructHelper() { typedef typename MetaEnumToType::Type Type; - int size = QMetaType::sizeOf(ID); - void *storage = qMallocAligned(size, TypeAlignment::Value); - void *actual = QMetaType::construct(ID, storage, /*copy=*/0); - QCOMPARE(actual, storage); + QMetaType info(ID); + int size = info.sizeOf(); + void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0); + void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *actual2 = info.construct(storage2, /*copy=*/0); + QCOMPARE(actual1, storage1); + QCOMPARE(actual2, storage2); if (DefaultValueTraits::IsInitialized) { Type *expected = DefaultValueFactory::create(); - QCOMPARE(*static_cast(actual), *expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); delete expected; } - QMetaType::destruct(ID, actual); - qFreeAligned(storage); + QMetaType::destruct(ID, actual1); + qFreeAligned(storage1); + info.destruct(actual2); + qFreeAligned(storage2); QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0); QMetaType::destruct(ID, 0); + + QVERIFY(info.construct(0, /*copy=*/0) == 0); + info.destruct(0); } template<> @@ -748,15 +837,24 @@ static void testConstructCopyHelper() { typedef typename MetaEnumToType::Type Type; Type *expected = TestValueFactory::create(); + QMetaType info(ID); int size = QMetaType::sizeOf(ID); - void *storage = qMallocAligned(size, TypeAlignment::Value); - void *actual = QMetaType::construct(ID, storage, expected); - QCOMPARE(actual, storage); - QCOMPARE(*static_cast(actual), *expected); - QMetaType::destruct(ID, actual); - qFreeAligned(storage); + QCOMPARE(info.sizeOf(), size); + void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *actual1 = QMetaType::construct(ID, storage1, expected); + void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *actual2 = info.construct(storage2, expected); + QCOMPARE(actual1, storage1); + QCOMPARE(actual2, storage2); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); + QMetaType::destruct(ID, actual1); + qFreeAligned(storage1); + info.destruct(actual2); + qFreeAligned(storage2); QVERIFY(QMetaType::construct(ID, 0, expected) == 0); + QVERIFY(info.construct(0, expected) == 0); delete expected; } @@ -895,6 +993,18 @@ void tst_QMetaType::isRegistered() QCOMPARE(QMetaType::isRegistered(typeId), registered); } +void tst_QMetaType::isRegisteredStaticLess_data() +{ + isRegistered_data(); +} + +void tst_QMetaType::isRegisteredStaticLess() +{ + QFETCH(int, typeId); + QFETCH(bool, registered); + QCOMPARE(QMetaType(typeId).isRegistered(), registered); +} + void tst_QMetaType::registerStreamBuiltin() { //should not crash; diff --git a/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp index 1c5dc9227f..a3cdd38e56 100644 --- a/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -72,6 +72,8 @@ private slots: void constructCoreType_data(); void constructCoreType(); + void constructCoreTypeStaticLess_data(); + void constructCoreTypeStaticLess(); void constructCoreTypeCopy_data(); void constructCoreTypeCopy(); @@ -79,6 +81,8 @@ private slots: void constructInPlace(); void constructInPlaceCopy_data(); void constructInPlaceCopy(); + void constructInPlaceCopyStaticLess_data(); + void constructInPlaceCopyStaticLess(); }; tst_QMetaType::tst_QMetaType() @@ -89,6 +93,12 @@ tst_QMetaType::~tst_QMetaType() { } +struct BigClass +{ + double n,i,e,r,o,b; +}; +Q_DECLARE_METATYPE(BigClass); + void tst_QMetaType::typeBuiltin_data() { QTest::addColumn("typeName"); @@ -260,6 +270,23 @@ void tst_QMetaType::constructCoreType() } } +void tst_QMetaType::constructCoreTypeStaticLess_data() +{ + constructCoreType_data(); +} + +void tst_QMetaType::constructCoreTypeStaticLess() +{ + QFETCH(int, typeId); + QBENCHMARK { + QMetaType type(typeId); + for (int i = 0; i < 100000; ++i) { + void *data = type.create((void *)0); + type.destroy(data); + } + } +} + void tst_QMetaType::constructCoreTypeCopy_data() { constructCoreType_data(); @@ -285,6 +312,7 @@ void tst_QMetaType::constructCoreTypeCopy() void tst_QMetaType::constructInPlace_data() { constructCoreType_data(); + QTest::newRow("custom") << qMetaTypeId(); } void tst_QMetaType::constructInPlace() @@ -305,7 +333,7 @@ void tst_QMetaType::constructInPlace() void tst_QMetaType::constructInPlaceCopy_data() { - constructCoreType_data(); + constructInPlace_data(); } void tst_QMetaType::constructInPlaceCopy() @@ -326,5 +354,29 @@ void tst_QMetaType::constructInPlaceCopy() qFreeAligned(storage); } +void tst_QMetaType::constructInPlaceCopyStaticLess_data() +{ + constructInPlaceCopy_data(); +} + +void tst_QMetaType::constructInPlaceCopyStaticLess() +{ + QFETCH(int, typeId); + int size = QMetaType::sizeOf(typeId); + void *storage = qMallocAligned(size, 2 * sizeof(qlonglong)); + void *other = QMetaType::create(typeId); + QCOMPARE(QMetaType::construct(typeId, storage, other), storage); + QMetaType::destruct(typeId, storage); + QBENCHMARK { + QMetaType type(typeId); + for (int i = 0; i < 100000; ++i) { + type.construct(storage, other); + type.destruct(storage); + } + } + QMetaType::destroy(typeId, other); + qFreeAligned(storage); +} + QTEST_MAIN(tst_QMetaType) #include "tst_qmetatype.moc" -- cgit v1.2.3