2006-10-03
Realtid - grunder
I ett typiskt Linuxbaserat Audio/MIDI-system kan man hitta flera olika komponenter som måste samverka:
IRQ
IRQ står för Interrupt ReQuest. Detta innebär en avbrottskanal där enheter som behöver sända data påkallar uppmärksamhet. Processorn avbryter då för att ta emot data från den enhet som sänt IRQ.
I begynnelsen fanns AT-datorerna. Dessa hade 8 IRQ (0-7), som sedan utökades till 16 (0-15). När det fanns åtta IRQ var prioritetsordningen mellan dem så att lägst nummer hade högst prioritet och högst nummer hade lägst prioritet.
När IRQ utökades till 16 stycken, lade man in alla från 8-15 i platsen för IRQ 2, så nu ser prioritetsordningen ut som följer:
0, 1, (8, 9, 10, 11, 12, 13, 14, 15), 3, 4, 5, 6, 7
Detta innebär att IRQ 9, 10 och 11 är högre prioriterade än exempelvis 3 och 4. Detta går dock att ändra på.
PROCESS-PRIORITET
Man kan mycket förenklat säga att ju högre prioritet en process har, ju större chans är det att den kan köra ostört. Med en realtids-kärna har man möjlighet att låta IRQ-hanterare köras med lägre prioritet än användarapplikationer.
Det är, till exempel, möjligt att köra jackd med högre prioritet än alla IRQer för att säkerställa ostörd audio-hantering. Detta kan även inkludera IRQer för hårddisk och nätverkskort.
I en standard realtids-kärna har alla IRQ-hanterare en prioritet mellan 40-60. Genom att sätta jackd's prioritet till 70, gör vi så att JACK går före alla enheters begäran om åtkomst till processorn och databussen. Vi gör detta med jackd's -P switch:
# jackd -R -P 70 -d alsa ...
Det är ju allt väl, om det inte vore så att den IRQ som ljudkortet ligger på, och JACK använder sig av, bör ligga högre i prioritetsskalan än jackd.
Introduktion alltså för ett nytt program, som brukar ligga i ett paket som heter något liknande schedutils, chrt. Med chrt kan man ändra realtids-attributen för en viss process.
I realtidskärnan har varje IRQ ett process-ID (pid) för att det ska vara möjligt att manuellt ställa prioriteten på dem. För att lista ut vilka process-IDn som innehas av olika IRQer använder vi oss av programmet ps. ps är en typisk UNIX-förkortning som står för process och kommandot kan visa alla processer som för närvarande finns på systemet. För att bara visa de processer som har beskrivningen IRQ använder vi kommandot grep och filtrerar ps-kommandot genom det:
Eftersom de ljudkort som finns installerade har ICE1712-chip samt CS46xx-chip så kan man av listningen ovan sluta sig till att raderna markerade med < style="font-weight: bold;">IRQ 3 och 9.
Detta är inte alldeles enkelt för en nybörjare att klara av, så om du är en sån, ha gärna med dig en garvad nörd som du kan rådfråga med jämna mellanrum.
Processerna kan alltså ändras genom kommandot chrt med följande växlar, -p för prioritet 0-99 och -f för FIFO (First In First Out) policy, vilket är vad som bör användas i ljudsammanhang.
För enkelhetens skull kan man använda kommandot pidof som tar process-IDt från en process som matchar en viss textsträng.
# chrt -f -p 99 `pidof "IRQ 3"`
eller enligt ps-listningen en bit ovan:
# chrt -f -p 99 2837
Det är bra, för att inte säga en förutsättning, för ett lyckat resultat att ha ljudkortet på en egen IRQ. Om ljudkortet delar IRQ med till exempel nätverkskortet (exempelvis eth0) får detta lika hög prioritet som ljudkortet och hotar att dra en massa elände med sig.
Men det förutsätter som sagt att man lyckats kompilera sin egen kärna med realtids-patchning. Det går vi igenom i nästa avsnitt.
- JACK
- ALSA
- En MIDI-sequencer
- Några mjukvarusynthar
- En hårddiskinspelare
- All annan hårdvara (som hårddisk, nätverkskort, etc..) som behöver IRQ (avbrottsförfrågan) för att fungera.
- Resten av mjukvaran (som window-managers och annat användbart)
- Prioriterad audio-hantering samt
- Grym MIDI-tajming
IRQ
IRQ står för Interrupt ReQuest. Detta innebär en avbrottskanal där enheter som behöver sända data påkallar uppmärksamhet. Processorn avbryter då för att ta emot data från den enhet som sänt IRQ.
I begynnelsen fanns AT-datorerna. Dessa hade 8 IRQ (0-7), som sedan utökades till 16 (0-15). När det fanns åtta IRQ var prioritetsordningen mellan dem så att lägst nummer hade högst prioritet och högst nummer hade lägst prioritet.
När IRQ utökades till 16 stycken, lade man in alla från 8-15 i platsen för IRQ 2, så nu ser prioritetsordningen ut som följer:
0, 1, (8, 9, 10, 11, 12, 13, 14, 15), 3, 4, 5, 6, 7
Detta innebär att IRQ 9, 10 och 11 är högre prioriterade än exempelvis 3 och 4. Detta går dock att ändra på.
PROCESS-PRIORITET
Man kan mycket förenklat säga att ju högre prioritet en process har, ju större chans är det att den kan köra ostört. Med en realtids-kärna har man möjlighet att låta IRQ-hanterare köras med lägre prioritet än användarapplikationer.
Det är, till exempel, möjligt att köra jackd med högre prioritet än alla IRQer för att säkerställa ostörd audio-hantering. Detta kan även inkludera IRQer för hårddisk och nätverkskort.
I en standard realtids-kärna har alla IRQ-hanterare en prioritet mellan 40-60. Genom att sätta jackd's prioritet till 70, gör vi så att JACK går före alla enheters begäran om åtkomst till processorn och databussen. Vi gör detta med jackd's -P switch:
# jackd -R -P 70 -d alsa ...
Det är ju allt väl, om det inte vore så att den IRQ som ljudkortet ligger på, och JACK använder sig av, bör ligga högre i prioritetsskalan än jackd.
Introduktion alltså för ett nytt program, som brukar ligga i ett paket som heter något liknande schedutils, chrt. Med chrt kan man ändra realtids-attributen för en viss process.
I realtidskärnan har varje IRQ ett process-ID (pid) för att det ska vara möjligt att manuellt ställa prioriteten på dem. För att lista ut vilka process-IDn som innehas av olika IRQer använder vi oss av programmet ps. ps är en typisk UNIX-förkortning som står för process och kommandot kan visa alla processer som för närvarande finns på systemet. För att bara visa de processer som har beskrivningen IRQ använder vi kommandot grep och filtrerar ps-kommandot genom det:
$ ps ax | grep IRQOm vi ska modifiera prioriteten på IRQ för ljudkortet, tittar vi först vilken IRQ som det använder sig av genom att lista den virtuella filen /proc/interrupts med kommandot cat:
18 ? S< 0:00 [IRQ 9]
808 ? S< 0:00 [IRQ 12]
891 ? S< 0:00 [IRQ 1]
1724 ? S< 0:00 [IRQ 14]
1803 ? S< 0:00 [IRQ 10]
2837 ? S< 0:00 [IRQ 3]
2946 ? S< 0:00 [IRQ 8]
2960 ? S< 0:00 [IRQ 7]
3004 ? S< 0:00 [IRQ 6]
3080 ? S< 0:00 [IRQ 11]
5403 pts/0 R+ 0:00 grep IRQ
$ cat /proc/interrupts
CPU0
0: 357694670 XT-PIC timer 0/94670
1: 192527 XT-PIC i8042 0/92527
2: 0 XT-PIC cascade 0/0
3: 3683355 XT-PIC CS46XX 0/83355 <
8: 12983156 XT-PIC rtc 0/83156
9: 203367747 XT-PIC ICE1712 0/67747 <
10: 18757427 XT-PIC eth0 0/57427
11: 652848 XT-PIC nvidia 0/52848
12: 3109504 XT-PIC i8042 0/9504
14: 1693997 XT-PIC ide0 0/93997
15: 3617940 XT-PIC ide1 0/17940
NMI: 0
ERR: 600
Eftersom de ljudkort som finns installerade har ICE1712-chip samt CS46xx-chip så kan man av listningen ovan sluta sig till att raderna markerade med < style="font-weight: bold;">IRQ 3 och 9.
Detta är inte alldeles enkelt för en nybörjare att klara av, så om du är en sån, ha gärna med dig en garvad nörd som du kan rådfråga med jämna mellanrum.
Processerna kan alltså ändras genom kommandot chrt med följande växlar, -p för prioritet 0-99 och -f för FIFO (First In First Out) policy, vilket är vad som bör användas i ljudsammanhang.
För enkelhetens skull kan man använda kommandot pidof som tar process-IDt från en process som matchar en viss textsträng.
# chrt -f -p 99 `pidof "IRQ 3"`
eller enligt ps-listningen en bit ovan:
# chrt -f -p 99 2837
Det är bra, för att inte säga en förutsättning, för ett lyckat resultat att ha ljudkortet på en egen IRQ. Om ljudkortet delar IRQ med till exempel nätverkskortet (exempelvis eth0) får detta lika hög prioritet som ljudkortet och hotar att dra en massa elände med sig.
Men det förutsätter som sagt att man lyckats kompilera sin egen kärna med realtids-patchning. Det går vi igenom i nästa avsnitt.
Realtidskärna - Ubuntu
Att kompilera sin egen kärna är inte alltid så enkelt. Det finns dock några knep för att underlätta för oss Ubuntu-användare också.
Men först måste vi skapa förutsättningar för att kunna kompilera kärnan.
FÖRUTSÄTTNINGAR
För att över huvud taget kunna kompilera något behöver vi paketet build-essential som är ett meta-paket som installerar alla nödvändiga utvecklingspaket för att kompilera, och för att konfigurera kärnan krävs paketet libncurses5-dev för att få ett fint litet menysystem att rodda runt i.
Installera dessa genom att skriva:
sudo apt-get install build-essential libncurses5-dev
i en terminal.
PATCHA KÄRNAN
Sen är det dags att plocka hem källkoden till kärnan och allt som hör till. Detta gör vi genom att ta ner den senaste RT-patchen från Ingo Molnars hemsida
http://people.redhat.com/mingo/realtime-preempt/
och välj näst senaste utgåva i katalogen older/.
Själv hämtade jag patch-2.6.17-rt8 och det har fungerat bra hittills.
Sen är det dags att hämta källkoden till kärnan. Då gäller endast "hela" versionsnummer, alltså 2.6.17, inte 2.6.17.1, inte 2.6.17.8 eller något annat. Dessutom är det bara den officiella kärnan från kernel.org som ska användas, inte Ubuntus egenpaketerade.
Denna finns tillgänglig som linux-2.6.17.tar.gz i
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
Spara den i /usr/src och utför följande kommandon för att packa upp källkodsträdet:
# tar zxvf linux-2.6.17.tar.gz
# mv linux-2.6.17 linux-2.6.17-rt8
# mv linux linux.old
# ln -s linux-2.6.17-rt8/ linux
För Ubuntu krävs dessutom en speciell patch för diskhanteringen (EVMS - Enterprise Volume Management System) som installeras på följande sätt:
# apt-get install kernel-patch-evms
# gunzip kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch.gz
Kontrollera dessutom att källkoden för realtime-lsm inte ligger och skräpar någonstans, för då kommer inte kompileringen av kärnan att fungera. Detta kan göras genom att se huruvida det finns en katalog som heter något liknande /usr/src/modules/realtime-lsm med kommandot
ls /usr/src/modules/
Om den katalogen inte finns kan ni vara lugna.
Sen är det alltså dags att patcha. Det är viktigt att vi står i katalogen /usr/src/. För att göra ett testskott så provar vi med växeln --dry-run och ser så att det inte blir några fel:
# patch --dry-run -p1 < sökväg/till/patch-2.6.17-rt8
Om det inte blir det kan vi köra på med fullt drag. Om vi sparat patchen i /usr/src/-katalogen blir det sålunda:
# patch -p1 < /usr/src/patch-2.6.17-rt8
Vi gör samma procedur med evms-patchen när vi står i /usr/src/-katalogen:
# patch --dry-run -p1 < ../kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch
och om det inte blev några fel, kör vi på den med:
# patch -p1 < ../kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch
KONFIGURERA KÄRNAN
När detta väl är gjort ska vi kopiera den befintliga konfigurationsfilen för kärnan. Denna ligger i katalogen /boot och heter något i stil med config-2.6.xx-xx-386. Denna skall kopieras till filen /usr/src/linux/.config
För att få den senaste kör vi cp-kommandot såhär, under förutsättning att vi står i katalogen /usr/src/linux:
cp /boot/config-`uname -r` .config
Sen kör vi ett kommando för att konfigurera kärnan. Det som rekommenderas är:
make menuconfig
som gör att man får ett menysystem som är hyfsat lätt att navigera i som ser ut som nedan:

