Dipl. Phys. Helmut Weber Dph.HelmutWeber at gmail.com






Achtung:

Alle Beiträge sind Copyright (C) 2018 Dipl. Phys. Helmut Weber

Jedes Kopieren - egal, in welcher Form - bedarf der schriftlichen Erlaubnis.



Beispiel 1



Linux und Echtzeit


Die Vorteile eines RTOS (realtime operating system) sind:

Deterministisches (vorhersagbares) Verhalten der einzelnen Tasks.

Regelmäßige Taskwechsel

Kein Absturz des Systems, wenn ein Task abstürzt.



Es wird in Kauf genommen, dass die Geschwindigkeit der Ausführung nicht optimal ist!


Eigentlich erfüllt Linux diese Ansprüche und wäre damit als RTOS ideal.

Allerdings gibt es einen kleine Haken:

Beim Taskswitch kann es immer wieder zu Verzögerungen kommen, weil Linux zwischendurch Betriebssystem-Arbeiten erledigt.


Denn plötzlich spielt die Geschwindigkeit doch eine Rolle!


Diese Sichtweise ist nicht konsequent. Denn wenn man z. Bsp. festlegt:

Jeder Task soll mindestens einmal pro Sekunde arbeiten, dann ist jedes Linux sofort als RTOS anzusehen. Es führt – ohne dass es im Programm verankert wurde – üblicherweise 100 Taskwechsel pro Sekunde durch. (RTOS typischerweise 100-1000)


Wenn es um Schnelligkeit geht, kommt man nie um eine gewisse Kooperation der Tasks aus, sprich: die Tasks geben freiwillig ihre Rechenzeiten zu geeigneten Zeitpunkten auf – durch einen angestoßenen Taskswitch (yield) oder ein Delay im Task.


Was kann man damit erreichen?

Wenn sich alle Tasks in diesem Sinne „kooperativ“

verhalten, dann sind auch auf allen embedded systems mit vergleichsweise schwachen Prozessoren in der Lage, mehrere Millionen Taskswitches pro Sekunde durchzuführen.


Es bleibt allerdings das Problem, dass Linux gelegentlich Rechenzeit für sich selbst beansprucht – und das stört, denn es mach deterministische Aussagen unmöglich.



Hier ein Beispiel:

Ein Task führt nur sehr wenig aus und gibt dann mit einem yield die Rechenzeit ab.

Es wird die Zeit gemessen, wann er die Rechenzeit wieder zurückbekommt, wenn er der einzige Task im Programm ist:


Bild1
Abb. 1 (C) 2018 H. Weber


99,9% der Taskswitches finden innerhalb von wenigen Mikrosekunden statt.

Wenn da nur nicht diese Ausrutscher von über 8000 µs wären.


Genau hier setzt Linux preempt_RT ein – ein Patch des Linuxkernels, der u. a. Hilft, das zu verhindern. Weiterhin hilft es bei modernen Prozessoren, ein core für spezielle Aufgaben zu reservieren.


Das gleiche Test-Programm unter solchen Bedingungen:


Bild2


Es gibt immer noch eine Verteilung, aber die maximale Zeit beträgt jetzt 62 µs statt 8400 µs.


Die Testzeiträume sind lang genug, um eine maximale Zeit von 100µs zu garantieren – selbst dann, wenn der Task selbst einige Rechenzeit beansprucht.

Solche kooperativen Tasks bringen das System auch nicht zum Absturz, wenn sie ihre Rechenzeit nicht freiwillig abgeben (wie es kooperativen Betriebssystem oft nachgesagt wird – die ersten Windows-Versionen habe zu diesem Ruf geführt), sondern dann übernimmt Linux den Taskswitch und führt alle sonstigen Aufgaben durch.

In nahezu jedem praktisch eingesetzten RTOS gibt es einen oder mehrere „Watchdog-Timer“, die das System überwachen. Das geht hier problemlos mit einem weiteren Task.

Mit anderen Worten, auch eine unendliche Schleife wie

while(1);

oder etwa ein „Segmentation Fault“ bringt das System nicht zum Absturz.


Dies ruft geradezu nach einem kooperativen Scheduler, der selbst Tasks initiert und aufruft.

Das hat gewaltige Vorteile:


mehrere Millionen calls des Schedulers pro Sekunde Tasks geben an genau vorherbestimmten Punkten ihre Rechenzeit ab. (Zeitkritische Abschnitte)
Die Zeit von Unterbrechung zu Unterbrechung läßt sich genau messen und vorhersage – für jeden einzelnen der so gestarteten kooperativen Tasks.
Betriebssytembedingte Verzögerungen (hier: bis zu 60µs) können gemessen und berücksichtigt werden.



Für noch höhere Präzision bleiben Timer-Interrupts für kurze Aufgaben!

Dieser Scheduler (CoopOS) zusammen mit einem RTOS statt Linux preempt_RT (aber im Prinzip vergleichbar) wird in Beispiel 2 näher erläutert., Beispiel 3 kommt auf den Raspberry Pi zurück.


Linux preempt_RT wird bei embedded systems eine zunehmende Rolle spielen!



Hier ein Beispiel:

Ein Timer feuert alle 100 µs, also 10000x pro Sekunde. Es wird eine Variable count hochgezählt, also 10000 pro Sekunde.

Ein Programm gibt in einer Schleife jede Sekunde die Variable count aus.


Es gibt dabei die Differenz der Zeit seit der letzten Ausgabe in µs aus (Genauigkeit in Nanosekunden!).



lastCycles=0;

anfang=nanos();

count=0;

setitimer (ITIMER_REAL, &timer, NULL); // start Timer IRQ ever 100µs

while(1) {

next=anfang+inum*1000000000LL; // NANOSECONDS

while (next>nanos()); // Wait 1 second

thisCycles=nanos();

diff=(long long)thisCycles - (long long)lastCycles; // calc difftime

if (count<10000) { count=0; diff=0; } //SYNC

printf("Count %12llu nanos-diff %9.1f µs\n",count, (double)diff/1000);

lastCycles=thisCycles;

inum++;

}



Sollte Linux preempt_RT zwischendurch mehr als 100 µs für andere Tasks benötigen, so wird sich dass sofort bemerkbar machen.


Nach anfänglicher Synchronisation gibt es keinen Zusammenhang zwischen Programmschleife und Timer. Jede massive Unterbrechung der Schleife durch Linux sollte die Synchronisation stören!

(Bei einer Loop-Dauer von 50µs ist das auch gelegentlich der Fall.)


Bild3

Bild 3


Das Ergebnis: auch nach 5 Stunden höchste Genauigkeit und Synchronisation !


Da die Entwickler von Linux stetig an der Verbesserung des Kernels in Richtung Echtzeit-OS arbeiten und es das erklärte Ziel ist, Linux zu einem echten RTOS zu machen, sind stetige Verbesserungen zu erwarten!


Linux preempt_RT wird bei embedded systems eine zunehmende Rolle spielen!


CoopOS kann nicht nur im Loop laufen. Der Scheduler kann, wenn die einzelnen Taskabschnitte schell genug erledigt werden, auch per Timer-Interrupt gestartet werden:


Bild9

Weitere Einzelheiten zu CoopOS im Zusammenspiel mit Linux preempt-RT in den anderen Beispielen.