schlechte Qt socket IO performance MS Windows

Verschiedenes zu Qt
Antworten
Borstel
Beiträge: 5
Registriert: 28. Mai 2006 13:07
Wohnort: Frankfurt/M

schlechte Qt socket IO performance MS Windows

Beitrag von Borstel »

Hallo,

ich scanne gerade verschiedene platformen fuer ein projekt bei dem schnelle reaktionszeiten auf netzwerk daten sehr wichtig ist. Dabei bin ich auch auf Qt gestossen und ein paar kleinere tests geschrieben. Der basis test ist ein UDP ping bei dem round trips pro sekunde gemessen werden. Qt auf Windows hat dabei sehr schlecht abgeschnitten, zum vergleich mal die ergebnisse:

Qt windows: 1000 (700 mit GUI update) messages per second
.NET windows: 2600 (1200 mit GUI update) messages per second
ACE Windows: 3800 messages per second
Qt linux: 4200 (400 mit GUI update) messages per second
ACE Linux: 8000 messages per second

Ich frage mich warum Qt unter windows so schlecht abschneidet, gibt es eventuell einen 1ms timer der nach jedem packet erst mal abgewarted wird um windows messages abzufragen? Das wuerde in etwa die 1000 messages pro sekunde erklaeren. Wenn dem so ist, kann man diesen timer umgehen? Und/oder kann man asynchrone windows sockets integrieren?
Qt unter X sieht zwar auf den ersten blick ganz gut aus, aber wenn man irgendwas anzeigen will wird man voll ausgebremst.

Als test applikation habe ich den broadcastreceiver aus den examples genommen und lediglich einen timer sowie paket zaehler eingefuegt.





Der code als referenz:

Code: Alles auswählen

Receiver::Receiver(QWidget *parent)
    : QDialog(parent)
{
    statusLabel = new QLabel(tr("Listening"));
    pktPerSecLabel = new QLabel(tr("0"));
    quitButton = new QPushButton(tr("&Quit"));
    startButton = new QPushButton(tr("&Start"));
    lineEdit = new QLineEdit(tr("10.60.67.197"), parent);

    pktPerSecLabel->setFrameStyle(QFrame::StyledPanel);
    pktPerSecLabel->setFrameShadow(QFrame::Shadow::Sunken);

    statusLabel->setFrameStyle(QFrame::StyledPanel);
    statusLabel->setFrameShadow(QFrame::Shadow::Sunken);

    udpSocket = new QUdpSocket(this);
    udpSocket->bind(12889);
	nPackets = 0;

    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingDatagrams()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
	connect(startButton, SIGNAL(clicked()), this, SLOT(sendPingDgram()));

    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->addStretch(1);
    buttonLayout->addWidget(quitButton);
	buttonLayout->addWidget(startButton);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addWidget(pktPerSecLabel);
	mainLayout->addWidget(lineEdit);
    mainLayout->addLayout(buttonLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Broadcast Receiver"));
	timer = new QTimer(parent);
	connect(timer,SIGNAL(timeout()), this, SLOT(timerProc()));
}

void Receiver::timerProc()
{
    static int nCalls = 0;
    nCalls++;
    QString st;
    int packetsPerSec = nPackets / (nCalls*10);
    st.sprintf("%i", packetsPerSec);
    pktPerSecLabel->setText(st);
}

void Receiver::processPendingDatagrams()
{
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        char buffer[1024];
        QHostAddress addr;
         quint16 port;
         qint64 nBytes;
         nBytes = udpSocket->readDatagram(buffer, 1024, &addr, & port);
        //datagram.resize(udpSocket->pendingDatagramSize());
        //udpSocket->readDatagram(datagram.data(), datagram.size(), & addr, & port);
        nPackets ++;
        QString st;
        //st.sprintf("%i",nPackets); // uncomment to test GUI update speed
        //statusLabel->setText(st);
        udpSocket->writeDatagram(buffer, nBytes, addr, port);
    }
}
void Receiver::sendPingDgram()
// called once to initiate the ping loop
{
	QString text = lineEdit->text();
	QHostAddress host;
	QByteArray dgram;
	qint16 port;
	port = 12889;
	host.setAddress(text);
	dgram.clear();
	dgram.append("1234567890");
	udpSocket->writeDatagram(dgram, host, port);
	timer->start(10000);
}
FlorianBecker
Beiträge: 1213
Registriert: 2. Dezember 2004 10:54
Kontaktdaten:

Beitrag von FlorianBecker »

Die Net Dinge in Qt sind eigentlich generell asynchron.

Eine Lösung könnte vielleicht ein weiterer Thread schaffen. Was hast du denn genau vor?
Borstel
Beiträge: 5
Registriert: 28. Mai 2006 13:07
Wohnort: Frankfurt/M

Beitrag von Borstel »

Hallo Florian,

ein extra thread will ich eigentlich vermeiden, da dann wieder synchonisationsverluste bei der datenuebergabe entstehen. Die applikation soll daten von verschiedenen finanzdatenfeeds moeglichst schnell und vollstaendig anzeigen (text und z.T. als grafik). Wichtig sind niedrige reaktionszeiten vom empfang der daten bis zur anzeige.

Das handling der network IO ist natuerlich asynchron, ich frage mich nur woher die 1000 messages pro sekunde kommen (es waren ziemlich genau 1000 messages). Fuer mich deuted alles auf einen timer von 1ms im main event handler hin.
FlorianBecker
Beiträge: 1213
Registriert: 2. Dezember 2004 10:54
Kontaktdaten:

