Do strony głównej modułu Pamięć
Ten dokument ma za zadanie przedstawić propozycję usprawnienia nieco tego mechanizmu wykorzystując cechę lokalności i liniowości programów, które są wykonywane w systemie.
Dla naszych potrzeb przypomnijmy kilka podstawowych własności tego mechanizmu:
Analiza tych informacji podsuwa pomysł aby starać się ograniczać ilość generowanych błędów strony. Środki służące temu nie mogą być jednak zbyt kosztowne obliczeniowo, gdyż zamiast przyspieszenia powodowałyby spowolnienie całego systemu.
Często zdarza się tak, że programy zachowują się liniowo, tzn. np.
operują na dużej tablicy w kolejności rosnących indeksów, zerują swoją
pamięć operacją memset, która także działa na kolejnych
bajtach, czy po prostu ciąg instrukcji, który wykonują ma coraz to
W takiej sytuacji można starać się przewidywać wystąpienia błędów
braku strony i nie dopuszczać do ich powstawania.
Każdy błąd wiąże się z wyznaczeniem obszaru pamięci
(vm_area_struct), którego dotyczy. Można z każdym takim
blokiem pamięci związać 2 dodatkowe liczby: adres w bloku gdzie
ostatnio wystąpił błąd strony i licznik, który mówi ile ostatnich
błędów strony tworzyło ciąg rosnący względem numerów stron.
Przy tworzeniu obszaru pamięci należy wyzerować
licznik a adres ostatniego błędu ustawić na jakąś nieosiągalną
wartość. Podczas obsługi błędu strony będziemy sprawdzać czy
jest on kolejnym w ciągu dotychczas zaobserwowanym dla danego obszaru
pamięci. Jeśli nie, to przyjmujemy że jest początkiem nowego ciągu,
w przypadku kiedy odwołanie rozszerza dotychczasowy ciąg i o ile
osiągnął on już pewną minimalną długość (np. 3), w następnym kroku
zasymulujemy dodatkowe błędy strony. Ma to na celu zapobieżenie
powstawaniu kolejnych błędów gdyż następne strony będą już
się znajdować w pamięci operacyjnej. Ilość symulowanych błędów
najlepiej wyznaczyć doświadczalnie, gdyż ta liczba jest bardzo silnie
zależna od rodzaju procesora, dostępnej pamięci, szybkości urządzeń
wejścia/wyjścia itp. Proponuję rozwiązanie wykładnicze, tzn. jeśli
mamy ciąg o długości 3, w następnym kroku doczytujemy 3 strony,
następnie 6, 12 itd. Oczywiście należy przewidzieć górne
ograniczenie, które będzie swego rodzaju rekompensatą w przypadku
kiedy nasze przewidywanie okaże się nietrafne i strona, którą
wczytamy okaże się niepotrzebna.
Po wyznaczeniu odpowiedniej struktury Po
wprowadzeniu niezbędnych zmian w kodzie należy zrekompilować jądro, a
plik wynikowy
Nieco mniej polepszenie wydajności będzie widoczne w przypadku
konieczności doczytania stron z dysku, gdyż opóźnienia z tym związane
z transmisjami dyskowymi są zbyt duże w stosunku do szybkości
dzisiejszych procesorów.
Przykłady programów testujących:
test1.cpp - przykład programu, dla
którego spodziewamy się znacznej poprawy wydajności. Alokuje on duzy
blok pamięci i wypełnia go danymi.
test2.cpp - przykład programu, którego
zadaniem jest sprawdzenie czy przedstawione rozwiązanie nie powoduje
znaczącego spowolnienia typowych operacji na pamięci (niezgodnych z
przyjętym założeniem o liniowości). Program ten alokuje duży blok
pamięci i wypełnia go danymi, ale w losowej kolejności.
test3.cpp - program generuje
błędy strony o numerach różniących się o 2, czyli 1, 3, 5, 7, ...
Jeśli będziemy zawsze generować parzystą ilość błędów braku strony
to także uzyskamy co najmniej 50% redukcji ilości błędów braku
strony, ponieważ zawsze po odwołaniu się do strony o numerze
Proponowane zmiany w systemie
Proponuję następujące rozwiązanie, które moim zdaniem przyczyni się
do przyspieszenia funkcjonowania całego systemu. Różnica w szybkości
nie będzie być może oszałamiająca (gdyż to nie procesor jest główną
przyczyną dla której systemy operacyjne nie osiągają pełnej wydajności),
niemniej jednak może być odczuwalne, szczególnie na wolniejszych
komputerach wyposażonych w mniejszą ilość pamięci operacyjnej.
Sposob wprowadzenia zmian
Należy uzupełnić strukturę vm_area_struct
(plik include/linux/mm.h
) o dodatkowe pola, po czym
zmodyfikować procedurę do_page_fault
znajdującą się w pliku arch/i386/mm/fault.c
.
Inicjalizację dodatkowych pól struktury vm_area_struct
najlepiej umieścić w funkcji insert_vm_struct
w pliku
mmap.c
.
vm_area_struct
odpowiadającej adresowi liniowemu, należy zastosować opisany wyżej
algorytm do policzenia ilości symulowanych błędów strony. Należy tu
wziąć pod uwagę także rozmiar struktury vm_area_struct aby przez
przypadek nie doprowadzić do powstania błędu krytycznego. zImage
dodać do pliku startowego
/etc/lilo.config
, po czym należy zamknąć i ponownie
wystartować system.
Przewidywane rezultaty
Należy się spodziewać, że taka zmiana w systemie spowoduje wzrost
wydajności programów, które operują na dużych obszarach pamięci,
szczególnie jeśli często wykonują operację przydziału pamięci
malloc()
. Wtedy wystąpi bardzo wiele błędów związanych z
nieprzydzielonymi stronami. Dzięki wcześniejszemu ich zasymulowaniu
będą możliwe znaczne oszczędności czasowe.
2*n+1
, strona o numerze 2*n+2
będzie już w
pamięci