1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
\input{confighandout}
\subsection{RT\_PREEMPT}
\subsubsection{Anwendung des Preempt RT Patches}
\paragraph{Besorgen und Anwenden des Patches}
Preempt RT wird als Patch gegen den Mainline Linux Kernel gepflegt.
Unter:\newline
http://www.kernel.org/pub/linux/kernel/projects/rt sind die aktuellsten Patche
f\"ur Preempt RT zu finden. Im Unterverzeichnis older/ sind \"altere Patche
archiviert. Das Vorbereiten eines Kerneltrees mit Preempt RT ist denkbar
einfach:
\begin{lstlisting}
# Vanilla Kernel
wget http://www.kernel.org/pub/linux/kernel\
/v2.6/linux-2.6.29.5.tar.bz2
# Preempt RT Patch
wget http://www.kernel.org/pub/linux/kernel\
/projects/rt/patch-2.6.29.5-rt21.bz2
# Extract the kernel tree
tar xjvf linux-2.6.29.5.tar.bz2
# Patch the kernel tree
cd linux-2.6.29.5
bzcat ../patch-2.6.29.5-rt21.bz2 | patch -p1
\end{lstlisting}
Mit Steven Rostedt's Version des Pythonskripts ''ketchup'' geht es sogar noch einfacher (Steven
Rostedt's ketchup Version steht unter:\newline
http://people.redhat.com/srostedt/rt/tools/ketchup-0.9.8-rt3 zum Download
bereit):
\begin{lstlisting}
mkdir linux-2.6.29.5-rt21
cd linux-2.6.29.5-rt21
ketchup -f --no-gpg 2.6.29.5-rt21
\end{lstlisting}
\paragraph{Konfigurieren und \"Ubersetzen eines Preempt RT Kernels}
Die Konfiguration und das \"Ubersetzen machen keinen Unterschied zu Linux ohne
Preempt RT Patch:
\begin{lstlisting}
# external build directory
mkdir ../build
# base build on existing config
cp /boot/config-x-x-x ../build/.config
make O=../build oldconfig
\end{lstlisting}
F\"ur ein Echtzeitsystem m\"ussen verschiedene Kerneloptionen aktiviert werden:
\begin{lstlisting}
make O=../build menuconfig
\end{lstlisting}
Die wichtigsten Optionen befinden sich unter dem Menupunkt ''Kernel features''
bzw. ''Processor type and features''.
\begin{figure}[ht!]
\centering
\includegraphics[height=0.5\textwidth]{images/menu_rt_001.png}
\end{figure}
Dort m\"ussen folgende Optionen aktiviert werden:
\begin{itemize}
\item High Resolution Timer Support
\item Preemption Mode (Complete Preemption (Real-Time))
\end{itemize}
\begin{figure}[ht!]
\centering
\includegraphics[height=0.5\textwidth]{images/menu_rt_002.png}
\end{figure}
\begin{figure}[ht!]
\centering
\includegraphics[height=0.5\textwidth]{images/menu_rt_003.png}
\end{figure}
\begin{figure}[ht!]
\centering
\includegraphics[height=0.5\textwidth]{images/menu_rt_004.png}
\end{figure}
Das \"Ubersetzen des Kernels erfolgt nun wie \"ublich mit
\begin{lstlisting}
make O=../build
make O=../build modules
make O=../build install
make O=../build modules_install
\end{lstlisting}
\subsubsection{Testen eines Preempt RT Systems}
\paragraph{RT Tests}
Die RT Tests sind eine Sammlung von Programmen, zur Validierung der
Eigenschaften von Echtzeitsystemen. Die RT Tests umfassen folgende Tools:
\begin{itemize}
\item cyclictest: High Resolution Timer Testsoftware.
\item hwlatdetect: Python Script zur Steuerung des Kernelmoduls zur Erkennung
von System Management Interrupts (hwlat\_detector).
\item pi\_stress: Stresstest f\"ur Mutexe mit Priority Inheritance Attribut
\item signaltest: Benchmark, bei dem Signale zwischen Tasks ausgetauscht werden.
\end{itemize}
Die Sourcen der RT Tests werden in einem GIT Tree verwaltet.
\begin{lstlisting}
# Checkout RT Tests
git-clone git://git.kernel.org/pub/scm/linux/kernel\
/git/clrkwllms/rt-tests.git
# Compile RT Tests
cd rt-tests
make
\end{lstlisting}
\subparagraph{Cyclictest}
Cyclictest ist die wohl meistgenutzte Testsoftware auf Preempt RT Systemen. Mit
Cyclictest kann eine bestimmte Anzahl von Timertasks mit einem definierten
Interval aufgesetzt werden. F\"ur diese Tasks wird kontinuierlich die Abweichung
zum gew\"unschten Intervall gemessen und hierf\"ur die Maximale und Durchschnittliche
Abweichung aufgezeichnet. Die wichtigsten Parameter f\"ur Cyclictest sind die
Anzahl und die Priorit\"at der gew\"unschten Timertasks, die Art des zu verwendenden
Timers und das gew\"unschte Timerintervall:
\begin{lstlisting}
# 4 Timertasks (2000 , 2500, 3000, 3500us)
# -i options tells us the interval of the first task
# the interval of all other tasks will be increased
# by 500us
# The -p options tells us the priority of the first task
# the priorities of all other tasks will be decremented by 1
# -n = using nanosleep
zi:~# cyclictest -p80 -n -t4 -i2000
0.32 0.30 0.12 1/56 2124
T: 0 ( 2121) P:80 I:2000 C: 1258 Min: 62 Act: 99 Avg: 83 Max: 161
T: 1 ( 2122) P:79 I:2500 C: 1007 Min: 47 Act: 76 Avg: 77 Max: 130
T: 2 ( 2123) P:78 I:3000 C: 841 Min: 54 Act: 76 Avg: 82 Max: 136
T: 3 ( 2124) P:77 I:3500 C: 723 Min: 67 Act: 95 Avg: 96 Max: 177
\end{lstlisting}
\paragraph{Lastszenarien}
Um eine Aussage \"uber das Echtzeitverhaltens treffen zu k\"onnen, interessiert in
der Hauptsache das Verhalten in Worst-Case Szenarien (hohe CPU Last, hohe
Interruptlast). Ein ausgezeichnetes Werkzeug, um CPU Last zu erzeugen, ist
''hackbench''. Hackbench wurde urspr\"unglich als Schedulerbenchmark entwickelt.
Es erzeugt eine bestimme Anzahl an Prozessgruppen von Clients und Servern, die
\"uber Sockets miteinander kommunizieren:\newline
http://people.redhat.com/mingo/cfs-scheduler/tools/hackbench.c
Interruptlast, l\"a\ss t sich hervorragend mit einem Floodping von einem entfernten
Rechner erzeugen. Ein Floodping schickt eine gro\ss e Anzahl von ICMP Paketen in
kurzer Zeit. Dies erzeugt eine hohe Anzahl von Netzwerkinterrupts. Um Floodpings
zu generieren mu\ss das Programm ping mit Rootrechten und mit der Option -f
ausgef\"uhrt werden.
\subparagraph{Pitfall}
Ein sehr h\"aufig gemeldetes Ph\"anomen bei Testl\"aufen von Cyclictest mit einem
Floodping als Lastszenario, sind extrem gro\ss e Ausrei\ss er in der Gr\"o\ss enordnung von
50ms. Dies ist auf ein ''Feature'' aktueller Preempt RT Kernel zur\"uckzuf\"uhren.
Da Preempt RT auch auf vielen Desktops eingesetzt wird, auf denen Low Latency
Anwendungen betrieben werden (z.B. Multimedia Anwendungen), h\"auften sich
Fehlerberichte, die letztendlich nicht auf ein Kernelproblem zur\"uckzuf\"uhren
waren, sondern auf eine Realtime Applikation, die den Rest des Systems
aushungerte. Daher wurde eine Option eingef\"uhrt, die die Laufzeit von Realtime
Tasks beschr\"anken kann. \"Uberschreiten die Realtime Tasks dieses Zeitlimit,
werden diese f\"ur einen bestimmten Zeitraum nicht mehr geschedult. Die
Standardeinstellung liegt bei 950ms. Bei \"Uberschreiten der 950ms werden die
Echtzeittasks f\"ur 50ms suspendiert.
Da Interrupts unter Preempt RT als Kernelthread mit Echtzeitpriori\"at laufen
und durch den Floodping eine hohe Anzahl an Netzwerkinterrupts
(einschliesslich der zugeh\"origen Softinterrupts) erzeugt wird, nehmen Realtime
Tasks im System einen Gro\ss teil der Resourcen ein. Somit kann es passieren, da\ss
dieses Zeitlimit \"uberschritten wird.
Das Limit f\"ur die Rechenzeit kann durch Schreiben des gew\"unschten Wertes nach
/proc/sys/kernel/sched\_rt\_runtime\_us angepa\ss t werden.
Zum Deaktivieren dieser Funktion mu\ss Folgendes getan werden:
\begin{lstlisting}
echo -1 > /proc/sys/kernel/sched_rt_runtime_us
\end{lstlisting}
\subsubsection{Erstellen einer Realtime Task f\"ur Preempt RT}
\paragraph{Schedulingklassen / Priorit\"aten}
Eine Realtime Applikation auf Preempt RT ist eine POSIX Realtime Applikation.
POSIX sieht f\"ur Echtzeitapplikationen folgende Schedulingstrategien vor:
\begin{itemize}
\item SCHED\_FIFO: Scheduling mit statischen Priori\"aten
\item SCHED\_RR: Round Robin mit Priorit\"aten
\end{itemize}
Echtzeitpriorit\"at bekommt eine Applikation nur dann, wenn dies explizit
gew\"unscht wird. Hierzu ist die Funktion sched\_setscheduler() vorgesehen.
\paragraph{Beispiel einer Echtzeitapplikation}
Das folgende Beispiel zeigt eine einfache POSIX Realtimeapplikation:
\begin{lstlisting}
/*
* POSIX Realtime Example
* based on the example on http://rt.wiki.kernel.org
/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <sys/mman.h>
#include <string.h>
#define MAX_SAFE_STACK (8*1024) /* The maximum stack size which is
guranteed safe to access without
faulting */
void stack_prefault(void) {
unsigned char dummy[MAX_SAFE_STACK];
memset(&dummy, 0, MAX_SAFE_STACK);
return;
}
int main(int argc, char* argv[])
{
struct sched_param param;
/* Declare ourself as a real time task */
param.sched_priority = 80;
if(sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
perror("sched_setscheduler failed");
exit(-1);
}
/* Lock memory !!!*/
if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
perror("mlockall failed");
exit(-2);
}
/* Pre-fault our stack */
stack_prefault();
while(1) {
[...]
}
}
\end{lstlisting}
Die oben aufgelistete Applikation zeigt sehr sch\"on, was notwendig ist, um eine
Applikation mit deterministischem Zeitverhalten zu erzeugen:
\begin{itemize}
\item RT Scheduling Policy und Priorit\"at festlegen
\item Speicher locken, um undeterministisches Zeitverhalten durch
Pagefaults auszuschliessen.
\item ''Stack Pre-Faulting'', um zu vermeiden, da\ss Stackfaults
undeterministisches Zeitverhalten verursachen
\end{itemize}
Eine Ausgezeichnete Einf\"uhrung zum Erstellen von Echtzeitapplikationen und zur
Verwendung von Preempt RT findet sich unter:\newline
http://rt.wiki.kernel.org
\paragraph{Tracing / Latenzen aufsp\"uren}
\subparagraph{FTrace}
Ein hervorragendes Werkzeug, um kernelseitige Codepfade aufzusp\"uren, die lange
Latenzzeiten verursachen, ist Ftrace. Ftrace wird \"uber DebugFS, einem virtuellen
Dateisystem, gesteuert und platziert dort auch seine Ausgaben. Die einfachste
Methode, FTrace zu verwenden ist Cyclictest. Cyclictest biete bereits einige
Optionen, um FTrace zu steuern. Die Option -f sch\"allt Cyclictests Ftrace
Support an, -b <max\_latency> veranla\ss t Cyclictest, bei \"Uberschreiten einer
maximalen Latenzzeit, abzubrechen und einen Trace zu triggern.
\subparagraph{Kerneloptionen f\"ur FTrace}
Um FTrace verwenden zu k\"onnen, m\"ussen beim Konfigurieren des Kernels einige
unter dem Menupunkt ''Kernel hacking-->Tracers'' einige Optionen aktiviert werden:
\begin{itemize}
\item Kernel Function Tracer
\item Beliebige Optionen, die mit Trace beginnen (der zu verwendende
Tracetyp kann cyclictest \"uber die Commandline mitgegeben werden, siehe
cyclictest -h. Default ist der Event Tracer)
\end{itemize}
\subparagraph{Beispiel eines Traces}
Das Erstellen eines Traces mit cyclictest l\"a\ss t sich am Besten mit einem Beispiel
erl\"autern:
\begin{lstlisting}
# mount DebugFS
mkdir -p /mnt/debugfs
mount -t debugs debugfs /mnt/debugfs
# list available tracers
zi:~# cat /mnt/debugfs/tracing/available_tracers
wakeup_rt wakeup preemptoff function sched_switch nop
# start trace
cyclictest -p80 -n -f -b 100
zi:~# less /mnt/debugfs/tracing/trace
# tracer: function
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
IRQ-129-772 [000] 4154503386.851178: __rt_mutex_adjust_prio<-t
IRQ-129-772 [000] 4154503386.851186: __rt_mutex_adjust_prio<-t
IRQ-129-772 [000] 4154503386.851189: task_setprio<-__rt_mutex_
IRQ-129-772 [000] 4154503386.851192: task_rq_lock <-task_setpr
IRQ-129-772 [000] 4154503386.851195: sched_clock <-sched_clock
IRQ-129-772 [000] 4154503386.851199: dequeue_task <-task_setpr
IRQ-129-772 [000] 4154503386.851202: dequeue_task_fair <-deque
IRQ-129-772 [000] 4154503386.851206: update_curr <-dequeue_tas
IRQ-129-772 [000] 4154503386.851217: enqueue_task_rt <-task_se
IRQ-129-772 [000] 4154503386.851221: dequeue_rt_stack<-enqueue
IRQ-129-772 [000] 4154503386.851226: switched_to_rt <-task_set
IRQ-129-772 [000] 4154503386.851234: timer_interrupt<-ret_from
[...]
\end{lstlisting}
\paragraph{Kontrollfragen}
\begin{itemize}
\item Welche Optionen sollten beim \"Ubersetzen eines Preempt RT Kernels
mindestens gesetzt sein?
\item Wozu dient das Tool cyclictest?
\item Welchen bekannten ''Pitfall'' gibt es bzgl. hoher Latencies mit Floodping
als Lastszenario? Wie kann dieser umgangen werden?
\item Welche 3 Schritte sind notwendig, um das deterministische Zeitverhalten
einer Applikation zu garantieren?
\end{itemize}
\input{tailhandout}
|