Lesen einer riesigen Datei in einen C ++ Vektor in Ubuntu (Linux OS)

9

In meinem C ++ - Programm unter Linux (Ubuntu 14.4) muss ich eine 90-GB-Datei lesen, die komplett in einem C ++ - Vektor gepuffert ist, und ich habe nur 125 GB Speicher.

Wenn ich die Datei Chunk für Chunk lese, führt dies zu einer Erhöhung der zwischengespeicherten Mem-Nutzung in Linux, die mehr als 50% der 128 GB Speicherkapazität ausmacht. Dann wird der freie Speicher leicht unter 50 GB.

%Vor%

Swap: 255 0 255

Also habe ich festgestellt, dass der freie Speicher dann zu Null wird, und der Dateilesevorgang fast gestoppt wurde, und ich manuell ausführen muss:

%Vor%

löscht den zwischengespeicherten Speicher, so dass der Dateilesevorgang fortgesetzt wird. Ich verstehe, Cache-Speicher ist, um eine Datei erneut zu lesen. Meine Frage ist, wie kann ich vermeiden, den Befehl zum Löschen des Cache manuell auszuführen, um sicherzustellen, dass der Dateilesevorgang erfolgreich abgeschlossen wird?

    
Ren Chen 07.07.2017, 09:00
quelle

1 Antwort

3

Da Sie die Daten einfach streamen und nie wieder lesen, macht Ihnen der Seitencache überhaupt nichts. Angesichts der Menge an Daten, die Sie durch den Seitencache schieben, und des Speicherdrucks durch Ihre Anwendung werden ansonsten wahrscheinlich nützliche Daten aus dem Seitencache gelöscht, und Ihre Systemleistung leidet darunter .

Verwenden Sie den Cache also nicht, wenn Sie Ihre Daten lesen. Verwenden Sie direkte IO. Pro die Linux open() man-Seite :

  

O_DIRECT (seit Linux 2.4.10)

     

Versuchen Sie Cache-Effekte der I / O zu und von diesem zu minimieren                 Datei. Im Allgemeinen wird dies die Leistung beeinträchtigen, aber es ist                 nützlich in besonderen Situationen, z. B. wenn Anwendungen dies tun                 ihr eigenes Caching. Datei-I / O erfolgt direkt zu / von Benutzer-                 Leerzeichen. Die O_DIRECT -Flagge macht sich Mühe                 Daten synchron zu übertragen, aber nicht geben                 Garantien des O_SYNC kennzeichnen diese Daten und notwendigen Metadaten                 werden übertragen. Um synchrone E / A zu garantieren, muss O_SYNC sein                 zusätzlich zu O_DIRECT verwendet. Weitere Informationen finden Sie weiter unten                 Diskussion.

     

...

     

HINWEISE

     

...

     

O_DIRECT

     

Das O_DIRECT-Flag kann Ausrichtungseinschränkungen für die Länge und aufweisen          Adresse von User-Space-Puffern und der Datei-Offset von I / Os. In Linux          Ausrichtungseinschränkungen variieren je nach Dateisystem und Kernelversion und          könnte ganz fehlen. Allerdings gibt es derzeit keine          Dateisystemunabhängige Schnittstelle für eine Anwendung, um diese zu finden          Einschränkungen für eine bestimmte Datei oder ein Dateisystem. Einige Dateisysteme          Dazu stellen sie eigene Schnittstellen zur Verfügung, z          XFS_IOC_DIOINFO-Operation in xfsctl (3).

     

Übertragen Sie unter Linux 2.4 die Größe und die Ausrichtung des Benutzerpuffers          und der Dateioffset muss alle ein Vielfaches der logischen Blockgröße sein          des Dateisystems. Seit Linux 2.6.0, Ausrichtung auf den logischen Block          Die Größe des zugrunde liegenden Speichers (typischerweise 512 Bytes) reicht aus. Das          Die logische Blockgröße kann mit ioctl (2) BLKSSZGET bestimmt werden          Operation oder von der Shell mit dem Befehl:

%Vor%      

...

Da Sie die Daten nicht immer wieder lesen, verbessert Direct IO die Leistung wahrscheinlich etwas, da die Daten direkt von der Festplatte in den Speicher Ihrer Anwendung anstatt von der Festplatte auf die Seite gelangen Cache und dann in den Speicher Ihrer Anwendung.

Verwenden Sie Low-Level-C-style-E / A mit open() / read() / close() und öffnen Sie die Datei mit dem O_DIRECT -Flag:

%Vor%

Dies führt dazu, dass die Daten direkt in den Speicher der Anwendung gelesen werden, ohne dass sie im Seitencache des Systems zwischengespeichert werden.

Sie müssen read() mit ausgerichteten Speicher verwenden, also benötigen Sie etwas, um die Daten tatsächlich zu lesen:

%Vor%

posix_memalign() ist eine POSIX-Standardfunktion , die einen Zeiger auf den Speicher als ausgerichtet zurückgibt angefordert. Seiten-ausgerichtete Puffer sind normalerweise mehr als ausreichend, aber die Ausrichtung auf eine riesige Seitengröße (2MiB auf x86-64) weist auf den gewünschten Kernel hin transparente hugepages für diese Zuweisung, um den Zugriff auf Ihren Puffer effizienter zu gestalten, wenn Sie ihn später lesen.

%Vor%

Ohne Ihren Code kann ich nicht sagen, wie ich die Daten von buffer in Ihre std::vector bringen soll, aber es sollte nicht schwer sein. Es gibt wahrscheinlich Möglichkeiten, den Low-Level-Dateideskriptor im C-Stil mit einem C ++ - Stream eines beliebigen Typs zu umhüllen und diesen Stream so zu konfigurieren, dass er Speicher verwendet, der ordnungsgemäß für Direct IO ausgerichtet ist.

Wenn Sie den Unterschied sehen möchten, versuchen Sie Folgendes:

%Vor%

Zeit, dass. Sehen Sie sich dann die Datenmenge im Seitencache an.

Dann tu das:

%Vor%

Überprüfen Sie danach die Datenmenge im Seitencache ...

Sie können mit verschiedenen Blockgrößen experimentieren, um zu sehen, was auf Ihrer Hardware und Ihrem Dateisystem am besten funktioniert.

Beachten Sie jedoch, dass direkte IO sehr implementierungsabhängig ist. Die Anforderungen für die direkte E / A-Verarbeitung können zwischen verschiedenen Dateisystemen erheblich variieren. Je nach E / A-Muster und spezifischer Hardware kann die Leistung stark variieren. Die meiste Zeit sind diese Abhängigkeiten nicht wert, aber die einzige einfache Anwendung, bei der es sich normalerweise lohnt, ist das Streamen einer großen Datei, ohne dass ein Teil der Daten erneut gelesen / neu geschrieben werden muss.

    
Andrew Henle 07.07.2017 18:42
quelle

Tags und Links