threading performance

Alles rund um die Programmierung mit Qt
Antworten
alainstgt
Beiträge: 19
Registriert: 22. August 2008 11:37
Wohnort: Stuttgart

threading performance

Beitrag von alainstgt »

ich arbeite mich in das Multithreading ein, habe ein kleines Programm zum Test geschrieben (siehe angehängte Dateien), mit verblüffendem Ergebnis!
Einmal der Unterschied zwischen MinGW 32-bit und MS Visual Studio 32-bit (Faktor 2), aber auch zwischen 32-bit und 64-bit Version (Faktor 3 bis 4), siehe Tabelle.
Der Test ist auf einen intel i7 6700HQ (4 cores) gelaufen.
Sind diese Ergebnisse repräsentativ? Sind die Unterschiede immer so groß?
Wenn jemand den MinGW 64 bit Compiler hätte, wäre ich am Vergleich MinGW32 mit MinGW64 auf einem 4 Core-Prozessor interessiert.
Die Dateien habe ich hier angehängt, sie sind ohne Änderungen Kompilierbar.

Compiler............Debug(single/multithread)....Release(single/multithread)
------------------------------------------------------------------------------------------------
MinGW 32-bit............ 5891 / 4594 ms .................. 5141 / 4047 ms
MS VS2015 32-bit........ 2891 / 3157 ms .................. 2406 / 2847 ms
MS VS2015 64-bit........ 2407 / 2422 ms ................... 688 / 969 ms

Ich liste die Pro Datei hier, weil sich diese nicht anhängen läßt( Fehler - Ungültige Dateierweiterung: test_qtconcurrent.pro)

Code: Alles auswählen

QT    += core
QT    += concurrent
QT    -= gui

CONFIG += c++11
CONFIG += console
CONFIG -= app_bundle

TARGET = test_qtconcurrent

TEMPLATE = app

SOURCES += main.cpp

Code: Alles auswählen

#include <QCoreApplication>
#include <QtConcurrent>
#include <QFuture>
#include <QTime>


void myFunction(QString name)
{
    for( int i = 0; i <= 5; ++i )
    {
        quint64 s = 0;
        for( quint64 j = 0; j < (1000*1000*10); ++j )
            s += atan(double(j));               // do something time consuming

        qDebug() << name << " s:" << s;
    }
}

int main( int argc, char *argv[] )
{
    QCoreApplication app(argc, argv);

    QTime t;

    t.start();
    myFunction("A");
    qDebug("Time elapsed: %d ms", t.elapsed());

    t.start();
    QFuture<void> t1 = QtConcurrent::run(myFunction, QString("A"));
    QFuture<void> t2 = QtConcurrent::run(myFunction, QString("B"));
    QFuture<void> t3 = QtConcurrent::run(myFunction, QString("C"));
    QFuture<void> t4 = QtConcurrent::run(myFunction, QString("D"));
    t1.waitForFinished();
    t2.waitForFinished();
    t3.waitForFinished();
    t4.waitForFinished();
    qDebug("Time elapsed: %d ms", t.elapsed());

    return app.exec();
}
Dateianhänge
main.cpp
(2.12 KiB) 249-mal heruntergeladen
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: threading performance

Beitrag von Christian81 »

Die Unterschiede sind so zu erwarten - auch wenn vielleicht nicht in dieser Größe.
Der MinGW-Compiler ist interessanter Weise immer langsamer als MSVC, vor allem wenn auf native Funktionen (und ich denke atan wird auch aus einer externe Windows-API aufgerufen).
Und 32 <-> 64 Bit ist in deinem Testcase auch klar. Du benutzt als Ziel einen 64Bit-Datentyp. Dieser muss unter 32Bit umständlich emuliert werden.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
alainstgt
Beiträge: 19
Registriert: 22. August 2008 11:37
Wohnort: Stuttgart

Re: threading performance

Beitrag von alainstgt »

ich habe weitere Tests mit interessantem Ergebnis gemacht.
Zunächst die Berechnung in der Schleife geändert, da ist plötzlich der GCC Compiler viel schneller.
Habe auch mit 8 threads (skaliert verblüffend gut bei beiden Compilern) und mit 16 threads. Da sind die zu vielen Threads, wie zu erwarten, sogar eine kleine Bremse.
Ergebnisse:
* ---------------------------------------------------------------------------------------------------------
* code: for(quint64 j = 0; j < (1000*1000*10); ++j) s += atan(double(j));
*
* compiler ............... debug(1/4/8/16-threads) ........ release(1/4/8/16-threads)
* ----------------------------------------------------------------------------------------------------------
* MinGW 5.30 32-bit .... 5891 / 4594 / 5195 / 9730 ms .... 5141 / 4047 / 4633 / 9133 ms
* MS VS2015 32-bit ..... 2891 / 3157 / 3586 / 7360 ms .... 2406 / 2847 / 3155 / 6313 ms
* MS VS2015 64-bit .... 2407 / 2422 / 2696 / 5470 ms .... 688 / 969 / 1234 / 2657 ms
* ---------------------------------------------------------------------------------------------------------
*
* ------------------------------------------------------------------------------------------------------
* code: for(quint64 j = 0; j < (1000*1000*50); ++j) s += j;
*
* compiler .............. debug(1/4/8/16-threads) ....... release(1/4/8/16-threads)
* ------------------------------------------------------------------------------------------------------
* MinGW 5.30 32-bit .... 984 / 1344 / 1496 / 3271 ms .... 16 / 15 / 47 / 109 ms ist richtig!
* MS VS2015 32-bit .... 813 / 1063 / 1134 / 2415 ms .... 235 / 343 / 438 / 875 ms
* MS VS2015 64-bit ....1078 / 878 / 828 / 1728 ms .... 78 / 78 / 125 / 234 ms
* -----------------------------------------------------------------------------------------------------
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: threading performance

Beitrag von Christian81 »

Da hast Du den Test zu einfach gemacht oder den Compiler für zu dumm gehalten. Die komplette Schleife "for(quint64 j = 0; j < (1000*1000*50); ++j) s += j;" wird beim Kompiliervorgang ausgewertet. Kann der gcc seit 4.9 wenn ich godbolt.org korrekt interpretiere. Clang kann das irgendwie schon immer und msvc und icc berechnen lieber zur Laufzeit.
https://godbolt.org/g/5o56WU

Was lernen wir daraus? Immer nur mit den Dingen rechnen, die später auch wirklich zum Einsatz kommen - zumindest wenn man die Performance betrachten möchte. Und um es auf die Spitze zu treiben - natürlich auch mit dem gleichen Compiler und der gleichen Hardware :)
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
alainstgt
Beiträge: 19
Registriert: 22. August 2008 11:37
Wohnort: Stuttgart

Re: threading performance

Beitrag von alainstgt »

wusste nicht dass Compiler mittlerweile so schlau sind.
Deine These wird auch dadurch bestätigt, dass das Ergebnis gleich bleibt, wenn ich die Anzahl Schleifen um Faktor 20 (1000 statt 50) erhöhe.
Die 16 ms werden von den qDebug() Anweisungen verursacht. 16 ms sind auch die Granularität der Clock.

Danke auf jeden Fall für deine Hinweise, Christian.
Antworten