Beitrag von FlorianBecker »

Dann hättest du aber auch einen Timer unter Qt Linux, logischerweise, oder?

Also ich denke nicht, dass es einen Timer dafür gibt, es geht halt nicht schneller, weil der eine Thread aufpassen muss, dass alle Daten verarbeitet werden und das siehst du ja z.B. auch an den Zeiten, wenn du GUI aufbaust, er muss eben in der gleichen Zeit viel mehr Dinge abarbeiten.

Mh, Daten also möglichst schnell über einen Socket bereitstellen... Mir fällt dafür nur noch Komprimierung ein, wenn keinen neuen Thread starten willst.

Vielleicht wäre auch eine generell andere Lösung interessant. Es gibt z.B. ein SF Projekt, welches gesamte GUI über einen Socket bereitstellt. Ist zwar GPL und Qt3, aber Anregung könnte man sich dort bestimmt holen. Gut, leider fällt mir auch hierzu nicht mehr der Name ein, aber hat irgendwas mit einem ERP System am Hut, vielleicht findest du das ja.
BartSimpson
Beiträge: 1379
Registriert: 6. November 2004 12:03
Kontaktdaten:

Beitrag von BartSimpson »

Welchen compiler haste denn genutzt?
kannste ja mal testeweise den von intel nehmen und die Sache auf deine CPU optimieren.
Borstel
Beiträge: 5
Registriert: 28. Mai 2006 13:07
Wohnort: Frankfurt/M

Beitrag von Borstel »

Compiler ist VC 7.0 (Visual Studio 2003). Intel holt vielleicht ein paar prozent raus.
Dann hättest du aber auch einen Timer unter Qt Linux, logischerweise, oder?
Das eventhandling ist platform spezifisch, fuer windows passiert das alles in qeventdispatcher_win.cpp. Soweit gesehen habe handled Qt die gesamte IO ueber ein "hidden window". Es ist also durchaus erklaerbar, dass es zwischen den platformen grosse unterschiede geben kann.

.NET benutzt asynchrone IO completion ports for sockets, daher ist es wohl auch schneller, da die events nicht ueber eine windows message pump laufen muessen.

[/quote]
Borstel
Beiträge: 5
Registriert: 28. Mai 2006 13:07
Wohnort: Frankfurt/M

Beitrag von Borstel »

Noch mal ein update...

Ich habe noch ein paar tests gemacht und auch ein wenig im source code gestoebert. Alles deuted darauf hin, dass das windows message loop handling nicht besonders gut implementiert ist. Fuer IO events werden windows messages mit PostMessage generiert und erst im zweiten duchlauf abgearbeited. Alles in allem nicht besonders effectiv. Unter Linux sieht es wesentlich besser aus offenbar ist das event loop handling dort viel besser optimiert.
Noch ein wort zum rendering/painting: .NET unter windows ist doppelt so schnell, und unter Linux (gleiche hardware, dual boot setup) sieht es z.T. noch schlechter fuer Qt aus.

Um hier nicht den negativen zu machen, mit Qt ist es sehr angenehm zu programmieren und auch sehr verstaendlich. In dieser hinsicht gibt es auch keine kritik, nur die performance ist halt nicht da wo ich sie gerne haette.
BartSimpson
Beiträge: 1379
Registriert: 6. November 2004 12:03
Kontaktdaten:

Beitrag von BartSimpson »

Das ist halt das Problem, wenn du eine API für alles haste. Egal ob mac/Windows/Unix etc. Da muste denn leider ein paar abstriche machen:(
Mal schauen was Qt 4.2 bringt.
Querdenker
Beiträge: 99
Registriert: 1. Dezember 2005 17:44
Wohnort: Karlsruhe

Beitrag von Querdenker »

Hi,

da bleibt mir doch glatt die Spucke weg.
Da nimmt einer einen Porsche, baut darin einen Rasenmähermotor ein
und wundert sich, warum das Dingens so lahm ist.

Klar ist, Dein Compiler ist für .NET optimiert. Nimm mal einen MinGW Compiler und checke deine Dinger nochmals und Du lernst, was Speed ist.

Ich kann überhaupt keine Einbußen feststellen.
Ne .NET Sprachröhre hat hier gerade noch gefehlt :evil:
e Grüssle au
Q... ;)
BartSimpson
Beiträge: 1379
Registriert: 6. November 2004 12:03
Kontaktdaten:

Beitrag von BartSimpson »

Ich hasse das .net Zeugs. Erst die großen versprechungen, und was ist davon übrig geblieben nicht viel:( Die beschworende Platformunabhändigkeit ist faktisch nicht da.
Borstel
Beiträge: 5
Registriert: 28. Mai 2006 13:07
Wohnort: Frankfurt/M

Beitrag von Borstel »

Querdenker hat geschrieben: Ne .NET Sprachröhre hat hier gerade noch gefehlt :evil:
Was das angeht bin ich weder ein .NET verfechter noch fuer irgend ein anderes system. Ich mache meine eigenen tests und wenn dabei ein bestimmtes system besser abschneidet dann werde ich es auch benutzen.

Und ich glaube nicht dass ein anderer compiler mehr als 20% rausholen kann (wenn ueberhaupt). Aber ich werd's mal ausprobieren....
Antworten