Figur 1. Bild på menuconfig
Här finns två menyalternativ som skall ändras i, nämligen:

Figur 2. Val av realtids-läge
I Kernel Hacking-sektionen är det ett val som skall kryssas bort och det är
KOMPILERA KÄRNAN
För att kompilera kärnan i Debian-baserade system som Ubuntu behövs paketet kernel-package, vilket vi kan installera med
# apt-get install kernel-package
Sen, stående i /usr/src/linux, kör vi kommandona
# make-kpkg clean
# make-kpkg modules_clean
# make-kpkg --revision 1 --initrd kernel_image kernel_headers modules_image
och ber en stilla bön att det inte blir några fel någonstans.
INSTALLERA KÄRNAN
Blir det inte det, kan vi installera paketen genom att
# cd ..
# dpkg -i *2.6.17-rt8*.deb
Detta kommer att lägga kärnan högst upp i hierarkin i bootmanagern Grub, vilket innebär att om du inte trycker på Esc-knappen vid uppstart så kommer den att boota in i den nya RT-kärnan. Det kan vara bra att veta om det inte går så bra.
Genom att trycka på Esc-knappen vid Grub-prompten, får du upp en lista över de installerade kärnorna. Det är där möjligt att välja en gammal kärna om RT-kärnan vägrar att starta.
TA BORT KÄRNAN
För att ta bort RT-kärnan kan du skriva kommandot
# apt-get remove kernel-image-2.6.17-rt8 kernel-headers-2.6.17-rt8
Men först måste vi skapa förutsättningar för att kunna kompilera kärnan.
FÖRUTSÄTTNINGAR
För att över huvud taget kunna kompilera något behöver vi paketet build-essential som är ett meta-paket som installerar alla nödvändiga utvecklingspaket för att kompilera, och för att konfigurera kärnan krävs paketet libncurses5-dev för att få ett fint litet menysystem att rodda runt i.
Installera dessa genom att skriva:
sudo apt-get install build-essential libncurses5-dev
i en terminal.
PATCHA KÄRNAN
Sen är det dags att plocka hem källkoden till kärnan och allt som hör till. Detta gör vi genom att ta ner den senaste RT-patchen från Ingo Molnars hemsida
http://people.redhat.com/mingo/realtime-preempt/
och välj näst senaste utgåva i katalogen older/.
Själv hämtade jag patch-2.6.17-rt8 och det har fungerat bra hittills.
Sen är det dags att hämta källkoden till kärnan. Då gäller endast "hela" versionsnummer, alltså 2.6.17, inte 2.6.17.1, inte 2.6.17.8 eller något annat. Dessutom är det bara den officiella kärnan från kernel.org som ska användas, inte Ubuntus egenpaketerade.
Denna finns tillgänglig som linux-2.6.17.tar.gz i
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
Spara den i /usr/src och utför följande kommandon för att packa upp källkodsträdet:
# tar zxvf linux-2.6.17.tar.gz
# mv linux-2.6.17 linux-2.6.17-rt8
# mv linux linux.old
# ln -s linux-2.6.17-rt8/ linux
För Ubuntu krävs dessutom en speciell patch för diskhanteringen (EVMS - Enterprise Volume Management System) som installeras på följande sätt:
# apt-get install kernel-patch-evms
# gunzip kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch.gz
Kontrollera dessutom att källkoden för realtime-lsm inte ligger och skräpar någonstans, för då kommer inte kompileringen av kärnan att fungera. Detta kan göras genom att se huruvida det finns en katalog som heter något liknande /usr/src/modules/realtime-lsm med kommandot
ls /usr/src/modules/
Om den katalogen inte finns kan ni vara lugna.
Sen är det alltså dags att patcha. Det är viktigt att vi står i katalogen /usr/src/. För att göra ett testskott så provar vi med växeln --dry-run och ser så att det inte blir några fel:
# patch --dry-run -p1 < sökväg/till/patch-2.6.17-rt8
Om det inte blir det kan vi köra på med fullt drag. Om vi sparat patchen i /usr/src/-katalogen blir det sålunda:
# patch -p1 < /usr/src/patch-2.6.17-rt8
Vi gör samma procedur med evms-patchen när vi står i /usr/src/-katalogen:
# patch --dry-run -p1 < ../kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch
och om det inte blev några fel, kör vi på den med:
# patch -p1 < ../kernel-patches/diffs/evms-bd-claim/2.6-bd-claim.patch
KONFIGURERA KÄRNAN
När detta väl är gjort ska vi kopiera den befintliga konfigurationsfilen för kärnan. Denna ligger i katalogen /boot och heter något i stil med config-2.6.xx-xx-386. Denna skall kopieras till filen /usr/src/linux/.config
För att få den senaste kör vi cp-kommandot såhär, under förutsättning att vi står i katalogen /usr/src/linux:
cp /boot/config-`uname -r` .config
Sen kör vi ett kommando för att konfigurera kärnan. Det som rekommenderas är:
make menuconfig
som gör att man får ett menysystem som är hyfsat lätt att navigera i som ser ut som nedan:

