Async/Overlapped Sockets Benchmark



  • Hi,

    asynchrone Behandlung (Sockets) soll ja (auch gegenüber select + nonblocking Sockets) einige Vorteile haben.

    http://www.c-plusplus.net/forum/285388 schrieb:

    Was ist nun der Vorteil von Overlapped I/O ggü. dem non-blocking-Ansatz? Als Resultat funktionieren beide Modelle ähnlich, jedoch gibt es Unterschiede:
    Die Funktionen der Overlapped I/O nutzen die der API übergebenen Puffer zum Senden und Empfangen im Kernel-Mode und zugleich im User-Mode, sodass sie nicht hin und her kopiert werden müssen. Es wird quasi das alloziierte Array direkt an die Netzwerkkarte weitergereicht, wodurch die Overlapped-Funktionen signifikant schneller sind als z.B. send() oder recv().

    Mich würde wirklich interessieren wie groß diese Unterschiede sind, wann sie sich bemerkbar machen etc. Da ich aber weder einen Server mit der entsprechenden Bandbreite, noch genügen User habe um das irgendwie vernünftig testen zu können, würden mich Benchmarks in dieser Richtung interessieren. Am besten wären alle Kombinationen mit select, Threads und Overlapped I/O, Unterschiede auf Linux, am besten noch verglichen mit boost::asio und Poco Net.
    Ist vielleicht etwas viel, aber alles was in die Richtung wird werde ich gerne lesen. Leider hat Google kaum etwas ausgespuckt, weshalb ich jetzt mal hier frage, vielleicht hat ja jemand ein paar Links dazu.

    Besten Dank im Voraus. 🙂



  • am besten noch verglichen mit boost::asio und Poco Net.

    Asio nutzt doch Overlapped I/O unter Win32.

    Es wird quasi das alloziierte Array direkt an die Netzwerkkarte weitergereicht, wodurch die Overlapped-Funktionen signifikant schneller sind als z.B. send() oder recv().

    Signifikant? Das bezweifle ich.
    Ein DDR-3 RAM hat locker einen Durchsatz von > 9000 MB/s, dagegen ist jede Netzwerkverbindung arschlahm.
    Da fällt es wohl kaum ins Gewicht wenn ein Buffer erst nochmal kopiert wird.



  • Ethon schrieb:

    am besten noch verglichen mit boost::asio und Poco Net.

    Asio nutzt doch Overlapped I/O unter Win32.

    Die Frage ist ob asio irgendetwas kostet.



  • Ich behaupte mal ASIO kostet, verglichen mit select() + non-blocking IO, mehr Entwicklungszeit und mehr Entwickler-Gehirnzellen.



  • Es ist relativ aufwändig, Daten zu finden. Aus einer meiner Quellen hab ich folgendes:

    I/O Model
     Attempted/Connected
     Memory Used (KB)
     Non-Paged Pool
     CPU Usage
     Threads
     Throughput (Send/ Receive Bytes Per Second)
    
    Blocking
     7000/ 1008
     25,632
     36,121
     10–60%
     2016
     2,198,148/ 2,198,148
    
     12,000/ 1008
     25,408
     36,352
     5– 40%
     2016
     404,227/ 402,227
    
    Non- blocking
     7000/ 4011
     4208
     135,123
     95–100%*
     1
     0/0
    
     12,000/ 5779
     5224
     156,260
     95–100%*
     1
     0/0
    
    WSA- Async Select
     7000/ 1956
     3640
     38,246
     75–85%
     3
     1,610,204/ 1,637,819
    
     12,000/ 4077
     4884
     42,992
     90–100%
     3
     652,902/ 652,902
    
    WSA- Event Select
     7000/ 6999
     10,502
     36,402
     65–85%
     113
     4,921,350/ 5,186,297
    
     12,000/ 11,080
     19,214
     39,040
     50–60%
     192
     3,217,493/ 3,217,493
    
     46,000/ 45,933
     37,392
     121,624
     80–90%
     791
     3,851,059/ 3,851,059
    
    Over- lapped (events)
     7000/ 5558
     21,844
     34,944
     65–85%
     66
     5,024,723/ 4,095,644
    
     12,000/12,000
     60,576
     48,060
     35–45%
     195
     1,803,878/ 1,803,878
    
     49,000/48,997
     241,208
     155,480
     85–95%
     792
     3,865,152/ 3,834,511
    
    Over- lapped (comple- tion port)
     7000/ 7000
     36,160
     31,128
     40–50%
     2
     6,282,473/ 3,893,507
    
     12,000/12,000
     59,256
     38,862
     40–50%
     2
     5,027,914/ 5,027,095
    
     50,000/49,997
     242,272
     148,192
     55–65%
     2
     4,326,946/ 4,326,496
    

    hustbaer, du scheinst zu vergesen, dass diese Art der Technologie für Server mit mehreren Tausend parallelen Verbindungen gedacht ist, nicht für kleine Blümchen-Server, wo ein select() genügt. boost::asio ist Overkill, wenn man einen kleinen Server bauen will.
    Bzgl. des "neuen" DDR3-RAMS: Die Netzwerktechnik entwickelt sich genauso, wenn auch nicht ganz so schnell. Vor ein paar Monaten noch wurde mit 100.000kbit/s Downstream für Privatkunden geworben.
    Wenn man Overlapped (und später auf Windows 8 Registered I/O) nicht bräuchte, hätte man es nicht erfunden. Manche Anwendungen (an Börsen z.B.), wo die Nanosekunden beginnen, bedeutsam zu werden, sind die Server nur als Kernel-Mode-Treiber schnell genug, weit weg von einer API wie den Berkeley-Sockets. Ja sogar der IIS hat sein gesamtes Inneres lieber in einen Treiber gepackt (http.sys) als es zu einer normalen Overlapped-Anwendung zu machen.
    Und jetzt, wo man die Wahl hatte zwischen echtem NIC-Treiber, Overlapped I/O und Berkeley-Sockets packte man die Winsock Kernel-Interfaces (WSK) noch zwischen Overlapped I/O und Treibern. Mit Windows 8 wird das mit RIO noch feiner gestaffelt.



  • Jodocus schrieb:

    hustbaer, du scheinst zu vergesen, dass diese Art der Technologie für Server mit mehreren Tausend parallelen Verbindungen gedacht ist, nicht für kleine Blümchen-Server, wo ein select() genügt.

    Ich "scheine" das nur zu vergessen, wenn man etwas in meine Aussage hineininterpretiert, was so nicht dasteht, und was ich auch nicht gemeint habe.

    Die Frage war "ob asio irgendetwas kostet". Meine Antwort ist: ja, Entwicklungszeit.

    Wie kann man das bitte falsch verstehen? Wo impliziert das, dass ASIO keine Berechtigung hätte?

    Natürlich hat ASIO seine Berechtigung.

    boost::asio ist Overkill, wenn man einen kleinen Server bauen will.

    Ja, genau. Siehe oben.

    Bzgl. des "neuen" DDR3-RAMS: Die Netzwerktechnik (blaaaah...)

    Ich hab nirgends irgendwas von DDR3 RAMs und/oder Netzwerktechnik geschrieben.
    Vielleicht solltest du irgendwie darauf hinweisen dass sich der Adressat deiner Erwiederungen geändert hat. So mit nem Absatz oder noch besser ner hüsbchen "---" Trennlinie.

    ----

    @all
    Asynchroner IO, speziell mit Completion-Ports, ist eines der Themen die unglaublich gehyped werden. ASIO hier, ASIO da, wer was anderes verwendet ist doof. Dabei ist ASIO für viele Projekte einfach nur Overkill - man tut sich komplett unnötigerweise viel zu viel an, verplempert Entwicklungszeit, und das alles für ...? Naja, im Idealfall genau nix, und im Normalfall einen Haufen unnötiger Bugs.



  • Jodocus schrieb:

    hustbaer, du scheinst zu vergesen, dass diese Art der Technologie für Server mit mehreren Tausend parallelen Verbindungen gedacht ist, nicht für kleine Blümchen-Server, wo ein select() genügt. boost::asio ist Overkill, wenn man einen kleinen Server bauen will.

    Also warum soll man die in jeder Hinsicht schlechtere Lösung wählen? Ah, wahrscheinlich, weil die Dokumentation von ASIO ein bisschen technisch gehalten ist und einen aufmerksamen Leser erfordert. Mit BSD-Sockets bekommt man per Copy-and-Paste ein paar Minuten schneller eine Verbindung zustande, toll!



  • @TyRoXx
    Wie viele funktionierende nicht-triviale Serverprogramme hast du mit Boost ASIO schon entwickelt?



  • hustbaer schrieb:

    @TyRoXx
    Wie viele funktionierende nicht-triviale Serverprogramme hast du mit Boost ASIO schon entwickelt?

    Was ist denn nicht-trivial? Netzwerk ist trivial. Verbindungen annehmen, empfangen, senden. Mit wenigen hundert Zeilen sind die ASIO-Sockets perfekt gekapselt und eingebunden.
    Das habe ich auch schon mehrmals mit BSD-Sockets gemacht. Die waren fehleranfällig und erforderten Anpassungen bei der Portierung, weil Microsoft Extra-Würste brät.
    Ganz abgesehen davon, dass ASIO eine asynchrone Architektur implementiert und als typische Anwendung Sockets mitliefert.
    Wer keine Ansprüche hat, kann BSD-Sockets nehmen. Ich habe aber Ansprüche an die Bibliotheken, die ich benutze.



  • Was ist der Unterschied zu einem Future mit einer blockierenden Send/Recv-Operation mit BSD=Sockets?



  • knivil schrieb:

    Was ist der Unterschied zu einem Future mit einer blockierenden Send/Recv-Operation mit BSD=Sockets?

    Bei blockierenden IO Requests, mit oder ohne Futures, mit oder ohne Thread-Pools, brauchst du einen Thread pro gleichzeitig ausstehendem IO Request. Weil der Thread ja vom IO Request blockiert wird.

    Bei asynchronem IO, mit oder ohne ASIO, brauchst du das nicht, da kannst du z.B. 10000 pending IO Requests haben, und trotzdem nur einen Thread (oder einen Pool mit weit weniger als 10000 Threads) verwenden. Trotzdem spart man sich im Vergleich zu select() + non-blocking den Overhead eines select() mit tausenden Sockets, und kann auch mit mehreren Threads Socket-IO machen.



  • TyRoXx schrieb:

    hustbaer schrieb:

    @TyRoXx
    Wie viele funktionierende nicht-triviale Serverprogramme hast du mit Boost ASIO schon entwickelt?

    Was ist denn nicht-trivial? Netzwerk ist trivial. Verbindungen annehmen, empfangen, senden. Mit wenigen hundert Zeilen sind die ASIO-Sockets perfekt gekapselt und eingebunden.
    Das habe ich auch schon mehrmals mit BSD-Sockets gemacht. Die waren fehleranfällig und erforderten Anpassungen bei der Portierung, weil Microsoft Extra-Würste brät.
    Ganz abgesehen davon, dass ASIO eine asynchrone Architektur implementiert und als typische Anwendung Sockets mitliefert.
    Wer keine Ansprüche hat, kann BSD-Sockets nehmen. Ich habe aber Ansprüche an die Bibliotheken, die ich benutze.

    Nochmal konkret die Frage: hast du schon was mit (Boost-)ASIO gemacht?

    Ich hab' ein Projekt mit Boost-ASIO angefangen (das dann leider abgebrochen wurde - was mit ASIO allerdings nix zu tun hatte), und durfte dort einige der Fallstricke und "Nettigkeiten" der Boost-ASIO kennenlernen.

    Und was ist nicht-trivial... Hm.
    Sagen wir mal ein Server der
    * Eine Liste der verbundenen Clients verwalten muss
    * Verbindungen zu den Clients (EDIT: zu *einzelnen* Clients) jederzeit trennen können muss
    * Eines der "lästigen" Protokolle ala HTTP verwenden muss, wo man dummerweise nicht von vornherein weiss wie viele Daten man noch lesen muss, bis man eine "Message" komplett empfangen hat



  • Bzgl. des "neuen" DDR3-RAMS: Die Netzwerktechnik entwickelt sich genauso, wenn auch nicht ganz so schnell. Vor ein paar Monaten noch wurde mit 100.000kbit/s Downstream für Privatkunden geworben.

    100.000 kbit/s sind doch gerade mal popelige ~12 MB/s.
    Dh. in etwa geht 1 Promille für das Buffer kopieren drauf. Zumindestens würde ich als Milchmädchen das so sagen.



  • hustbaer schrieb:

    Nochmal konkret die Frage: hast du schon was mit (Boost-)ASIO gemacht?

    Ja und es hat mich offensichtlich überzeugt.

    hustbaer schrieb:

    Ich hab' ein Projekt mit Boost-ASIO angefangen (das dann leider abgebrochen wurde - was mit ASIO allerdings nix zu tun hatte), und durfte dort einige der Fallstricke und "Nettigkeiten" der Boost-ASIO kennenlernen.

    Beispiele?



  • > Also warum soll man die in jeder Hinsicht schlechtere Lösung wählen? Ah, wahrscheinlich, weil die Dokumentation von ASIO ein bisschen technisch gehalten ist und einen aufmerksamen Leser erfordert. Mit BSD-Sockets bekommt man per Copy-and-Paste ein paar Minuten schneller eine Verbindung zustande, toll!

    Weil du auf einmal mit Sachen wie Threadsicherheit arbeiten musst, das ist alles andere als trivial.

    > 100.000 kbit/s sind doch gerade mal popelige ~12 MB/s.
    Dh. in etwa geht 1 Promille für das Buffer kopieren drauf. Zumindestens würde ich als Milchmädchen das so sagen.

    Naja, mittlerweile gibt's wohl schon 100 Mbit/s (http://netforbeginners.about.com/od/internet101/tp/What-Broadband-Internet-Choices-Are-Available.htm) (für Privatanwender), für Unternehmen und Serverfarmen sicher noch einiges mehr. Da werden aus deinem Promille einige Prozente.



  • TyRoXx schrieb:

    hustbaer schrieb:

    Nochmal konkret die Frage: hast du schon was mit (Boost-)ASIO gemacht?

    Ja und es hat mich offensichtlich überzeugt.

    hustbaer schrieb:

    Ich hab' ein Projekt mit Boost-ASIO angefangen (das dann leider abgebrochen wurde - was mit ASIO allerdings nix zu tun hatte), und durfte dort einige der Fallstricke und "Nettigkeiten" der Boost-ASIO kennenlernen.

    Beispiele?

    Als erstes fand ich mal toll einen Bug in der SSL Anbindung finden zu dürfen:
    https://svn.boost.org/trac/boost/ticket/2910
    (Das Ticket ist von mir)
    OK, das ist EIN Bug, wenn ich mir die Change-Logs von anderen Projekten so ansehe ... also da gibt es viel schlimmeres. Wenn man sowas allerdings (wie es bei mir der Fall war) am 3. oder 4. Tag des schönen neuen Projekts mit der schönen ASIO selbst findet, sträkt das natürlich nicht gerade das Vertrauen in die Lib.

    Dann fand ich es "interessant" herauszufinden, dass die ASIO Completion-Handler unter bestimmten Bedingungen nicht aufruft.
    Wenn das passiert, ist die einzige Möglichkeit draufzukommen dass es passiert ist, die, zu gucken wann die letzte Kopie des übergebenen Handlers zerstört wird.
    D.h. man braucht schon wieder shared_ptr in den Handlern, oder man muss selbst Referenzen zählen.
    Dummerweise gilt das "Handler wird nur im Strand ausgeführt" aber nur für den operator () des Handlers, nicht aber für das Erzeugen oder Zerstören von Kopien des Handlers.

    D.h. der Destruktor der letzten Kopie eines Handlers kann in irgendeinem Thread zu irgendeiner Zeit laufen. Tja blöd, wir wollten uns doch darauf verlassen dass der Strand für uns das Synchronisieren übernimmt. Doof. Aber ne, geht schon, post()en wir einfach ne Invokation der nötigen Cleanup-Funktion auf den Strand, dann ist wieder alles gut. Pustekuchen, nix ist gut, denn das post()en von Handlern kann ne Exception werfen. Nämlich wenn der Handler sich nicht kopieren lässt (OK, da ist man wohl selbst schuld), oder wenn einfach ein bad_alloc von irgendwoher geflogen kommt. Also doch doof.
    D.h. man scheisst entweder auf die Fälle wo der Speicher knapp wird ( set_new_handler(terminate) , yeah!), oder man muss erst wieder selbst synchronisieren. Na gut, synchronisieren wir eben selbst. Dann können wir wenigstens den Strand (und den damit verbundenen Overhead) loswerden. Oder doch nicht? Was mich gleich zum nächsten Punkt bringt...

    Der ganze Tanz mit den Strands, bloss weil man Verbindungen "von aussen" Trennen können möchte. Die einzige (sinnvolle) Möglichkeit (die ich kenne), die die ASIO diesbezüglich anbietet, ist den Stream zu schliessen. Jetzt darf man den Stream aber nicht einfach so schliessen, weil Operationen auf dem Stream nicht threadsafe sind. Dummerweise hat man aber ausser den erwähnten Strands keine Möglichkeit, die Ausführung von Handlern von "composed asynchronous operations" zu synchronisieren. Denen es ja ebenfalls erlaubt ist Operationen auf dem Stream zu machen. Es nützt also nichts, wenn man in seinem "Session" Objekt bereits selbst eine Mutex drinnen hat über die man bestimmte Dinge synchronisiert. Man muss trotzdem zusätzlich alle IOs in einen Strand einwickeln. Was den Overhead verdoppelt.

    Und das alles nur, weil man Sessions "tracken" (=eine zentrale Liste aller offenen Sessions verwalten), und Sessions unter bestimmten Bedingungen von aussen abbrechen können möchte.



  • asio muss schon eine unglaublich schlechte bibliothek sein, wenn es die arbeit erschwert anstatt zu vereinfachen (wie man es normalerweise von bibliotheken gewöhnt ist)



  • ps:
    Nur weil in diesem Thread (unter anderem von mir) select() + non-blocking IO als "Alternative" zu ASIO dargestellt wurde...

    Der echte "ASIO Killer" für Projekte die schnell fertig werden sollen, und keine Unmengen an gleichzeitigen Connections unterstützen müssen, ist mMn. nicht select() + non-blocking IO, sondern ein Thread pro Connection + blocking IO.

    Skaliert wunderbar bis zu etlichen hundert Clients pro Prozess, und man spart sich enorm viel Aufwand bei der Implementierung.
    (Erfahrung mit etlichen tausend Clients - die mit 64 bittigen Systemen kein grundsätzliches Problem darstellen - konnte ich noch keine sammeln. Würde mich aber nicht wundern, wenn das auch noch halbwegs OK funktioniert.)



  • AFAIK ist Boost Asio "tot". Letztes Release vor fast einem Jahr und der Autor meldet sich schon seit vielen vielen Monaten nicht mehr in der Mailinglist.



  • Also die Boost Version 1.48 ist noch kein Jahr alt, und da gab es doch etliche Änderungen in der ASIO:
    http://www.boost.org/users/history/version_1_48_0.html

    Und im TRAC tut sich auch noch was, z.B.:
    https://svn.boost.org/trac/boost/ticket/6310

    Sieht für mich nicht tot aus.

    Ich will die ASIO auch hier nicht schlechter darstellen als sie ist. Ich meine nur, dass sie lange nicht so einfach ist, wie manche meinen 🙂


Anmelden zum Antworten