Frage

Ich arbeite an einem eingebetteten Linux -Projekt, das einen ARM9 in einen Hardware -Video -Encoder -Chip übergibt und das Video auf SD -Karte oder USB -Stick schreibt. Die Softwarearchitektur umfasst einen Kernel -Treiber, der Daten in einen Pufferpool liest, und eine Userland -App, die die Daten in eine Datei auf dem montierten abnehmbaren Gerät schreibt.

Ich stelle fest, dass ich über einer bestimmten Datenrate (ca. 750 kByte/Sek.) Ich beginne, dass die Userland-Video-Schreib-App-App möglicherweise eine halbe Sekunde lang abbindet, etwa alle 5 Sekunden. Dies reicht aus, um den Kernel -Treiber zu veranlassen, die Puffer zu verlassen - und selbst wenn ich die Anzahl der Puffer erhöhen könnte, müssen die Videodaten (idealerweise innerhalb von 40 ms) mit anderen Dingen synchronisiert werden, die in Echtzeit vor sich gehen. Zwischen diesen 5 Sekunden "Verzögerungsspitzen" werden die Schreibungen innerhalb von 40 ms gut abgeschlossen (was die App betrifft - ich schätze, dass sie vom Betriebssystem gepuffert sind).

Ich denke, diese Verzögerungsspitze hat mit der Art und Weise zu tun, wie Linux Daten auf die Festplatte spülen - ich stelle fest, dass PDFLUSH so konzipiert ist, dass sie alle 5s aufwachen. Mein Verständnis ist, dass dies das Schreiben ist. Sobald der Stand über die Userland -App übertrifft, kann sie den Rückstand der Puffer schnell bedienen und schreiben (das nicht überflutet).

Ich denke, das Gerät, mit dem ich schreibe, hat einen angemessenen ultimativen Durchsatz: Kopieren einer 15 -MB -Datei aus einem Speicher -FS und Warten auf die Synchronisierung (und das Licht des USB -Sticks, um das Blinken aufzuhören), gab mir eine Schreibgeschwindigkeit von ca. 2,7MBytes/Sek.

Ich suche zwei Arten von Hinweisen:

  1. Wie kann ich das bürgerliche Schreiben davon abhalten, meine App zum Stoppen zu bringen - möglicherweise Prioritäten, Echtzeit -Patches oder den Dateisystemcode zu verarbeiten, um kontinuierlich zu schreiben, anstatt ergriffen zu schreiben?

  2. Wie kann ich meine App (en) aufmerksam machen, was mit dem Dateisystem in Bezug auf Schreibstau und Durchsatz zur Karte/Stick vorgeht? Ich habe die Möglichkeit, das Video -Bitrate in der Hardware -Codec im laufenden Fliegen zu ändern, was viel besser wäre als Frames zu fallen oder eine künstliche Kappe auf maximal zulässige Bitrate auferlegt.

Einige weitere Informationen: Dies ist ein 200-MHz-ARM9, der derzeit einen in Montavista 2.6.10 basierten Kernel betreibt.

Aktualisierung:

  • Durch die Montage der Dateisystem -Synchronisation ist der Durchsatz viel zu schlecht.
  • Das abnehmbare Medium ist fett/fat32 formatiert und muss als Zweck des Designs sein, dass das Medium an einen Windows -PC angeschlossen und gelesen werden kann.
  • Regelmäßig aufrufen sync () oder fsync () sagen, jede Sekunde verursacht regelmäßige Stände und inakzeptabel schlechter Durchsatz
  • Ich benutze write () und open (o_wronly | o_creat | o_trunc) anstatt fopen () usw.
  • Ich kann online nichts über die genannten "Linux Echtzeit -Dateisysteme" finden. Links?

Ich hoffe das macht Sinn. Erste eingebettete Linux -Frage auf Stackoverflow? :)

War es hilfreich?

Lösung

Für die Aufzeichnung stellte sich heraus, dass es zwei Hauptaspekte gab, die das Problem in allen extremsten Fällen anscheinend beseitigt haben. Dieses System ist noch in der Entwicklung und wurde noch nicht gründlich gefoltert, funktioniert aber ziemlich gut (berühren Sie Holz).

