Datei-I/O beschleunigen: mmap() vs. read()

Lesezeit: 7 Minuten

Benutzeravatar von Bill N
Bill N.

Ich habe eine Linux-Anwendung, die 150-200 Dateien (4-10 GB) parallel liest. Jede Datei wird der Reihe nach in kleinen Blöcken unterschiedlicher Größe gelesen, typischerweise jeweils weniger als 2K.

Ich muss derzeit eine Lesegeschwindigkeit von über 200 MB/s, kombiniert aus dem Satz von Dateien, aufrechterhalten. Die Festplatten kommen damit gut zurecht. Es gibt eine prognostizierte Anforderung von über 1 GB/s (was derzeit außerhalb der Reichweite der Festplatte liegt).

Wir haben zwei verschiedene Lesesysteme implementiert, die beide stark genutzt werden posix_advise: zuerst ist ein mmaped read, in dem wir den gesamten Datensatz abbilden und bei Bedarf lesen. Der zweite ist ein read()/seek() basierte System.

Beide funktionieren gut, aber nur für die moderaten Fälle, die read() -Methode verwaltet unseren gesamten Dateicache viel besser und kann gut mit 100 GB an Dateien umgehen, ist aber stark ratenbegrenzt, mmap ist in der Lage, Daten vorab zwischenzuspeichern, wodurch die dauerhafte Datenrate von über 200 MB/s einfach aufrechtzuerhalten ist, kann jedoch nicht mit großen Gesamtdatenmengen umgehen.

Daher kommt meine Frage dazu:

Eine Kanne read() type file i/o darüber hinaus weiter optimiert werden posix_advise Anrufe unter Linux, oder nachdem wir den Festplattenplaner, VMM und posix_advise-Aufrufe optimiert haben, ist das so gut, wie wir erwarten können?

B: Gibt es systematische Möglichkeiten für mmap, mit sehr großen gemappten Daten besser umzugehen?

Mmap-vs-reading-blocks ist ein ähnliches Problem wie das, an dem ich arbeite, und bot zusammen mit den Diskussionen in mmap-vs-read einen guten Ausgangspunkt für dieses Problem.

  • Dies ist ein gutes Beispiel dafür, wie optimierungs-/leistungsbezogene Fragen sein sollten. Es zeigt Forschungsergebnisse, enthält gemessene Daten und hat klar definierte Ziele. Nach einer Weile wird man müde von „keine Ahnung wie schnell es istwollen Schneller“. Schade, dass ich nur +1 geben kann 🙂

    – R.Martinho Fernandes

    8. November 2011 um 21:17 Uhr


  • Gibt es eine Chance, Ihre sich drehenden Festplatten durch SSDs zu ersetzen? Das würde die Kopfsuchstrafen vermeiden, die Sie wahrscheinlich zahlen müssen, wenn Sie von einer Datei zur anderen wechseln …

    – Jeremy Friesner

    8. November 2011 um 21:50 Uhr

  • War es nicht der Sinn des Distributed Computing (Map-Reduce), solche Probleme zu lösen (Hadoop verwenden)?

    – Ramadheer Singh

    8. November 2011 um 22:11 Uhr

  • Es ist nicht genau klar, welches Problem Sie haben, wenn Sie den gesamten Datensatz mit abbilden mmap(). mmap() sollte kein Problem haben, Hunderte von GBs zuzuordnen (vorausgesetzt, Sie kompilieren sowieso eine ausführbare 64-Bit-Datei).

    – Café

    9. November 2011 um 0:39 Uhr

Benutzeravatar von Matt Joiner
Matt Tischler

Liest zurück auf was? Was ist der endgültige Bestimmungsort dieser Daten?

Da es so klingt, als wären Sie vollständig IO-gebunden, mmap und read sollte keinen unterschied machen. Der interessante Teil ist, wie Sie die Daten zu Ihrem Empfänger bekommen.

Angenommen, Sie geben diese Daten in eine Pipe, empfehle ich Ihnen, einfach den Inhalt jeder Datei vollständig in die Pipe zu kopieren. Um dies mit Zero-Copy zu tun, versuchen Sie die splice Systemaufruf. Sie können auch versuchen, die Datei manuell zu kopieren oder eine Instanz von zu forken cat oder ein anderes Tool, das mit der aktuellen Datei als stdin und der Pipe als stdout stark puffern kann.

if (pid = fork()) {
    waitpid(pid, ...);
} else {
    dup2(dest, 1);
    dup2(source, 0);
    execlp("cat", "cat");
}

Update0

Wenn Ihre Verarbeitung dateiunabhängig ist und keinen wahlfreien Zugriff erfordert, möchten Sie eine Pipeline mit den oben beschriebenen Optionen erstellen. Ihr Verarbeitungsschritt sollte Daten von stdin oder einer Pipe akzeptieren.

Um deine konkreteren Fragen zu beantworten:

A: Kann die Datei-I/O vom Typ read() über die posix_advise-Aufrufe unter Linux hinaus optimiert werden, oder ist das Optimieren des Disk-Schedulers, des VMM und der posix_advise-Aufrufe so gut, wie wir erwarten können?

Das ist das Beste, wenn es darum geht, dem Kernel zu sagen, was er vom Userspace aus tun soll. Der Rest liegt bei Ihnen: Puffern, Threading usw., aber es ist gefährlich und wahrscheinlich unproduktiv. Ich würde einfach die Dateien in eine Pipe spleißen.

B: Gibt es systematische Möglichkeiten für mmap, mit sehr großen gemappten Daten besser umzugehen?

