diff options
| author | Marc Mutz <marc.mutz@qt.io> | 2025-04-08 10:56:20 +0200 |
|---|---|---|
| committer | Ahmad Samir <a.samirh78@gmail.com> | 2025-04-11 10:13:39 +0000 |
| commit | 8e98a3a82602016b2e9bfe2435031ae6ff8010e7 (patch) | |
| tree | fbd97b9a0efcaebcbd82a8b68acc445744541b43 /src/corelib/kernel/qmetaobject.cpp | |
| parent | cb48788425b04338a60587b09c27bd5ed74b739f (diff) | |
QMetaObject: fix performance regression in methodMatch()
Amends 22ce92f8040183faf9e1ba53c59c6b0b9172fb26, which apparently
changed the method name stored in the moc data from unqualified to a
qualified name. The original commit message doesn't mention it, but
the change in QMetaMethodPrivate::name() suggests as much.
Unfortunately, the search for the colon causes the name() call to
increase to 25% of the total methodMatch() runtime, up from 6.85%
before the change.
Since name() now always strips a possible prefix, re-add the original
name() as qualifiedName() and use that in methodMatch().
This is faster because we don't need to perform an a-priori search for
colons; instead, we can first check for endsWith(), and only if we
have a match, can we a-posteriori check that the match was preceded by
an (optional) colon.
Results on my machine:
********* Start testing of tst_QObject *********
Config: Using QtTest library 6.10.0, Qt 6.10.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 15.0.3 (github.com:llvm/llvm-project.git 48b23aa469b8cfdb6cde1c55bf3361cabcdef6bc)), ubuntu 20.04
PASS : tst_QObject::initTestCase()
PASS : tst_QObject::connect_disconnect_benchmark(normalized signature)
RESULT : tst_QObject::connect_disconnect_benchmark():"normalized signature":
- 923.542494 nsecs per iteration (total: 461,771,247, iterations: 500000)
+ 880.558792 nsecs per iteration (total: 440,279,396, iterations: 500000)
- 4,340.832532 CPU cycles per iteration, 4,7 GHz (total: 2,170,416,266, iterations: 500000)
+ 4,093.487614 CPU cycles per iteration, 4,65 GHz (total: 2,046,743,807, iterations: 500000)
- 13,706.07561 instructions per iteration, 3,157 instr/cycle (total: 6,853,037,807, iterations: 500000)
+ 12,779.02463 instructions per iteration, 3,122 instr/cycle (total: 6,389,512,318, iterations: 500000)
- 2,201.185595 branch instructions per iteration, 2,38 G/sec (total: 1,100,592,798, iterations: 500000)
+ 2,208.176500 branch instructions per iteration, 2,51 G/sec (total: 1,104,088,250, iterations: 500000)
For a ~5% overall speedup in both ns/iter and instr/iter, keeping in
mind that this data contains the disconnect() call, too.
As a drive-by, remove a second call of QMetaObjectPrivate::get() on the
same object, and reuse the previous call's result.
Pick-to: 6.9
Task-number: QTBUG-135572
Change-Id: Ide253b323e7b826f8fa09d2f5f57496861c12f75
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
Diffstat (limited to 'src/corelib/kernel/qmetaobject.cpp')
| -rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 17bacd219f0..969e335a212 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -191,6 +191,7 @@ public: { return static_cast<const QMetaMethodPrivate *>(q); } inline QByteArray signature() const; + inline QByteArrayView qualifiedName() const noexcept; inline QByteArrayView name() const noexcept; inline int typesDataIndex() const; inline const char *rawReturnTypeName() const; @@ -652,7 +653,11 @@ bool QMetaObjectPrivate::methodMatch(const QMetaObject *m, const QMetaMethod &me if (priv->parameterCount() != argc) return false; - if (QMetaMethodPrivate::get(&method)->name() != name) + // QMetaMethodPrivate::name() is looking for a colon and slicing the prefix + // away; that's too slow: we already know where the colon, if any, has to be: + if (const auto qname = priv->qualifiedName(); !qname.endsWith(name)) + return false; + else if (const auto n = qname.chopped(name.size()); !n.isEmpty() && !n.endsWith(':')) return false; const QtPrivate::QMetaTypeInterface * const *ifaces = priv->parameterMetaTypeInterfaces(); @@ -1921,13 +1926,18 @@ QByteArray QMetaMethodPrivate::signature() const QByteArrayView QMetaMethodPrivate::name() const noexcept { - Q_ASSERT(priv(mobj->d.data)->revision >= 7); - QByteArrayView name = stringDataView(mobj, data.name()); + QByteArrayView name = qualifiedName(); if (qsizetype colon = name.lastIndexOf(':'); colon > 0) return name.sliced(colon + 1); return name; } +QByteArrayView QMetaMethodPrivate::qualifiedName() const noexcept +{ + Q_ASSERT(priv(mobj->d.data)->revision >= 7); + return stringDataView(mobj, data.name()); +} + int QMetaMethodPrivate::typesDataIndex() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
