Do spisu treści rozdziału 4
Zadanie:
Zmiana sposobu zarządzania ramkami pamięci głównej.
Przy przydzielaniu/zwalnianiu ramek pamięci głównej Linux stosuje algorytm
bliźniaków ("buddy", p. wykład). Wykorzystane algorytmy są na tyle niejasne
i skomplikowane, że aż prosi się, by je zmienić. Zadanie polega na zastąpieniu
użytych struktur danych i algorytmów innymi (moim zdaniem możliwe, że szybszymi).
Proponuję następujące rozwiązanie (inne, niż dotychczas stosowane):
-
Wolna pamięć fizyczna jest podzielona na spójne obszary, przy czym każdy
z obszarów jest maksymalny, tzn. jest otoczony zajętymi ramkami.
-
Dla każdego obszaru pamiętamy jego początek (nr pierwszej ramki) i długość,
być może coś jeszcze.
-
Na zbiór struktur odpowiadających obszarom nałożone są następujące struktury:
(a) lista jednokierunkowa, posortowana po początkach obszarów,
(b) drzewo AVL, utworzone ze względu na początki obszarów,
(c) być może jeszcze jakieś struktury poprawiające efektywność algorytmów,
zależnie od woli rozwiązującego.
-
Zajmowanie pojedynczej ramki polega na zabraniu jej z pierwszego obszaru
na liście (a). Jeżeli obszar był jednoramkowy, należy go usunąć ze struktury,
co wiąże się z koniecznością zbalansowania drzewa (b).
-
Zwalnianie pojedynczej ramki polega na znalezieniu przy pomocy drzewa (b)
obszaru, do jakiego można ją "przykleić" i dodanie do niego tej ramki.
Gdy ramka daje się "dokleić" do dwóch sąsiednich obszarów (sąsiada danego
obszaru można łatwo znaleźć przy pomocy listy (a)), należy je połączyć,
gdy nie da się "dokleić" do żadnego - utworzyć nowy obszar. W razie potrzeby
zbalansować drzewo (b).
-
Operacje na ramkach pamięci fizycznej to jedne z najczęściej wykonywanych
operacji w całym systemie (np. przy każdym błędzie braku strony, ale nie
tylko). Dlatego przy implementowaniu powyższych operacji należy zwrócić
baczną uwagę na efektywność.
Uwagi:
-
Jeśli ktoś uważa, ze używanie drzew AVL w jądrze systemu operacyjnego to
przejaw manii, odsyłam do pliku mm/mmap.c, gdzie takie drzewa
sa użyte, a autorzy wyjaśniają, że dzieje się tak dla poprawy efektywności.
W ogólności nieprawdą jest stwierdzenie: "Algorytmy o najlepszej złożoności
są najmniej efektywne".
-
Wszystkie procesy zajmują i zwalniają tylko pojedyncze ramki. Niestety,
z naszego algorytmu będzie korzystać również jądro, które może zażądać
większej porcji ramek i oczekuje, że będzie ona spójna w pamięci fizycznej.
Między innnymi dlatego zaproponowana struktura jest tak skomplikowana.
Przy przydziale większego bloku ramek, należy przeszukać strukturę
w celu znalezienia odpowiedniego obszaru. Od implementatora zależy, jakiej
strategii użyć ("pierwszy pasujący", "najlepszy pasujący" czy jakiejś ich
kombinacji). Należy jednak pamiętać o konieczności zapewnienia efektywności
użytych algorytmów.
Sugerowałbym rozważenie zadania dodatkowej struktury na zbiorze wolnych
obszarów w celu poprawienia efektywności poszukiwań.
-
Wydaje się, że żądanie przydziału pojedynczej ramki występuje w systemie
znacznie częściej niż przydział bloku ramek. Należy więć zwrócić
szczególną uwagę na efektywne postępowanie w tym wypadku.
Miarą jakości rozwiązania będzie jego efektywność. W szczególności, ostatecznym
celem jest zaimplementowanie rozwiązania, które w pewnych sytuacjach będzie
działało szybciej niż dotychczasowe oraz podanie tych sytuacji.
Przedmiotem oceny jest działające jądro po dokonaniu koniecznych zmian,
opis rozwiązania wraz z uzasadnieniem i wskazaniem miejsc w kodzie źrodłowym
jądra, w których zostały dokonane zmiany, a także propozycja sposobu testowania
wydajności rozwiązania i wyniki testów.
Autor: Bartosz Klin