Mikrojądro
Autorzy
W kolejności występowania na scenie:
- Marcin Przybyłko
- Maciej Teter
- Jędrzej Jabłoński
Spis treści
- Wstęp
- Troszkę teorii
- Mikrojądro: a cóż to jest?
- Monolit - twój wróg?
- Different systems for different purposes
- Minix
- QNX
- Hurd
- A co na to MS?
- Monolit vs Mikrojądro
- Jak działają systemy z mikrojądrem?
- Architektura Windows NT
- QNX (Neutrino)
- Minix
- Hurd (Mach)
- Testy wydajności
- Screenshoty
Wstęp
Początkowo jądra systemów były "niewielkich" rozmiarów. Było to
spowodowane ograniczonością architektur (pamieć), ale także małymi
wymaganiami użytkowników czy też małą różnorodnością/ilocią sprzętu
który winien być obsługiwany przez system operacyjny.
Jednakże wraz ze wzrostem możliwości komputerów, wraz z dodawaną
funkcjonalnością, jądra systemów rosły i stawały się coraz to bardziej
skomplikowane.
Przejscie z systemow 16 na 32 bitowe tylko spotęgowało efekt
rozrastania się kodu źródłowego, ktorego ilość w jądrach monolitowych
możemy liczyć w milionach.
Spowodowało to powstawanie wielu błędów, które, ze względu na ogrom
kodu, niemożliwy do ogarnięcia przez pojedyńczą osobę, były i ciągle są
trudne do wytropienia i zlikwidowania.
Szczególnie niekorzystny jest to fakt dla monolitów dla których
niewielki błąd zawarty w peryferyjnym sterowniku może spowodować crash
całego systemu.
Inną konsekwencją wielu linii kodu źródłowego jest bardzo
pracochłonna i trudna pielęgnacja. Aby zapobiec tym skutkom zaczęto
rozwijać ideę systemów opartych o mikrojądra, które minimalizują
wielkosć kodu źródłowego serca SO.
Troszkę teorii
Mikrojądro a cóż to jest?
Mikrojądro jak nazwa wskazuje jest to minimalne jądro, gdzie przez minimalność rozumiemy
ilość udostępnionych mechanizmów koniecznych do prawidłowego funkcjonowania systemu.
Takim minimalnym zestawem jest:
- IPC
- obsługa CPU
- obsługa przestrzeni adresów
obecny w Nucleusie - jądrze systemu RC 4000 Multiprogramming System.
minimality principle
Jeśli zastanawiamy się co jest potrzebne w jądrze możemy posłużyć się zasadą minimalności:
A concept is tolerated inside the microkernel only if moving it
outside the kernel would prevent the implementation of the system's
required functionality
Ale czy to dobra droga?
I w ogólności co możemy usunąć z jądra systemu by ten ciągle działał??
Wiemy zatem czym jest mikrojądro, ale nie zostało (explicite)
powiedziane w jaki sposób możemy zachować sprawność systemu wyrzucająć
z jądra prawie cały kod.
A co ważniejsze dlaczego chcielibyśmy chcieć to zrobić ?
Skoro nie mamy żadnej funkcjonalności jądra w jądrze to musimy się
posiłkować aplikacjami wykonywanymi w trybie użytkownika - serwerami.
Serwery są to zwykłe aplikacje, demony, ktore dodatkowo mogą posiadać
prawo do bezpośredniego dostepu do sprzętu, np. do pamięci fizycznej, a
wszelkie usługi oferowane przez serwery są udostępniane innym programom
poprzez komunikaty IPC.
Przykładami serwerów są:
- file system servers
- device driver servers
- networking servers
- display servers
Innymi słowy wszystkie funkcje jądra są udostępniane jako oddzielne procesy w trybie użytkownika.
Monolit twoj wróg?
Zanim możemy mówić o zaletach albo wadach mikrojądra powinniśmy poznać jego najważniejszego oponenta jądro monolitowe
Jądro monolitowe jest to jądro z jakim codziennie spotykamy się pożytkując nasz czas na naukę SO.
Przykładem jest oczywiście Linux.
Specyfikę jądra monolitowego poznajemy systematycznie na wykładzie,
zatem pozwolę sobie jedynie zamieścić obrazek podsumowujący cechy
systemu opartego na jądrze monolitowym.
Different systems for different purposes
MINIX
Minix - system stworzony przez A. Tanenbauma , opublikowany w 1987r.
Został stworzony do celów edukacyjnych i rozpowszechniany razem z książką
"Operating Systems: Design and Implementation" autorstwa A.T i A.W.
Jest to pierwszy klon Uniksa z dostępnym źródłem.
W roku 2005 zostały ogłoszone prace nad trzecią wersją Miniksa, pisaną w zasadzie od podstaw.
Która w zaożeniach miała być "a serious system on resource-limited and embedded computers and for applications requiring high reliabity"
Jej najnowsza wersja to 3.1.2 z 8.05.2006
Cechy miniksa to:
- niewielki rozmiar jądra systemu (ok. 4k linii kodu źródłowego)
- wysoka niezawodność, elastyczność i bezpieczeństwo
- self-healing
- wielozadaniowość
- niewielkie wymagania sprzętowe
Jądro miniksa składa się z:
- obsługi przerwań
- schedulera
- IPC
Trusted computing base
Jest to jądro oraz zespół serwerów których załamanie powoduje śmierć całego systemu.
W skład wchodzą: file, reincarnation, process server oraz jądro systemu.
Załamanie jakiegokolwiek innego elementu miniksa nie powinien mieć znaczącego wpływu na kondycję systemu.
Cały TCB to około 28k lini kodu.
Cel do którego dążą tworcy miniksa:
(...)Minix 3 (...) is not about microkernels. It is about bulding highly reliable, self-healing, operating system.
I will consider the job finished when no manufacturer anywhere makes PC with reset button
QNX
QNX jest to system czasu rzeczywistego, ktorego początki sięgają 1980 roku.
System
czasu rzeczywistego, w tym kontekscie, oznacza, że system jest
zobowiazany aby każde zadanie było wykonane w ściśle określonym
terminie.
Jest to przykład systemu komercyjnego opartego na mikrojądrze.
Jego targetem są głównie systemy wbudowane, wymagające niezawodności i dotrzymywania terminów.
QNX jest wykorzystywany w takich urządzeniach jak:
- Systemy bezzałogowego sterowania samolotami
- Akustyczne systemy śledzenia czołgów
- Radiostacje wojskowe
- Nadajniki szerokopasmowe do przekazywania danych
- Autonomiczne układy do pracy pod wodą
- Systemy sterowania bronią przeciwpancerną
- Kontrolery w systemach aeronautycznych
- Systemy globalnego pozycjonowania GPS dla wojsk naziemnych
- Systemy sterowania lądowaniem pojazdów latających
- Wojskowe satelity meteorologiczne
- urządzenia inteligentne
- sztuczne organy
- elektrownie atomowe w Kanadzie
Jądro QNXa zawiera:
- IPC
- CPU scheduler
- Obsługę przerwań
- Liczniki czasu
Hurd
- 1983: Richard Stallman founds the GNU project.
- 1988: Decision is made to use Mach 3.0 as the kernel.
- 1991: Mach 3.0 is released under compatible license.
- 1991: Thomas Bushnell, BSG, founds the Hurd project.
- 1994: The Hurd boots the first time.
- 1997: Version 0.2 of the Hurd is released.
- 1998: Debian hurd-i386 archive is created.
- 2001: Debian GNU/Hurd snapshot fills three CD images.
- 2008: The Hurd boots the second time ;)
Oczywiście ostatnia data to tylko żart. Prawdą jest jednak, że Hurd nie
doczekał się ani jednej wersji stabilnej, oraz w obecnym stanie nie
obsługuje kontrolerów SATA, w związku z czym jest nie do zastosowania w
komputerach domowych.
A co na to MS?
Microsoft, który wie jak trudno pielęgnować kod systemu
monolitycznego, także próbował stworzyć własny system oparty na
mikrojądrze.
Miał nim być WinNT a dokładniej wersja 3.1, jednakże zamysł koncepcyjny
spowodował powstanie tzw. jądra hybrydowego, a pomysł utworzenia
Windowsa opartego na mikrojądrze został chwilowo zarzucony.
Pojawił się ponownie w projekcie o nazwie Singularity.
Obecnie jest dostępna wersja 2.0 wydana w listopadzie 2008 roku.
Singularity Research Development Kit jest dostepny jako Shared Source,
co pozwala na niekomercyjne, naukowe wykorzystanie żródła.
Monolit vs mikrojądro
Po takiej dawce informacji możemy udzielić odpowiedzi na zadane wcześniej pytania._
Zatem co wygrywa w pojedynku mono vs. mikro
Porównanie koncepcji
Mikrojądro | Jądro monolitowe |
- mały rozmiar kodu źródłowego
- łatwiejsze wykrywanie błędów
- błędy w sterownikach nie powodują "crash'u" całego systemu
- duży narzut systemowy na wykonanie aplikacji
- ogromna ilość komunikatów synchronizujących
- duża ilość komunikacji międzyprocesowej, wąskie gardło systemu
|
- brak potrzeby bardzo szybkiej komunikacji międzyprocesowej
- mniejszy narzut systemowy na sys_call
- większy kod jądra - więcej miejsca na błędy
- istnieje standardowy zestaw sterowników w jądrze
- dużo łatwiejsze w implementacji
|
Jak działają systemy z mikrojądrem?
Architektura Windows NT
Modularna budowa - podzielone na składowe odpowiadające za udostępnianie określonych funkcji.
Dwie główne części: podsystemy pracujące w trybie użytkownika i elementy trybu jądra.
Tryb użytkownika:
- Podsystemy środowiska: uruchamianie programów pod różne systemy
- win32
- OS/2
- POSIX
- kompatybilność, rozszerzalność, niezawodność.
- Podsystemy wewnętrzne: wykonują pewne funkcje systemu operacyjnego w imieniu systemu środowiska.
- Bezpieczeństwo: udzielanie bądź odmowa dostępu do kont użytkowników, dostęp do zasobów, rozpoczyna proces uwierzytelniania
- Usługa serwera: pozwala komputerowi na udostępnianie usług sieciowych
- Usługa stacji roboczej: dostęp komputera do sieci
Tryb jądra:
- Warstwa abstrakcji sprzętu (HAL): oddziela pozostałą część systemu od architektury sprzętowej ukrywając jej szczegóły
- Mikrojądro: serce systemu Windows NT
- wykonuje większość zadań tradycyjnego mikrojądra
- może być wykonywane jednocześnie na wielu procesorach
- nie może zostać wywłaszczone
- wyraźnie oddzielone od Wykonywania, cecha mikrojąder
- Wykonywanie (Executive): grupa wielu podsystemów realizujących żądania podsystemów trybu użytkownika, między innymi
- Menedżer wejścia/wyjścia
- Menedżer obiektów: usługa zarządzająca zasobami, zapobiega powielaniu tego typu funkcjonalności w innych podsystemach Wykonania
- Menedżer procesów
- Monitor powiązań bezpieczeństwa: decyduje czy zasób ma być dostępny dla danego użytkownika
- Menedżer pamięci wirtualnej
- Local
prcedure call: udostępnia porty komunikacyjne używane przez podsystemy
trybu użytkownika do komunikacji ze swoimi klientami oraz przez
podsystemy Wykonania do komunikacji z podsystemami trybu użytkownika.
Transparent Distributed Processing (QNX)
TDP - ( protokół / moduł ) łączący jądra systemów w sieci,
powodujący że wszystkie usługi systemowe dostępne są przez ten sam
mechanizm, niezależnie od tego z jakiej jednostki (maszyny) są
wywoływane.
Możliwości jakie to stwarza:
- on - służy do tworzenia procesu na konkretnej maszynie
- //1/bin/diff //2/etc/passwd //3/etc/passwd
- na lokalnej maszynie wykonuje proces porównania plików /etc/passwd z
maszyn 2 i 3 wykorzystując program diff znajdujący się na maszynie 1
- slay proces -n 1 - wysłanie sygnału SIGTERM do procesu "proces", działającego na maszynie 1
- //1 cp plik.c //4/dev/par1 - na maszynie 1 stworzy proces kopiujący plik.c na drukarkę maszyny 4
są imponujące. Dodatkowo środowisko graficzne photon pozwala na przeciąganie aplikacji między ekranami różnych komputerów ;)
Przepływ komunikatów (Minix) - na przykładzie wywołania systemowego read
Programista wywołuje read
Od strony programisty kod wywołania wygląda następująco
count = read(fd, buffer, nbytes);
Przełożenie na język komunikatu
Funkcja read składa się z jednej linii
return(callm1(FS, READ, fd, nbytes, 0, buffer, NIL_PTR, NIL_PTR));
Skonstruowanie komunikatu
callm1 - zrób wywołanie systemowe używając komunikatu typu 1.
PUBLIC int callm1(proc, syscallnr, int1, int2, int3, ptr1, ptr2, ptr3)
int proc; /* FS or MM */
int syscallnr; /* which system call */
int int1; /* first integer parameter */
int int2; /* second integer parameter */
int int3; /* third integer parameter */
char *ptr1; /* pointer parameter */
char *ptr2; /* pointer parameter */
char *ptr3; /* pointer parameter */
{
/* Send a message and get the response. The 'M.m_type' field of the
* reply contains a value (>= 0) or an error code (<0). Use message format m1.
*/
_M.m1_i1 = int1;
_M.m1_i2 = int2;
_M.m1_i3 = int3;
_M.m1_p1 = ptr1;
_M.m1_p2 = ptr2;
_M.m1_p3 = ptr3;
return callx(proc, syscallnr);
}
Struktura _M jest de facto zmienną globalną
message _M = {0};
Wysłanie komunikatu
Funkcja callx wywołuje funkcję sendrec, natomiast ta jest napisana w assemblerze
SEND = 1
RECEIVE = 2
BOTH = 3
SYSVEC = 32
|*========================================================================*
| send and receive *
|*========================================================================*
| send(), receive(), sendrec() all save bp, but destroy ax, bx, and cx.
.globl _send, _receive, _sendrec
_send: mov cx,*SEND | send(dest, ptr)
jmp L0
_receive:
mov cx,*RECEIVE | receive(src, ptr)
jmp L0
_sendrec:
mov cx,*BOTH | sendrec(srcdest, ptr)
jmp L0
L0: push bp | save bp
mov bp,sp | can't index off sp
mov ax,4(bp) | ax = dest-src
mov bx,6(bp) | bx = message pointer
int SYSVEC | trap to the kernel
pop bp | restore bp
ret | return
Odbiór komunikatu przez jądro - weryfikacja i przesłanie dalej
Komunikat po stronie jądra odbiera funkcja s_call ładowana w main():
set_vec(SYS_VECTOR, s_call, base_click);
Funkcja s_call (w assemblerze) zachowuje stan procesora, po czym wywoluje sys_call
07477 /*===========================================================================*
07478 * sys_call *
07479 *===========================================================================*/
07480 PUBLIC int sys_call(call_nr, src_dst, m_ptr)
07481 int call_nr; /* system call number and flags */
07482 int src_dst; /* src to receive from or dst to send to */
07483 message *m_ptr; /* pointer to message in the caller's space */
07484 {
07489 register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */
07490 int function = call_nr & SYSCALL_FUNC; /* get system call function */
07491 unsigned flags = call_nr & SYSCALL_FLAGS; /* get flags */
07492 int mask_entry; /* bit to check in send mask */
07493 int result; /* the system call's result */
07494 vir_clicks vlo, vhi; /* virtual clicks containing message to send */
07550 /* Now check if the call is known and try to perform the request. The only
07551 * system calls that exist in MINIX are sending and receiving messages.
07552 * - SENDREC: combines SEND and RECEIVE in a single system call
07553 * - SEND: sender blocks until its message has been delivered
07554 * - RECEIVE: receiver blocks until an acceptable message has arrived
07555 * - NOTIFY: nonblocking call; deliver notification or mark pending
07556 * - ECHO: nonblocking call; directly echo back the message
07557 */
07558 switch(function) {
07559 case SENDREC:
07560 /* A flag is set so that notifications cannot interrupt SENDREC. */
07561 priv(caller_ptr)->s_flags |= SENDREC_BUSY;
07562 /* fall through */
07563 case SEND:
07564 result = mini_send(caller_ptr, src_dst, m_ptr, flags);
07565 if (function == SEND || result != OK) {
07566 break; /* done, or SEND failed */
07567 } /* fall through for SENDREC */
07568 case RECEIVE:
07569 if (function == RECEIVE)
07570 priv(caller_ptr)->s_flags >= ~SENDREC_BUSY;
07571 result = mini_receive(caller_ptr, src_dst, m_ptr, flags);
07572 break;
07573 case NOTIFY:
07574 result = mini_notify(caller_ptr, src_dst);
07575 break;
07576 case ECHO:
07577 CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr);
07578 result = OK;
07579 break;
07580 default:
07581 result = EBADCALL; /* illegal system call */
07582 }
07583
07584 /* Now, return the result of the system call to the caller. */
07585 return(result);
07586 }
Funkcja generalnie upewnia się, że komunikat jest poprawny i przekazuje go dalej przez sendrec.
Odbiór komunikatu przez serwer systemu plików
Komunikat ten odbierany jest przez obsługę systemów plików (która
decyduje jaką funkcję należy wykonać po otrzymaniu jakiego komunikatu)
24075 if (call_nr < 0 || call_nr >= NCALLS) {
24076 error = ENOSYS;
24077 printf("FS, warning illegal %d system call by %d\n", call_n
24078 } else if (fp->fp_pid == PID_FREE) {
24079 error = ENOSYS;
24080 printf("FS, bad process, who = %d, call_nr = %d, slot1 = %d
24081 who, call_nr, m_in.slot1);
24082 } else {
24083
I w przypadku read() wywoła się do_read()
PUBLIC int do_read()
{
return(read_write(READING));
}
Wykonanie
A funkcja read_write robi już to co trzeba.
System plików - translatory (QNX/Hurd)
Linux
Na linuxie dostępny jest system montowania katalogów. Jeżeli jądro obsługuje system plików XXX to możemy wykonać
mount -t XXX /path/device /another/path
Aby sprawić by w katalogu /another/path dostępna była zawartość
urządzenia /path/device zinterpretowana w odpowiedni (XXX) sposób.
Hurd
W mikrojądrach obsługa systemu plików odbywa się przez
program zewnętrzny, który decyduje należy zrobić z wywołaniami
systemowymi dotyczącymi systemu plików. Może (jak w wywyższym
przykładzie wywołania read() w minixie) sam zająć się jego realizacją,
lub zlecić ją komuś innemu.
W systemach takich jak QNX/Hurd użytkownik może (analogicznie
do mount-owania) zdefiniować jaki program (translator) ma obsługiwać
jakie odwołania. Przykładowo mount -t iso9660 /dev/cdrom /mnt
przetłumaczone na język Hurda brzmi
settrans -a /cdrom /hurd/iso9660fs /dev/hd1
Gdzie /hurd/iso9660fs jest programem do obsługi tego systemu
plików. Niewątpliwie idea translatorów wydaje się ogólniejsza i
bardziej praktyczna - dzięki niej, możemy na przykład łatwo stworzyć
translator obsługujący kopiowanie za pomocą scp, tak by dla użytkownika
wyglądało jak operowanie na lokalnym systemie plików.
FUSE
Odpowiedzią na tę potrzebę w Linuxie jest FUSE -
Filesystem in USErspace, który pokrywa wszystkie możliwości
translatorów Hurda :)
Możemy zdefiniować kilka funkcji m.in.
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if(strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
return 0;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper);
}
I cieszyć się rezultatem:
~/fuse/example$ mkdir /tmp/fuse
~/fuse/example$ ./hello /tmp/fuse
~/fuse/example$ ls -l /tmp/fuse
total 0
-r--r--r-- 1 root root 13 Jan 1 1970 hello
~/fuse/example$
QNX
W QNXie jest lepiej, ze względu na TDP. Ponieważ nie ma tam
rozróżnienia na komunikaty przechodzące tylko w obrębie systemu i
komunikaty wychodzące do innej maszyny, wywołania systemowe mogą zostać
obsłużone przez inne komputery.
Dlatego ścieżka pliku ma w QNXie postać //n/[katalog]/plik, gdzie n jest numerem maszyny. Jeżeli //n się pominie, to ścieżka będzie odnosić się do pliku na maszynie lokalnej.
W QNXie nic nie stoi na przeszkodzie, by stworzyć link symboliczny do pliku na innym komputerze.
Mountowanie w QNXie zostało przystosowane do unixowego
(linuxowego) sposobu używania. Polecenie mount -t iso9660 /dev/cd0 /cd0
wykonuje: mount_iso9660 /dev/cd0 /cd0
Metody komunikacji
Spotkania (QNX)
- Send(T2,M,Mr) - wysyłanie wiadomości M do procesu T2 i zawieszenie procesu nadającego do czasu otrzymania odpowiedzi Mr
- Receive(T1,M) - odebranie wiadomości M od procesu T1
- Reply(T1,M) - wznowienie procesu T1 i przekazanie mu odpowiedzi Mr
Wiadomości w tym schemacie przenoszone są bezpośrednio z pamięci
jednego procesu do pamięci drugiego (ewentualnie przez sieć, jeśli
procesy znajdują się na różnych maszynach).
Depozyty (QNX)
System depozytów służący do informowania procesów o zaistniałych zdarzeniach zewnętrznych.
- qnx_proxy_attach(T,M) - utworzenie depozytu z wiadomością M
- qnx_proxy_detach(P) - usunięcie depozytu P
- Trigger(P) - pobudzenie depozytu P i wysłanie wiadomości do procesu właściciela
-
Właściciel depozytu może w dowolnym momencie wykonać Receive na dypozycie (i ew. zawiesić się w oczekiwaniu na pobudzenie).
Sygnały (QNX)
Sygnały - działające prawie dokładnie jak w Linuxie.
Obsługa przerwań (QNX)
Jądra QNXa zajmuje się obsługą przerwań, ale nie wyklucza ono obsługi przerwać przez serwery.
Funkcja InterruptAttach pozwala na zdefiniowanie funkcji obsługi przerwania.
W L4 przekazywaine informacji o przerwaniu odbywa się przez IPC
QNX vs minix
Operacja Send jest blokująca, co może
doprowadzić do niemiłych sytuacji zakleszczenia. Złośliwy klient usługi
mógłby z łatwością przeprowadzić atak DoS polegający na zakleszczeniu
serwera. QNX i minix proponują dwa rozwiązania tego problemu:
- QNX,L3 - po ustalonym czasie zwalnia instrukcję Send nawet jeśli nie otrzyma ona odpowiedzi (czyli operacje są tylko czasowo blokujące)
- Minix,L4 - można wywołać Send z flagą oznaczającą, iż Send spodziewa się odpowiedzi natychmiastowo. Jeśli jej nie otrzyma: kończy się z błędem.
Adaptive Partition Schedulers (QNX)
RTOS - Real-Time Operating
System (system, którego poprawność zależy nie tylko od wyniku, ale od
momentu w którym ten wynik zostanie dostarczony).
Opóźnienie obsługi przerwania w QNXie, przy dosyć wolnej maszynie jest rzędu 10 mikrosekund.
Przy obciążeniu systemu ważne jest, żeby krytyczne procesy dostawały co
pewien czas czas procesora, pomimo tego, że mają niższy priorytet niż
inne procesy. AP - powoduje, że jest zarezerwowany czas procesora dla
procesów krytycznych, jednocześnie nie blokując na stałe określonego
procentu czasu CPU.
Testy wydajności
W jądrze monolitycznym usługa przez pojedyncze
wywołanie systemowe, wymagające dwukrotnego przełączenia kontekstu.
W architekturze mikrojądrowej usługa jest osiągana poprzez wysłanie do
serwera komunikatu i odbiór wyniku w innym komunikacie.
Może to prowadzić do zwiększenia kosztu wykonania operacji o dodatkowe
przełączanie kontekstu oraz kopiowanie danych pomiędzy przestrzeniami
adresowymi procesów.
Wczesne systemy operacyjne operacyjne oparte na mikrojądrze miały
bardzo słabą wydajność, MkLinux oparty na jądrze Mach był średnio o ok.
50% wolniejszy od monolitycznego linuxa.
Problemy z
wydajnością były jednak spowodowane kiepską architekturą i
implementacją.
Poprzez staranną implementację jądro L4 miało o rząd wielkości szybszą
komunikację międzyprocesową, dzięki czemu uzyskiwało wyniki tylko o
kilka procent gorsze od jąder monolitycznych.
Platforma testowa : notebook z procesorem AMD Turion X2 1.8 Ghz, 1GB
RAM
Testowane systemy:
- Jądro monolityczne : Debian GNU/Linux
- Jądro hybrydowe : Windows NT 6.0 (Vista)
- Mikrojądro : QNX Neutrino RTOS
Każdy system był uruchamiany bezpośrednio na maszynie, wszystkie
operacje na plikach wykonywane przy użyciu systemu plików FAT32.
Wszystkie testy, z wyjątkiem ostatniego, były wykonywane kilkukrotnie i
podana wartość jest średnią artmetyczną otrzymanych wyników.
Czas mierzony był przy pomocy oprogramowania, więc wyniki nie są
obarczone błędem ludzkim.
Wyniki testów to czas działania podany w sekundach, im mniejsza wartość
tym lepszy wynik.
Test 1: Sito Eratostenesa. Program wykonujący obliczenia, brak operacji wejścia\wyjścia. Duże wykorzystanie pamięci.
Windows najszybciej, mikrojądro 30% wolniej od monolitu.
Test 2: To samo sito Eratostenesa, ale dla mniejszych liczb i
wywołane 1000 razy. Dużo operacji tworzenia nowego, małego procesu.
Linux bezkonkurencyjny, 4x szybszy niż QNX i 10x szybszy niż Windows.
Test 3: Program wypisujący w pętli jeden znak na ekran, wynik przekierowany do pliku. Bardzo dużo operacji wejścia/wyjścia.
Tym razem przewaga linuxa jeszcze większa, QNX bardzo wolny.
Test 4: Program wywołujący w pętli bardzo krótką funkcję systemową. Dużo przełączeń kontekstu.
Windows i Linux remis. QNX ponad 2x szybszy.
Test 5: Bardziej praktyczny. Wyszukiwanie ciągu znaków w kodzie
źródłowym dużego programu. Dużo operacji czytania z pliku oraz odwołań
do sterownika urządzenia (kod znajdował się na zewnętrznym nośniku).
Linux ponownie najlepszy, QNX najwolniej.
Screenshoty
Dodawanie translatora (HURD)
Lista procesów (HURD)
Lista procesów (QNX)
Jeśli da się grać w pokera, to z naczy, że system działa
QNX Software Development Platform