Der große Sieg kam davon, die Userland Writer App Multi-Threadede zu machen. Es sind die Anrufe zu schreiben (), die manchmal blockieren: andere Prozesse und Threads werden noch ausgeführt. Solange ich einen Thread -Thread -Treiber und die Aktualisierung von Frame -Zählungen und anderen Daten zum Sychronisieren mit anderen Apps, die ausgeführt werden, aktualisiert habe, können die Daten einige Sekunden später gepuffert und ausgeschrieben werden, ohne die Fristen zu brechen. Ich habe zuerst einen einfachen Ping-Pong-Doppelpuffer ausprobiert, aber das war nicht genug; Kleine Puffer wären überwältigt und große verursacht nur größere Pausen, während das Dateisystem die Schreibvorgänge verdaute. Ein Pool von 10 1 MB Puffern zwischen Threads funktioniert jetzt gut.

Der andere Aspekt besteht darin, den ultimativen Schreibdurchsatz für physische Medien im Auge zu behalten. Dafür behalte ich das Status schmutzig: Von /proc /meminfo gemeldet. Ich habe einen rauen und fertigen Code, um den Encoder zu drosseln, wenn es schmutzig ist: Anstiege über eine bestimmte Schwelle, scheint vage zu funktionieren. Weitere Tests und Stimmen benötigen später. Glücklicherweise habe ich viel Ram (128 m), um mir ein paar Sekunden Zeit zu geben, um zu sehen, wie sich mein Rückstand aufgebaut und sanft nach unten sucht.

Ich werde versuchen, mich daran zu erinnern, diese Antwort zu aktualisieren, wenn ich finde, dass ich etwas anderes tun muss, um mit diesem Problem umzugehen. Vielen Dank an die anderen Antworten.

Andere Tipps

Ich werde einige Vorschläge wegwerfen, Ratschläge sind billig.

  • Stellen Sie sicher fopen, fread, fwrite Verwenden Sie die Funktionen auf niedrigerer Ebene open, read, write.
  • Pass die O_SYNC Wenn Sie die Datei öffnen, werden jede Schreiboperation bis zum Schreiben auf der Festplatte blockiert, wodurch das Bursty -Verhalten Ihrer Schreibvorgänge entfernt wird ... wobei die Kosten jedes Schreibens langsamer sind.
  • Wenn Sie von einem Gerät von Lesevorgängen/IOCTLs ausführen, um einen Teil von Videodaten zu holen copy_to_user Anrufe beim Übertragen von Videodatenpuffern vom Kernel -Speicherplatz auf den Benutzerraum.
  • Möglicherweise müssen Sie validieren, dass Ihr USB -Flash -Gerät schnell genug mit anhaltenden Überweisungen ist, um die Daten zu schreiben.

Nur ein paar Gedanken, hoffe das hilft.

Hier Es gibt einige Informationen über das Tuning von PDflush für Schreibvorgänge.

Klingt so, als würden Sie nach Linux -Echtzeit -Dateisystemen suchen. Achten Sie darauf, dass Sie darauf suchen können.

XFS hat eine Echtzeitoption, obwohl ich nicht damit gespielt habe.

Mit HDParm können Sie das Caching insgesamt ausschalten.

Das Abstimmen der Dateisystemoptionen (deaktivieren Sie alle zusätzlichen nicht benötigten Dateiattribute) können das reduzieren, was Sie zum Spülen benötigen, wodurch das Spülen beschleunigt wird. Ich bezweifle jedoch, dass das sehr helfen würde.

Mein Vorschlag wäre jedoch, den Stick als Dateisystem überhaupt zu verwenden und ihn stattdessen als Rohgerät zu verwenden. Sachen Daten dazu wie Sie "DD" verwenden würden. Dann lesen Sie diese Rohdaten an anderer Stelle und schreiben Sie sie nach dem Backen aus.

Natürlich weiß ich nicht, ob das eine Option für Sie ist.

Wenn Sie eine Debugging -Hilfe haben, können Sie Strace nutzen, um zu sehen, welche Operationen Zeit in Anspruch nehmen. Es könnte eine überraschende Sache mit dem Fat/Fat32 geben.

Schreiben Sie in eine einzelne Datei oder in mehreren Dateien?

Sie können einen Leser -Thread erstellen, der einen Pool von Videopuffer beibehält, das bereit ist, in einer Warteschlange geschrieben zu sein. Wenn ein Rahmen empfangen wird, wird er der Warteschlange hinzugefügt und der Schreibfaden signalisiert

Gemeinsame Daten

empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore

Thread lesen:

buf=get_buffer()
bufer_to_write = buf_dequeue(empty_buffer_queue)
memcpy(bufer_to_write, buf)
buf_enqueue(bufer_to_write, ready_buffer_queue)
sem_post(video_data_ready_semaphore)

Thread schreiben

sem_wait(vido_data_ready_semaphore)
bufer_to_write = buf_dequeue(ready_buffer_queue)
write_buffer
buf_enqueue(bufer_to_write, empty_buffer_queue)

Wenn Ihr Schreibfaden blockiert ist, das auf den Kernel wartet, kann dies funktionieren. Wenn Sie jedoch im Kerne -Raum blockiert sind, gibt es nicht viel, was Sie tun können, außer nach einem neueren Kernel als Ihren 2.6.10 zu suchen

Ohne mehr über Ihre besonderen Umstände zu wissen, kann ich nur die folgenden Vermutungen angeben:

Versuchen Sie, FSYNC ()/sync () zu verwenden, um den Kernel häufiger zum Speichergerät zu spülen. Es klingt nach dem Kernel, der alle Ihre Schreibvorgänge pufft und dann den Bus verbindet oder Ihr System auf andere Weise beschränkt, während Sie das tatsächliche Schreiben durchführen. Mit sorgfältigen Aufrufen von FSYNC () können Sie versuchen, Schreibvorgänge über den Systembus auf feinkörnigere Weise zu planen.

Es könnte sinnvoll sein, die Anwendung so zu strukturieren, dass die Codierung/Erfassung (Sie haben die Videoaufnahme nicht erwähnt, also mache ich hier eine Annahme - Sie möchten vielleicht weitere Informationen hinzufügen) Task in ihrem eigenen Thread und in ihrem eigenen Thread und hier ausführen Puffert seine Ausgabe in Userland - dann kann ein zweiter Thread das Schreiben auf das Gerät verarbeiten. Dadurch erhalten Sie einen Glättungspuffer, damit der Encoder seine Schreibvorgänge immer beenden kann, ohne zu blockieren.

Eine Sache, die misstrauisch klingt, ist, dass Sie dieses Problem nur mit einer bestimmten Datenrate sehen. Wenn dies wirklich ein Pufferproblem wäre, würde ich erwarten Ausgabe.

In jedem Fall können sich weitere Informationen als nützlich erweisen. Was ist die Architektur Ihres Systems? (In sehr allgemeiner Hinsicht.)

Angesichts der zusätzlichen Informationen, die Sie zur Verfügung gestellt haben, klingt es so, als ob der Durchsatz des Geräts für kleine Schreibvorgänge und häufige Flushs eher schlecht ist. Wenn Sie sicher sind, dass Sie für größere Schreibvorgänge einen ausreichenden Durchsatz erhalten können (und ich bin mir nicht sicher, ob dies der Fall ist, aber das Dateisystem kann etwas Dummes tun, wie das Fett nach jedem Schreiben), dann haben Sie einen Codierungs -Thread -Rohrleitungsdaten zu einem Schreib Thread mit ausreichender Pufferung im Schreibfaden, um Stände zu vermeiden. Ich habe in der Vergangenheit gemeinsam genutzte Speicherringpuffer verwendet, um diese Art von Schema zu implementieren, aber jeder IPC -Mechanismus, der es dem Autor ermöglicht, in den E/A -Prozess zu schreiben, ohne zu stopfen, es sei denn, der Puffer ist voll, sollte den Trick ausführen.

Eine nützliche Linux -Funktion und Alternative zu Sync oder Fsync ist sync_file_range. Auf diese Weise können Sie Daten für das Schreiben planen, ohne darauf zu warten, dass das In-Kernel-Puffer-System dazu kommt.

Um lange Pausen zu vermeiden, stellen Sie sicher, dass Ihre IO -Warteschlange (zum Beispiel:/sys/block/hda/queue/nr_requests) groß genug ist. In dieser Warteschlange gehen die Daten zwischen dem Speicher und der Ankunft auf der Festplatte.

Beachten Sie, dass sync_file_range nicht tragbar ist und nur in Kernels 2.6.17 und später erhältlich ist.

Mir wurde gesagt, dass MMC- und SD -Karten "innerhalb von 0 bis 8 Bytes antworten müssen".

Mit der Spezifikation können diese Karten jedoch mit "geschäftig" antworten, bis sie den Vorgang beendet haben, und anscheinend gibt es keine Begrenzung, wie lange eine Karte behaupten kann, beschäftigt zu sein (bitte sagen Sie mir, ob es ein solches Limit gibt).

Ich sehe, dass einige kostengünstige Flash-Chips wie das M25P80 eine garantierte "maximale Einsektor-Löschzeit" von 3 Sekunden haben, obwohl es normalerweise "nur" 0,6 Sekunden erfordert.

Diese 0,6 Sekunden klingen verdächtig ähnlich wie bei Ihrem "Stalling für vielleicht eine halbe Sekunde".

Ich vermute, dass der Kompromiss zwischen billigen, langsamen Flash -Chips und teuren, schnellen Flash -Chips etwas mit der großen Variation der USB -Flash -Laufwerksergebnisse zu tun hat:

Ich habe Gerüchte gehört, dass jedes Mal, wenn ein Flash-Sektor gelöscht und dann neu programmiert wird, etwas länger dauert als beim letzten Mal.

Wenn Sie also eine zeitkritische Anwendung haben, müssen Sie möglicherweise (a) Ihre SD-Karten und USB-Sticks testen, um sicherzustellen oder ersetzen Sie diese Speichergeräte präventiv.

Nun offensichtlich, haben Sie zuerst versucht, die Datei explizit zu sagen, dass sie spülen sollen? Ich denke auch, dass es vielleicht etwas IOCTL geben kann, mit dem Sie es tun können, aber ich habe ehrlich gesagt nicht viel C/POSIX -Dateiprogrammierung gemacht.

Wenn Sie sehen, dass Sie sich auf einem Linux -Kernel befinden, sollten Sie den Kernel an etwas einstellen und wieder aufbauen, das Ihren Bedürfnissen besser entspricht, z. Viel häufiger, aber dann auch kleinere Flushs zum dauerhaften Speicher.


Ein kurzer Check in meine Mannseiten findet dies:

SYNC(2)                    Linux Programmer’s Manual                   SYNC(2)

NAME
       sync - commit buffer cache to disk

SYNOPSIS
       #include <unistd.h>

       void sync(void);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500

DESCRIPTION
       sync() first commits inodes to buffers, and then buffers to disk.

ERRORS
       This function is always successful.

Wenn Sie Ihr eigenes Flush () -Rog für mich richtig erstellen - möchten Sie die Kontrolle haben, lassen Sie es nicht den Launen der generischen Pufferschicht.

Dies mag offensichtlich sein, aber stellen Sie sicher, dass Sie Write () nicht zu oft anrufen - stellen Sie sicher, dass jedes Write () über genügend Daten geschrieben wird, um den Syscall -Overhead lohnt. Nennen Sie es auch in der anderen Richtung nicht zu selten, oder es blockiert lange genug, um ein Problem zu verursachen.

Haben Sie auf einer schwierigeren Auffassung versucht, auf asynchrone E/O zu wechseln? Mit AIO können Sie ein Schreiben abfeuern und einen Puffersatz geben, während Sie Videodaten in den anderen Satz saugen, und wenn das Schreiben beendet ist, wechseln Sie die Puffersätze.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top