Figur 1. Bild på menuconfig
Här finns två menyalternativ som skall ändras i, nämligen:
- Processor type and features, samt
- Kernel Hacking
- High Resolution Timer Support - ska finnas
- High Resolution Timer resolution (i nanosekunder) - ska ställas till 1000
- Processor family - till CPU-typen i systemet (t ex Pentium 4 M)
- Preemption mode - se nedan.
- Timer frequency - sätts till 1000Hz

Figur 2. Val av realtids-läge
I Kernel Hacking-sektionen är det ett val som skall kryssas bort och det är
- Kernel debugging
KOMPILERA KÄRNAN
För att kompilera kärnan i Debian-baserade system som Ubuntu behövs paketet kernel-package, vilket vi kan installera med
# apt-get install kernel-package
Sen, stående i /usr/src/linux, kör vi kommandona
# make-kpkg clean
# make-kpkg modules_clean
# make-kpkg --revision 1 --initrd kernel_image kernel_headers modules_image
och ber en stilla bön att det inte blir några fel någonstans.
INSTALLERA KÄRNAN
Blir det inte det, kan vi installera paketen genom att
# cd ..
# dpkg -i *2.6.17-rt8*.deb
Detta kommer att lägga kärnan högst upp i hierarkin i bootmanagern Grub, vilket innebär att om du inte trycker på Esc-knappen vid uppstart så kommer den att boota in i den nya RT-kärnan. Det kan vara bra att veta om det inte går så bra.
Genom att trycka på Esc-knappen vid Grub-prompten, får du upp en lista över de installerade kärnorna. Det är där möjligt att välja en gammal kärna om RT-kärnan vägrar att starta.
TA BORT KÄRNAN
För att ta bort RT-kärnan kan du skriva kommandot
# apt-get remove kernel-image-2.6.17-rt8 kernel-headers-2.6.17-rt8