On Wednesday 16 April 2014 12:55:38 Matthew Woehlke wrote:
> On 2014-04-16 03:18, Volker Krause wrote:
> > On Tuesday 15 April 2014 08:02:56 Thiago Macieira wrote:
> >> In other words: use QBasicAtomicPointer.
> > 
> > As mentioned on https://codereview.qt-project.org/#change,83272 Kevin Funk
> > measured the difference between the current approach and using atomics
> > using Olivier's initial benchmark, it's about 4-5x slower for checking if
> > there's a callback set.

@Volker: The 4-5x slower version was the one trying to support the multiple-
callback-scenario (implemented inefficiently, apparently).

> How are you doing that check?
> 
> I believe the 'correct' way is 'if (callback)', which calls an inline
> operator that accesses the internal pointer directly, i.e.
> 'callback->operator T*' -> 'callback->_q_value' (which should further be
> the first member, and thus require no additional instructions to access
> versus a raw pointer type).
> 
> The only reason this should perform significantly different is if you're
> comparing it to a non-volatile raw pointer... and I'd be very, very
> suspicious of using a non-volatile raw pointer that may be written in
> another thread.

Now, using the straight-forward approach of just defining a 
QAtomicPointer<void(*)()> callback; and testing whether this one is set via 
'if (callback)', I get much better results using Olivier's testbench.

I get a ~1.5x slowdown with atomic pointers (test4) compared to the version 
using raw pointers (test2) on my machine.

New benchmark attached, so everyone can test on his/her own.

If the results can be confirmed, I wonder whether we should actually 
reconsider using QInternal for the hooking API...

Greets

PS: Sorry for the confusion with the initial benchmark results (I'm not sure 
what I've done there...)

-- 
Kevin Funk
#include <QtCore/QVarLengthArray>

__attribute__((visibility("default")))  void noop() {};
#include <QtCore/QElapsedTimer>
#include <QtCore/QDebug>
#include <QtCore/QReadLocker>
#include <QtCore/QMutex>
#include <QtCore/QAtomicPointer>

extern void noop();

void (*test1_ptr)() = noop;
void (*test2_ptr)() = 0;

QAtomicPointer<void(*)()> callback;

static int test1() {
    test1_ptr();
    return 42;
}

static int test2() {
    if (test2_ptr)
        test2_ptr();
    return 42;
}

static int test3() {
    noop();
    return 42;
}

static int test4() {
    if (callback) {
        (*callback)();
    }
    return 42;
}

int main() {

    quint64 r;
    QElapsedTimer t;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test1();
    r = t.elapsed();
    qDebug() << "test1: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test2();
    r = t.elapsed();
    qDebug() << "test2: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test3();
    r = t.elapsed();
    qDebug() << "test3: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test4();
    r = t.elapsed();
    qDebug() << "test4: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test4();
    r = t.elapsed();
    qDebug() << "test4: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test3();
    r = t.elapsed();
    qDebug() << "test3: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test2();
    r = t.elapsed();
    qDebug() << "test2: " << r;

    t.start();
    for(quint64 i = 0; i <  500 * 1000 * 1000; ++i)
        test1();
    r = t.elapsed();
    qDebug() << "test1: " << r;
}
_______________________________________________
Development mailing list
Development@qt-project.org
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to