Ja. Das folgenden Optionen kann Ihnen großartige Leistungsvorteile bringen (und kann es wert machen, mmap über das Lesen zu verwenden, mit Tests):

  • MAP_HUGETLB

    Ordnen Sie das Mapping mit “riesigen Seiten” zu.

    Dadurch wird der Paging-Overhead im Kernel reduziert, was großartig ist, wenn Sie Gigabyte-große Dateien zuordnen.

  • MAP_NORESERVE

    Reservieren Sie keinen Auslagerungsbereich für diese Zuordnung. Wenn Auslagerungsspeicher reserviert ist, hat man die Garantie, dass es möglich ist, das Mapping zu modifizieren. Wenn der Auslagerungsspeicher nicht reserviert ist, kann es beim Schreiben zu SIGSEGV kommen, wenn kein physischer Speicher verfügbar ist.

    Dadurch wird verhindert, dass Ihnen der Arbeitsspeicher ausgeht, während Ihre Implementierung einfach bleibt, wenn Sie tatsächlich nicht über genügend physischen Arbeitsspeicher + Swap für das gesamte Mapping verfügen.**

  • MAP_POPULATE

    Füllen Sie (voreingestellte) Seitentabellen für ein Mapping. Bei einer Dateizuordnung bewirkt dies ein Vorauslesen der Datei. Spätere Zugriffe auf das Mapping werden nicht durch Seitenfehler blockiert.

    Dies kann Ihnen bei ausreichenden Hardwareressourcen und bei bestelltem Prefetching und Faulheit Geschwindigkeitssteigerungen bringen. Ich vermute, dass dieses Flag redundant ist, das VFS macht das wahrscheinlich standardmäßig besser.

  • Das Ziel ist schließlich ein Netzwerkgerät, obwohl es vorher verarbeitet und neu geordnet werden muss.

    – Bill N.

    8. November 2011 um 21:47 Uhr

  • Ich denke nicht MAP_HUGETLB ist für normale dateigestützte Zuordnungen zulässig. Ich denke, es ist nur für anonyme Zuordnungen erlaubt. (Oder für Dateien, die in erstellt wurden /dev/hugepagesich schätze, um einen gemeinsamen Speicher von riesigen Seiten zwischen Prozessen zuzulassen.) Ich glaube nicht MAP_NORESERVE ist sinnvoll für gemeinsam genutzte dateigestützte Mappings. Es ist sinnvoll für private Zuordnungen, da Schreibvorgänge in diese Zuordnungen den Dateiinhalt nicht beeinflussen. Aber gemeinsam genutzte Zuordnungen werden bereits durch die Datei auf der Festplatte gesichert, nicht durch den Auslagerungsbereich.

    – Peter Cordes

    8. Mai 2016 um 20:28 Uhr

Vielleicht mit der lesen Sie weiter Systemaufruf könnte helfen, wenn Ihr Programm die Dateifragmente, die es lesen möchte, im Voraus vorhersagen kann (aber das ist nur eine Vermutung, ich könnte mich irren).

Und ich denke, Sie sollten Ihre Anwendung und vielleicht sogar Ihre Algorithmen darauf abstimmen, Daten in Blöcken zu lesen, die viel größer als ein paar Kilobyte sind. Kann es nicht stattdessen ein halbes Megabyte sein?

  • Gute Idee. Allerdings, und ich könnte mich irren, read(), sagen wir, ruft do_generic_read() auf, was nach meinem besten Wissen automatisch ein Readahead durchführt. Vielleicht könnte eine Feinabstimmung des Read-Ahead-Fensters oder etwas anderes helfen, aber wahrscheinlich wird dies bereits im Hintergrund erledigt.

    – Gnometorule

    8. November 2011 um 22:20 Uhr

  • Und ja, mehr zu verlangen. Dies löst beispielsweise den automatischen Read-Ahead-Algorithmus aus.

    – Gnometorule

    8. November 2011 um 22:21 Uhr

Benutzeravatar von Tobias Schlegel
Tobias Schlegel

Das Problem scheint hier nicht zu sein, welche API verwendet wird. Es spielt keine Rolle, ob Sie mmap() oder read() verwenden, die Disc muss immer noch zum angegebenen Punkt suchen und die Daten lesen (obwohl das Betriebssystem hilft, den Zugriff zu optimieren).

mmap() hat Vorteile gegenüber read(), wenn Sie sehr kleine Chunks (ein paar Bytes) lesen, weil Sie das Betriebssystem nicht für jeden Chunk aufrufen müssen, was sehr langsam wird.

Ich würde auch raten, wie Basile, mehr als 2 KB hintereinander zu lesen, damit die Disc nicht so oft suchen muss.

  • Nun, mit mmap wird das Lesen von einer Seite, die nicht zugeordnet ist, zu einer Falle für das Betriebssystem führen, das dann die Daten von der Festplatte liest, also ist es nicht billiger als ein Aufruf von read(). Natürlich ist das wiederholte Lesen derselben Seite mit mmap schnell.

    – janeb

    8. November 2011 um 21:37 Uhr

  • Stimmt, auch das Lesen zum Füllen der mmap ist aus Sicht der Anwendung asynchron, so dass mein Datei-Thread im Gegensatz zu einem Aufruf von readahed() nicht blockiert, es sei denn, ich habe die zwischengespeicherte Seite erschöpft und der Kernel befindet sich im IO-Wartemodus.

    – Bill N.

    8. November 2011 um 21:49 Uhr

1404530cookie-checkDatei-I/O beschleunigen: mmap() vs. read()

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy