Frage

Ich brauche einen Timer-Tick mit 1ms Auflösung unter Linux. Es wird verwendet, um einen Timer-Wert zu erhöhen, die wiederum verwendet wird, um zu sehen, wenn verschiedene Ereignisse ausgelöst werden sollen. Die POSIX timerfd_create ist keine Option, da der glibc Anforderung. Ich habe versucht, timer_create und timer_settimer, aber das Beste, was ich von ihnen bekommen, ist eine 10 ms Auflösung, scheinen kleinere Werte zu 10ms Auflösung auf Standard. Getittimer und setitimer haben eine Auflösung von 10 ms nach der manpage.

Der einzige Weg, diesen Timer zu tun ich zur Zeit denken kann, ist clock_gettime zu verwenden, um mit CLOCK_MONOTONIC in meiner Hauptschleife einen Test, ob eine ms vergangen ist, und wenn ja, um den Zähler zu erhöhen (und dann prüfen, ob die verschiedenen Ereignisse ausgelöst werden sollen ).

Gibt es einen besseren Weg, dies zu tun, als ständig in der Hauptschleife abfragen? Was ist die empfohlene Lösung für dieses?

Die Sprache, die ich verwende, ist das gute alte c

Aktualisieren
Ich verwende einen 2.6.26 Kernel. Ich weiß, Sie können es bei 1kHz brechen müssen, und die POSIX timer_ * Funktionen können dann auf bis zu 1 ms programmiert werden, aber das scheint nicht zuverlässig zu sein, und ich möchte nicht, dass verwenden, weil es einen neuen Kernel auf einige benötigen Systeme. Einige Lager Kernel scheinen immer noch zu haben, die 100Hz konfiguriert. Und ich müsste das erkennen. Die Anwendung kann auf etwas anderes als mein System ausgeführt werden:)

Ich kann nicht für 1ms schlafen, weil es Netzwerk-Events sein kann ich zu reagieren haben.

Wie kann ich mich entschlossen es Da es nicht so wichtig ist, erklärte ich einfach, dass der globale Zeitgeber eine 100ms Auflösung hat. Alle Veranstaltungen ihre eigenen Timer mindestens 100ms für die Timer-Ablauf einzustellen. Ich war mehr oder weniger fragen, ob es wäre ein besserer Weg, daher die Frage.

Warum ich akzeptierte die Antwort Ich denke, die Antwort von freiem Speicherplatz am besten beschrieben, warum es ohne Echtzeit-Linux-System nicht wirklich möglich ist.

War es hilfreich?

Lösung

Polling in der Hauptschleife ist keine Antwort entweder -. Ihr Prozess nicht viel CPU-Zeit bekommen könnte, so dass mehr als 10 ms verstreichen, bevor Sie Ihren Code ausführen wird, wodurch es strittig

10 ms ist über die Standard-Timer-Auflösung für die meisten nicht Echtzeit-Betriebssysteme (RTOS ). Aber es ist strittig in einer Nicht-RTOS - das Verhalten des Schedulers und Dispatcher wird stark beeinflussen, wie schnell man auf einen Timer Ablaufen reagieren kann. Sie können beispielsweise auch annehmen, eine Unter 10ms Auflösung Timer hatten, können Sie nicht auf den Timer reagieren abläuft, wenn Ihr Code nicht ausgeführt wird. Da Sie nicht vorhersagen können, wenn Ihr Code ausgeführt wird, kann man nicht genau Timer Ablauf reagieren.

Es gibt natürlich Realtime Linux-Kernel finden Sie unter http://www.linuxdevices.com/articles /AT8073314981.html für eine Liste . Ein RTOS bietet Einrichtungen, wobei Sie weiche oder harte Garantien erhalten können, wenn Ihr Code ausgeführt wird. Es geht um die einzige Möglichkeit, zuverlässig und genau zu Timer reagiert auslaufende etc.

Andere Tipps

Um 1ms Auflösung Timer tun, was libevent der Fall ist.

Organisieren Sie Ihre Timer in einen min-heap , das heißt, die Spitze des Haufens ist der Timer mit die früheste Ablauf (absolut) Zeit (a rb-Baum würde auch mit mehr Aufwand, aber). Vor dem Aufruf select() oder epoll() in der Hauptereignisschleife berechnet das Delta in Millisekunden zwischen der Ablauf der Zeit des frühesten Timer und jetzt. Verwenden Sie dieses Delta als das Timeout auf select(). select() und epoll() Timeouts haben 1ms Auflösung.

Ich habe eine Timer-Auflösung Test bekam, die den Mechanismus verwendet oben erklärt (aber libevent nicht). Der Test misst die Differenz zwischen der gewünschten Timer Ablaufzeit und dem tatsächlichen Ablauf von 1 ms, 5 ms und 10 ms-Timer:

1000 deviation samples of  1msec timer: min=  -246115nsec max=  1143471nsec median=   -70775nsec avg=      901nsec stddev=    45570nsec
1000 deviation samples of  5msec timer: min=  -265280nsec max=   256260nsec median=  -252363nsec avg=     -195nsec stddev=    30933nsec
1000 deviation samples of 10msec timer: min=  -273119nsec max=   274045nsec median=   103471nsec avg=     -179nsec stddev=    31228nsec
1000 deviation samples of  1msec timer: min=  -144930nsec max=  1052379nsec median=  -109322nsec avg=     1000nsec stddev=    43545nsec
1000 deviation samples of  5msec timer: min= -1229446nsec max=  1230399nsec median=  1222761nsec avg=      724nsec stddev=   254466nsec
1000 deviation samples of 10msec timer: min= -1227580nsec max=  1227734nsec median=    47328nsec avg=      745nsec stddev=   173834nsec
1000 deviation samples of  1msec timer: min=  -222672nsec max=   228907nsec median=    63635nsec avg=       22nsec stddev=    29410nsec
1000 deviation samples of  5msec timer: min= -1302808nsec max=  1270006nsec median=  1251949nsec avg=     -222nsec stddev=   345944nsec
1000 deviation samples of 10msec timer: min= -1297724nsec max=  1298269nsec median=  1254351nsec avg=     -225nsec stddev=   374717nsec

Der Test lief als Echtzeit-Prozess auf Fedora 13-Kernel 2.6.34, die besten erreichte Präzision von 1 ms Timer war avg = 22nsec stddev = 29410nsec.

Ich bin mir nicht sicher, es ist die beste Lösung, aber Sie könnten erwägen, eine kleine Kernel-Modul zu schreiben, die das Kernel-High-Res-Timer verwendet Timing zu tun. Grundsätzlich würden Sie eine Gerätedatei erstellen, für die liest nur auf 1 ms Intervallen zurückkehren würde.

Ein Beispiel für diese Art von Ansatz ist in dem Asterisk PBX, über das ztdummy Modul verwendet. Wenn Sie Google für ztdummy Sie den Code finden, der dies tut.

Ich glaube, Sie Probleme zu erreichen 1 ms Genauigkeit mit Standard-Linux auch bei konstanten anfragende in der Hauptschleife haben werden, da der Kernel nicht Ihre Anwendung nicht gewährleistet werden CPU die ganze Zeit erhalten. Zum Beispiel können Sie für Dutzende von Millisekunden in den Schlaf versetzen wegen preemptives Multitasking und es gibt wenig, was Sie dagegen tun können.

Sie könnte aussehen wollen in Real-Time Linux .

Wenn Sie x86-Plattform zielen sollten Sie HPET Timern überprüfen. Dies ist Hardware-Timer mit großer Präzision. Es muss von Ihrem mother unterstützt werden (jetzt alle von ihnen es unterstützen) und der Kernel sollte enthält Treiber für sie als gut. Ich habe es einige Male ohne Probleme verwendet und war in der Lage eine viel bessere Auflösung als 1 ms zu erreichen.

Hier finden Sie einige Dokumentation und Beispiele:

Ich scheine ok Ergebnisse mit gettimeofday / usleep basierend Polling wieder zu bekommen - ich nicht, um 1000 einem zweiten oder etwas Timer, aber ich war für Zecken mit dem Timing gute Genauigkeit benötigen ich brauche - meine app eine war MIDI Drum-Machine-Controller und ich scheine Sub-Millisekunden-Genauigkeit zu erinnern bekommen, die Sie für eine Drum-Maschine benötigen, wenn Sie es wie ein sehr schlechter Schlagzeuger (va MIDI-interne Latenzen zu zählen.) klingen nicht wollen - iirc (es war 2005 so mein Gedächtnis ein wenig unscharf ist) ich wurde innerhalb von 200 Mikrosekunden von Zielzeiten mit usleep bekommen.

Allerdings war ich nicht viel anderes auf dem System ausgeführt werden. Wenn Sie eine kontrollierte Umgebung haben könnten Sie in der Lage sein, mit einer Lösung wie das wegzukommen. Wenn es mehr los auf dem System (watch cron Anheizen updatedb, etc.), dann können die Dinge auseinander fallen.

Sind Sie auf einem Linux-2.4-Kernel ausgeführt wird?

Von VMware KB-Artikel # 1420 ( http://kb.vmware.com/kb/1420 ).

  

Linux-Gastbetriebssysteme halten   Zeit durch den Timer-Interrupts zu zählen.   Ungepatchte 2.4 und ältere Kernel   Programmieren der virtuellen System-Timer   Anforderungstaktunterbricht bei 100 Hz (100   Interrupts pro Sekunde). 2.6-Kernel,   Interrupts auf der anderen Seite fordern   1000 Hz - zehnmal so oft. Etwas   2.4 Kernel durch Verteilung Anbieter modifizierte 2.6 Funktionen auch enthalten   Anfrage 1000Hz unterbricht, oder in einigen   Fälle zu anderen Sätzen unterbricht, so   als 512Hz.

Zuerst die Kernel-Quelle erhalten und es mit einem angepassten HZ Parameter kompilieren.

  • Wenn HZ=1000, Timer-Interrupts 1000-mal pro Sekunde. Es ist ok HZ=1000 für eine i386-Maschine zu verwenden.
  • Auf einer eingebetteten Maschine, HZ bis 100 oder 200 begrenzt werden könnten.

Für einen guten Betrieb sollte PREEMPT_KERNEL Option sein. Es gibt Kerne, die diese Option nicht richtig unterstützt. Sie können sie überprüfen, indem Suche.

Neuere Kernel, das heißt 2.6.35.10 unterstützt NO_HZ Optionen, die verwandelt sich auf dynamischen Ticks. Das bedeutet, dass es keine Timer Ticks wenn im Leerlauf sein, aber ein Timer-Tick wird am angegebenen Zeitpunkt erzeugt werden.

Es ist ein RT-Patch für den Kernel, aber Hardware-Unterstützung ist sehr begrenzt.

Generell RTAI ist eine All Killer Lösung für Ihr Problem, aber seine Hardware-Unterstützung ist sehr begrenzt. Doch eine gute CNC-Steuerungen, wie emc2 verwenden RTAI für ihre Taktung, vielleicht 5000 Hz, aber es kann sein, harte Arbeit zu installieren.

Wenn Sie können, Sie könnten Hardware hinzufügen Impulse zu erzeugen. Das würde ein System, das auf jede OS-Version angepasst werden kann.

Können Sie zumindest verwenden Nanosleep in der Schleife für 1ms zu schlafen? Oder ist das ein glibc Ding?

Update: Es macht nichts, ich von der Mann-Seite „kann es bis zu 10 ms dauert länger als angegeben, bis der Prozess zur Ausführung wird wieder“

Sie haben kein RTOS für eine einfache Echtzeit-Anwendung benötigen. Alle modernen Prozessoren haben General Purpose Timer. Holen Sie sich ein Datenblatt für was auch immer Ziel-CPU Sie arbeiten. Schauen Sie in den Kernel-Quellen, unter dem Bogen Verzeichnis Sie prozessorspezifische Quelle finden, wie diese Zeiten zu behandeln.

Es gibt zwei Ansätze, die Sie mit diesem nehmen:

1) Ihre Anwendung läuft NUR Ihre Zustandsmaschine, und sonst nichts. Linux ist einfach Ihre „Bootloader“. Erstellen Sie ein Kernel-Objekt, das ein Zeichengerät installiert. Beim Einsetzen in den Kernel, stellen Sie Ihren GP Timer dauernd laufen. Sie wissen, dass die Frequenz, bei es arbeitet. Nun, im Kernel deaktivieren explizit Ihre Watchdog. Jetzt deaktivieren Interrupts (Hardware und Software) auf einem Single-CPU-Linux-Kernel, rief spin_lock () erreichen wird dies (nie loslassen.) Die CPU liegt bei Ihnen. Busy Schleife, haben den Wert der GPT, bis die gewünschte Anzahl der Zecken Überprüfung bestanden, wenn sie haben, legen Sie einen Wert für die nächste Timeout und Ihre Verarbeitungsschleife ein. stellen Sie sicher, dass die Zerfallszeit für Ihren Code unter 1ms

2) Eine zweite Option. Dies setzt voraus, Sie einen Präventiv Linux-Kernel ausgeführt werden. Richten Sie einen nicht verwendet einen GPT an der Seite Ihrer laufenden OS. Nun richten Sie einen Interrupt einige konfigurierbare Marge vor Ihrem 1ms abzufeuern Timeout passiert (etwa 50-75 uSek.) Wenn die Interrupt ausgelöst, werden Sie sofort Interrupts deaktivieren und Spin warten auf 1ms Fenster auftreten, dann Zustandsmaschine eingeben und anschließend ermöglicht Interrupts auf Ihrer abzuwarten. Dies trägt der Tatsache Rechnung, dass Sie mit anderen Dingen im Kernel zusammenarbeiten, die Interrupts deaktivieren. Dies setzt voraus, dass es keine andere Kernel-Aktivität, die Interrupts für eine lange Zeit sperrt (mehr als 100 s.) Nun können Sie die Genauigkeit Ihrer Feuerungsereignis messen und das Fenster größer machen, bis es Ihren Bedarf gerecht wird.

Wenn Sie stattdessen versuchen Sie, zu lernen, wie RTOS Arbeit ... oder wenn Sie versuchen, ein Steuerungsproblem mit mehr als einer Echtzeit-Verantwortung zu lösen ... dann einen RTOS verwenden.

Was ist mit "/ dev / rtc0" (oder "/ dev / rtc") Gerät und die dazugehörigen ioctl () Schnittstelle? Ich denke, es bietet einen genauen Zeitzähler. Es ist nicht möglich, die Geschwindigkeit nur auf 1 ms eingestellt, jedoch in der Nähe bzw. 1 / 1024sec (1024Hz), oder auf eine höhere Frequenz, wie von 8192 Hz.

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