2010-11-24 9 views
1

Ich habe einen fprintf Anruf, der für unangemessene 10 Sekunden blockiert, wenn das System IO beschäftigt ist, aber immer noch viel CPU hat. Ich weder setvbuf des zugrunde liegenden Stream noch öffnete die zugrunde liegende FD mit O_DIRECT. Dies bedeutet, dass der Stream sowohl den Status-Stream als auch den System-Cache hat.Wie kann fprintf in Linux blockieren?

Ich kann nicht sagen, wie ein fprintf Anruf für so lange Zeit blockiert werden kann. Für den schlechtesten Fall, in dem der Strompuffer des zugrundeliegenden Streams voll ist, denke ich, dass die libc einfach write(2) aufruft, um den Pufferinhalt auf Platte zu schreiben. Aber nach meinem Wissen wird write(2) auf einem FD, das nicht mit O_DIRECT geöffnet ist, nicht auf die Plattenübertragung warten, d. H. Es ist asynchron zu Platten-IO. Die einzige zeitraubende Arbeit, die ich mir vorstellen kann, ist der Kernel, der den Cache für die geschriebenen Daten reserviert, aber das scheint keine 10-Sekunden-Arbeit zu sein, selbst wenn das System zu wenig Speicher hat. Tatsächlich verfügt das System über zehn MB freien Arbeitsspeicher und mehrere GB Arbeitsspeicher im Cache.

Gibt es einen Ratschlag?

Danke.

+0

Wie groß ist die Größe der übertragenen Daten? – ascobol

+0

Ungefähr 100 Bytes habe ich gerade Log geschrieben. – Utoah

+0

nicht mit o_direct zu öffnen bedeutet nicht, dass es schnell fertig sein würde .. es kann zum Beispiel mit cache/lock contention handeln. –

Antwort

0

Haben Sie Ihren Code auf mehr als einer Maschine ausgeführt? Wenn ja, ist das Verhalten das gleiche?

Wenn nicht, nach Festplattenzugriffsfehlern in Ihrem Systemprotokoll suchen, sobald ich ein ähnliches Problem hatte und der Grund war eine fehlerhafte Festplatte.

+0

Eigentlich habe ich Dutzende von Servern von diesem Problem leiden. – Utoah

0

Ein Schreibaufruf ist nicht asynchron, dh der Systemaufruf muss vom Kernel zurückgegeben werden. Natürlich stellt dieser Systemaufruf hauptsächlich Daten in eine E/A-Warteschlange, die später die eigentliche Übertragung durchführen. Ich nehme jedoch an, dass diese I/O-Warteschlange für einige Zeit nicht verfügbar sein kann.

Dies ist unabhängig vom Medium, an das Sie schreiben, solange es ein Block-Gerät ist. Ich habe ein Programm, das Streams von JPEG-Bildern auf eine SD-Karte schreibt. Dieses Programm wird wegen der auf der Festplatte stattfindenden Vorgänge hängen bleiben.

Wenn dies jedoch ein Problem mit der Blockierung des Schreibaufrufs für zehn Sekunden ist, können Sie versuchen, Ihr Programm zu straffen. Ich weiß nicht, wie oder ob sie das Verhalten stören versuchen Sie

strace -T -e trace=write progname 

zu beobachten Wenn Sie Ihre Log-Aktivität überwachen möchten, kann Sie Ihre Log-Schreibvorgang in einem Rohr oder einer benannten Pipe umleiten können, setzen ein Prozess, der im Wesentlichen von dieser Pipe liest und in Ihre Logdatei schreibt und strace.

+0

Haben Sie endlich den Grund dafür gefunden, dass Ihr Programm, das SD-Karten schreibt, wegen Festplattenoperationen stecken bleibt? Ich denke, dieser Grund wäre hilfreich. Übrigens denke ich, dass jedes Blockgerät (keine Partition) eine eigene Anforderungswarteschlange hat, so dass es unwahrscheinlich ist, dass zwei Threads in Warteschlangen verschiedener Geräte konkurrieren. – Utoah

+0

Ja, jeder hat seine eigene Anforderungswarteschlange, aber wird am Ende nicht jede Warteschlange durch einen einzelnen Scheduler bearbeitet? Es war auf einem Kernel 2.6.24. Möglicherweise haben sich die Dinge seitdem geändert. – shodanex

+0

Und selbst wenn ich falsch liege, können Sie versuchen, tlog auf einem tmpfs, und sehen, ob Ihr Problem verschwindet – shodanex

0

Sie haben gesagt, Sie haben setvbuf() nicht im Stream aufgerufen, aber welche Art von Pufferung verwendet der Stream? Sofern der von Ihnen verwendete Stream stderr (oder manchmal stdout) ist, wird er standardmäßig blockweise gepuffert, was bedeutet, dass keine Schreibvorgänge stattfinden, bis der Puffer voll ist (normalerweise 4096 Byte oder mehr). Je nachdem, wie häufig Sie Protokolle schreiben, kann dies zu einer Verzögerung von 10 Sekunden führen.

Also ich würde versuchen: setvbuf(my_stream, NULL, _IONBF, 0);

EDIT: ... Oder es ist möglich, dass ich das Wort völlig falsch interpretiert "blockiert". Ich gehe sowieso, nur für den Fall.

0

Wenn Ihr Prozess große Datenmengen auf die Festplatte schreibt, werden viele schmutzige Seiten im Seitencache erstellt, und write() wird Ihren Prozess schließlich zwingen, für einige dieser Seiten einen synchronen Rückschreibvorgang auszuführen.In dieser Situation kehrt der Kernel nicht zu Ihrem Prozess zurück, bis er eine vernünftige Menge an Daten auf die Festplatte geschrieben hat (10 Sekunden klingen immer noch etwas hoch).

+0

Hilfreich. Es ist ein ausgelasteter Server und schreibt viel Protokoll auf Festplatte. Wenn ein anderes E/A-gebundenes Programm auf demselben Server gestartet wird, hat es wahrscheinlich einen 10-Sekunden-Schreibvorgang. Ich werde das überprüfen. – Utoah

+0

@Utoah: Writeback ist durch sysctls in '/ proc/sys/vm /' einstellbar. Sie könnten versuchen, 'dirty_expire_centisecs' zu verringern und' dirty_ratio' zu erhöhen, so dass mehr von dem Rückschreiben im Hintergrund ausgeführt wird. – caf