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):

  1. Wolna pamięć fizyczna jest podzielona na spójne obszary, przy czym każdy z obszarów jest maksymalny, tzn. jest otoczony zajętymi ramkami.
  2. Dla każdego obszaru pamiętamy jego początek (nr pierwszej ramki) i długość, być może coś jeszcze.
  3. Na zbiór struktur odpowiadających obszarom nałożone są następujące struktury:

  4. (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.
  5. 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).
  6. 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).
  7. 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:
  1. 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".
  2. 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.

  3. 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ń.
  4. 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