Okładka... | >>> |
---|
Autor:
Tomasz Stachowicz
ts181294@zodiac.mimuw.edu.pl
2001.12.19
Spis treści:
>>> |
Wprowadzenie... | >>> |
---|
Autor: Jeff Bonwick (Sun Microsystems)
The Slab Allocator: An Object-Caching Kernel Memory Allocator
Obiekt = obszar danych o ustalonym rozmiarze
Problem: częste przydzielanie i zwalnianie obiektów standardowym algorytmem było kosztowne
Rozwiązanie: zamiast niszczenia obiektu - wstawianie go do cache'a, zamiast tworzenia - pobieranie z cache'a
Zarys ogólny... | >>> |
---|
Przydzielanie i zwalnianie obiektów następuje poprzez cache'e.
Każdy cache ma ustalony rozmiar obiektów i typ pamięci.
Dostępne operacje:
|
|
Zarys ogólny cd... | >>> |
---|
Każdy cache zawiera listę tafli (ang. slab).
Tafla to ciągły blok pamięci obejmujący jedną lub kilka ramek, podzielony na obiekty tego samego rozmiaru.
W obrębie jednego cache'a tafle są posortowane według następującej reguły:
najpierw tafle pełne, potem niepełne, na końcu puste.
Organizacja wewnętrzna tafli zależy od rozmiaru obiektów:
PAGE_SIZE/8
, deskryptory (struktury opisujące)
tafli i obiektów znajdują się w tym samym bloku pamięci, co same obiekty,
Ilustracja... | >>> |
---|
Struktury... | >>> |
---|
typedef unsigned int kmem_bufctl_t; typedef struct slab_s { struct list_head list; unsigned long colouroff; void *s_mem;wskaźnik do pierwszego obiektuunsigned int inuse;liczba aktualnie używanych obiektówkmem_bufctl_t free;indeks pierwszego wolnego obiektukmem_bufctl_t nextfree[num];jeśli i-ty obiekt jest używany, to nextfree[i] zawiera indeks następnego wolnego obiektu lub BUFCTL_END, gdy jest ostatnim wolnym} slab_t;
Uwaga! W rzeczywistości w strukturze nie występuje zmienna nextfree
(gdyż nie ma z góry ustalonego rozmiaru). Jednak w źródłach Linuksa struktury
slab_s
używa się tak, jakby ta zmienna w niej występowała i miała rozmiar
num
ze struktury kmem_cache_s
, czyli liczba obiektów w tafli.
Struktury cd... | >>> |
---|
struct kmem_cache_s { struct list_head next;następny deskryptor cache'astruct list_head slabs;lista tafli w danym cache'ustruct list_head *firstnotfull;pierwsza niepełna taflaunsigned int objsize;rozmiar obiektuunsigned int num;liczba obiektów w tafliunsigned int gfporder;2^gfporder == liczba ramek na taflękmem_cache_t *slabp_cache;cache cache'avoid (*ctor)(...);konstruktor obiektuvoid (*dtor)(...);destruktor obiektu}; #define MAX_OBJ_ORDER 52^MAX_OBJ_ORDER == maksymalna liczba ramek na obiekt
Cache'e ogólnego przeznaczenia... | >>> |
---|
typedef struct cache_sizes { size_t cs_size;Tablicarozmiar cache'akmem_cache_t *cs_cachep;wskaźnik na cache o tym rozmiarzedla zwykłej pamięcikmem_cache_t *cs_dmacachep;dla pamięci DMA} cache_sizes_t; static cache_sizes_t cache_sizes[] = { { 32, NULL, NULL}, { 64, NULL, NULL}, ..... { 65536, NULL, NULL}, {131072, NULL, NULL}, { 0, NULL, NULL} };
cache_sizes
jest inicjowana przy starcie systemu zestawem
cache'y ogólnego przeznaczenia.
Algorytm kmalloc... | >>> |
---|
kmalloc(size_t size, int flags) w tablicy cache_sizes znajdź pierwszy pasującą pozycję lub zwróć błąd z tej pozycji wybierz odpowiedni cache \ - w zależności od tego, czy flaga GFP_DMA jest w flags wywołaj kmem_cache_alloc dla tego cache'a i zwróć wynik kmem_cache_alloc(kmem_cache_t *cachep, int flags) powtarzaj zablokuj przerwania jeśli jest niepełna tafla, to weź adres pierwszego wolnego obiektu w tej tafli usuń go z listy wolnych odblokuj przerwania zwróć adres obiektu wpp odblokuj przerwania spróbuj dodać nową taflę do cache'a jeśli się nie udało, to zwróć błąd
Algorytm kfree... | >>> |
---|
kfree (const void *objp) zablokuj przerwania znajdź cache, do którego należy obiekt wywołaj kmem_cache_free dla tego cache'a i obiektu odblokuj przerwania kmem_cache_free(kmem_cache_t *cachep, void *objp) znajdź taflę zawierającą dany obiekt wstaw obiekt do listy wolnych w tej tafli przesuń tą taflę na liście tak, by zachowany był porządek: \ najpierw tafle pełne, później niepełne, na końcu puste
Różnice między 2.2 a 2.4... | >>> |
---|
2.2 | 2.4 |
dma i normal - różne tafle, ale w obrębie tego samego cache'a | dla każdego rodzaju pamięci (normal, dma, highmem) osobny cache |
deskryptor tafli na końcu tafli | na początku |
brak optymalizacji dla SMP | optymalizacje dla SMP |
nie można usunąć cache'a z pamięci | można |
>>> |
Wprowadzenie... | >>> |
---|
2 rodzaje organizacji:
Każde urządzenie wymiany składa się z sekwencji slotów stron (ang. page slots), czyli bloków do przechowywania wymienianych stron.
swap_info
- tablica z informacjami o urządzeniach wymiany;
max rozmiar określony przez stałą MAX_SWAPFILES
(zwykle 8);
Informacje o urządzeniu opisane są stukturą swap_info_struct
.
Struktury... | >>> |
---|
struct swap_info_struct { unsigned int flags;czy używane i czy można zapisywaćkdev_t swap_device;numer urządzeniastruct dentry * swap_file;i-węzeł urządzeniaunsigned short * swap_map;wskaźnik do tablicy licznikówodwołań do slotów stronunsigned char * swap_lockmap;wskaźnik do tablicy blokadbitowych slotów stronunsigned int lowest_bit;od tej pozycji należy zacząćszukanie wolnego slotuunsigned int highest_bit;na tej pozycji należy zakończyćunsigned int cluster_next;następny slot do sprawdzeniaprzy szukaniu wolnegounsigned int cluster_nr;liczba używanych slotówint prio;priorytet urządzeniaint pages;ile wolnych slotów na urządzeniuunsigned long max;rozmiar urządzenia wymiany w stronachint next;następne urządzeniena liście priorytetowej}
Ilustracja... | >>> |
---|
Zmienne globalne... | >>> |
---|
nr_swapfiles
- maksymalny indeks urządzenia wymiany w tablicy swap_info
nr_swap_pages
- całkowita liczba wolnych slotów we wszystkich urządzeniach wymiany
Informacje o urządzeniach wymiany znajdują się na liście uporządkowanej wg priorytetów.
Indeks pierwszego elementu tej listy trzymany jest w zmiennej swap_list
typu:
struct swap_list_t { int head;głowa listyint next;następne urządzenie do rozpatrzenia(patrz: Wybór urządzenia do zrzucenia strony)}
Dodawanie urządzenia wymiany... | >>> |
---|
int sys_swapon(const char *specialfile, int swap_flags)
specialfile
- ścieżka do pliku urządzenia (partycji) lub zwykłego pliku
swap_flags
- jeśli ustawiona flaga SWAP_FLAG_PREFER
,
to najmłodsze 15 bitów określa priorytet urządzenia
Funkcja znajduje pierwszy wolne miejsce w tablicy swap_info
, wstawia tam
dane urządzenie, inicjuje tablicę liczników i tablicę blokad, zwiększa
liczbę wolnych slotów (nr_swap_pages
), wstawia urządzenie do listy priorytetowej.
Jeśli w swap_flags
bit SWAP_FLAG_PREFER
jest zgaszony,
to priorytet urządzenia nadawany jest zgodnie z licznikiem least_priority
,
zmniejszanym po każdym wykorzystaniu.
Usuwanie urządzenia wymiany... | >>> |
---|
int sys_swapoff(const char *specialfile)
Funkcja usuwa urządzenie z listy i ustawia mu flagę, że nie można zapisywać.
Przy pomocy try_to_unuse()
próbuje zwolnić wszystkie strony
zrzucone na to urządzenie. Jeżeli się uda, zwalnia odpowiednie pole
w tablicy swap_info
i ustawia flagę, że urządzenie jest nieużywane.
Wpp. wstawia urządzenie z powrotem do listy i wychodzi z błędem.
Wybór urządzenia wymiany... | >>> |
---|
Wybór urządzenia odbywa się w funkcji
unsigned long get_swap_page(void)
służącej do przydzielenia wolnego slotu strony.
W celu znalezienia urządzenia, funkcja wykonuje dwa przejścia po liście urządzeń.
Za pierwszym razem zaczyna od swap_list.next
i idzie tak długo,
aż zmieni się priorytet lub skończy lista. Następnie rozpoczyna od początku listy
(swap_list.head
) i idzie aż do końca.
Jeśli w ciągu obu przejść nie znajdzie urządzenia, to znaczy że nie ma wolnego miejsca
i wychodzi z błędem. Wpp. zwraca zakodowany numer urządzenia i numer slotu.
Pole swap_list.next
ustawiane jest na następnik tego urządzenia,
chyba że było ono ostatnim o danym priorytecie, wówczas
swap_list.next = swap_list.head
.
That's all folks... |
---|