Jaka jest różnica między vmalloc i kmalloc?

113

Przeszukałem go i zauważyłem, że większość ludzi opowiada się za używaniem kmalloc, ponieważ masz gwarancję, że otrzymasz ciągłe fizyczne bloki pamięci. Jednak wydaje się również, że kmallocmoże się nie powieść, jeśli nie można znaleźć ciągłego fizycznego bloku, którego chcesz.
Jakie są zalety posiadania ciągłego bloku pamięci? W szczególności, dlaczego miałbym mieć ciągły fizyczny blok pamięci w wywołaniu systemowym ? Czy jest jakiś powód, dla którego nie mogłem po prostu użyć vmalloc?
Wreszcie, jeśli miałbym przydzielić pamięć podczas obsługi wywołania systemowego, czy powinienem określić GFP_ATOMIC? Czy wywołanie systemowe jest wykonywane w kontekście atomowym?

GFP_ATOMIC
Alokacja ma wysoki priorytet i nie zasypia. Jest to flaga używana w obsłudze przerwań, dolnych połówkach i innych sytuacjach, w których nie możesz spać.

GFP_KERNEL Jest to normalna alokacja i może blokować. To jest flaga używana w kodzie kontekstu procesu, gdy można bezpiecznie spać.

Wolna pamięć
źródło
Dobry artykuł na temat vmalloc i kmalloc http://learnlinuxconcepts.blogspot.in/2014/02/linux-memory-management.html
JIN007
4
Ten artykuł zawiera bzdury typu: „Generalnie architektura 32-bitowa ma rozmiar strony 4 KB, a architektura 64-bitowa ma rozmiar strony 8 KB”. Nie przeczytałem go do końca, ale nie nazwałbym tego „dobrym”, ani nawet nie zaufałbym ani słowu.
Alexandro Sánchez
1
Uwaga (częściowo powiązane): vmallocjest szybsze z Kernel 5.2 (Q2 2019)
VonC

Odpowiedzi:

96

Musisz tylko martwić się o używanie fizycznie ciągłej pamięci, jeśli bufor będzie dostępny przez urządzenie DMA na fizycznie adresowanej magistrali (takiej jak PCI). Problem polega na tym, że wiele wywołań systemowych nie ma możliwości sprawdzenia, czy ich bufor zostanie ostatecznie przekazany do urządzenia DMA: kiedy przekażesz bufor do innego podsystemu jądra, naprawdę nie możesz wiedzieć, dokąd zmierza. Nawet jeśli jądro nie używa dziś bufora dla DMA , może to zrobić w przyszłości.

vmalloc jest często wolniejszy niż kmalloc, ponieważ może być zmuszony do ponownego odwzorowania przestrzeni bufora na praktycznie ciągły zakres. kmalloc nigdy nie zmienia mapowania, chociaż jeśli nie zostanie wywołany z GFP_ATOMIC, kmalloc może blokować.

kmalloc ma ograniczony rozmiar bufora, który może dostarczyć: 128 KB *) . Jeśli potrzebujesz naprawdę dużego bufora, musisz użyć vmalloc lub innego mechanizmu, takiego jak rezerwowanie dużej ilości pamięci podczas rozruchu.

*) Tak było w przypadku wcześniejszych jąder. Na najnowszych jądrach (testowałem to na 2.6.33.2), maksymalny rozmiar pojedynczego kmalloc wynosi do 4 MB! (Napisałem dość szczegółowy post na ten temat .) - kaiwan

W przypadku wywołania systemowego nie musisz przekazywać GFP_ATOMIC do kmalloc (), możesz użyć GFP_KERNEL. Nie jesteś operatorem przerwań: kod aplikacji wchodzi do kontekstu jądra za pomocą pułapki, nie jest przerwaniem.

DGentry
źródło
1
Myślałem, że wywołania systemowe zostały wprowadzone przez wyzwolenie int $ 0x80? (tj. przerwanie)?
FreeMemory
2
int $ 0x80 to przerwanie programowe, zwane także pułapką. Pod pojęciem obsługi przerwań rozumie się przerwanie sprzętowe, na przykład gdy użytkownik naciska klawisz lub przesuwa ruchy.
Branan
Wywołania systemowe dotyczą przejść z przestrzeni użytkownika do jądra ... kmalloc jest używany tylko w kontekście jądra?
AIB,
3
@FreeMemory: int $ 0x80 jest specyficzne dla x86, a następnie jest to również stara metoda zastąpiona przez sysenter / syscall (na x86).
jørgensen
18

Krótka odpowiedź: pobierz sterowniki urządzeń Linux i przeczytaj rozdział o zarządzaniu pamięcią.

Poważnie, jest wiele subtelnych problemów związanych z zarządzaniem pamięcią jądra, które musisz zrozumieć - spędzam dużo czasu na debugowaniu z nim problemów.

vmalloc () jest bardzo rzadko używana, ponieważ jądro rzadko używa pamięci wirtualnej. Zazwyczaj używana jest kmalloc (), ale musisz wiedzieć, jakie są konsekwencje różnych flag i potrzebujesz strategii radzenia sobie z tym, co się dzieje, gdy się nie powiedzie - szczególnie jeśli jesteś w obsłudze przerwań, jak sugerowałeś.

Mike Heinz
źródło
1
„ponieważ jądro rzadko używa pamięci wirtualnej”, dlaczego tak jest?
Trey
Ponieważ generalnie nie chcesz, aby blok jądra czekał, aż jądro wymieni pamięć do lub z pamięci dyskowej ...
Mike Heinz
Nie, pamięć jądra przydzielona przez vmalloc nigdy nie jest wymieniana. Można wymienić tylko pamięć przestrzeni użytkownika. Przestrzeni adresowej jądra nie można zamienić, a vmalloc przydziela w przestrzeni adresowej jądra.
user2679859
13

Linux Kernel Development Robert Love (Rozdział 12, strona 244 w 3. wydaniu) odpowiada na to bardzo jasno.

Tak, w wielu przypadkach pamięć fizycznie ciągła nie jest wymagana. Głównym powodem, dla którego kmalloc jest używany częściej niż vmalloc w jądrze, jest wydajność. Książka wyjaśnia, że ​​kiedy duże fragmenty pamięci są przydzielane za pomocą vmalloc, jądro musi mapować fizycznie nieciągłe fragmenty (strony) w pojedynczy ciągły region pamięci wirtualnej. Ponieważ pamięć jest praktycznie ciągła i fizycznie nieciągłość, do tabeli stron trzeba będzie dodać kilka odwzorowań adresów wirtualnych na fizyczne. W najgorszym przypadku do tabeli stron zostanie dodana liczba mapowań (rozmiar bufora / rozmiar strony) .

Zwiększa to również presję na TLB (wpisy pamięci podręcznej przechowujące najnowsze mapowania adresów wirtualnych na fizyczne) podczas uzyskiwania dostępu do tego bufora. Może to prowadzić do bicia .

codetwiddler
źródło
11

Funkcje kmalloc()& vmalloc()to prosty interfejs do uzyskiwania pamięci jądra w porcjach wielkości bajtów.

  1. kmalloc()Funkcja gwarantuje, że strony są fizycznie przyległe (i praktycznie przyległe).

  2. vmalloc()Funkcja działa w sposób podobny do kmalloc(), oprócz tego, że przydziela pamięć, która jest tylko wirtualnie przyległe niekoniecznie fizycznie przyległe.

Yogeesh HT
źródło
4

Jakie są zalety posiadania ciągłego bloku pamięci? W szczególności, dlaczego miałbym mieć ciągły fizyczny blok pamięci w wywołaniu systemowym? Czy jest jakiś powód, dla którego nie mogłem po prostu użyć vmalloc?

Z „Szczęśliwy traf” Google vmalloc:

kmalloc jest preferowanym sposobem, o ile nie potrzebujesz bardzo dużych obszarów. Problem polega na tym, że jeśli chcesz wykonać DMA z / do jakiegoś urządzenia sprzętowego, musisz użyć kmalloc i prawdopodobnie będziesz potrzebować większego kawałka. Rozwiązaniem jest przydzielenie pamięci tak szybko, jak to możliwe, zanim pamięć zostanie pofragmentowana.

Dark Shikari
źródło
Widzisz, przeczytałem to i nie ma to dla mnie sensu. Rozumiem używanie kmalloc na dużych obszarach; ale w przypadku małych przydziałów, dlaczego nie użyć narzędzia vmalloc, aby uniknąć fragmentacji pamięci fizycznej?
FreeMemory
Ponieważ powinieneś ufać jądru, że zrobi to, co najlepsze; jeśli uzna, że ​​przydzielenie pojedynczego fragmentu jest lepsze, zrobi to. vmalloc jest używany tylko wtedy, gdy absolutnie musisz mieć ciągły fragment.
Dark Shikari,
Myślę, że to ma sens, ale wydaje się sprzeczne z intuicją. kmalloc brzmi tak, jakby powinien być używany, gdy wydajność jest najważniejsza (tj. nie mogę być nękany przez IO dysku). A co z GFP_ATOMIC?
FreeMemory
2

W systemie 32-bitowym kmalloc () zwraca adres logiczny jądra (chociaż jest to adres wirtualny), który ma bezpośrednie mapowanie (właściwie ze stałym przesunięciem) na adres fizyczny. To bezpośrednie mapowanie zapewnia, że ​​otrzymamy ciągły fizyczny fragment pamięci RAM. Odpowiedni dla DMA, w którym podajemy tylko początkowy wskaźnik i oczekujemy ciągłego fizycznego mapowania dla naszej operacji.

vmalloc () zwraca wirtualny adres jądra, który z kolei może nie mieć ciągłego mapowania w fizycznej pamięci RAM. Przydatne do alokacji dużej ilości pamięci oraz w przypadkach, gdy nie obchodzi nas, że pamięć przydzielona naszemu procesowi jest ciągła również w fizycznej pamięci RAM.

a.saurabh
źródło
1

Jedną z innych różnic jest to, że kmalloc zwróci adres logiczny (w przeciwnym razie określisz GPF_HIGHMEM). Adresy logiczne są umieszczane w „małej ilości pamięci” (w pierwszym gigabajcie pamięci fizycznej) i są odwzorowywane bezpośrednio na adresy fizyczne (do konwersji użyj makra __pa). Ta właściwość oznacza, że ​​kmalloced memory jest pamięcią ciągłą.

Z drugiej strony, Vmalloc jest w stanie zwrócić adresy wirtualne z „dużej pamięci”. Adresów tych nie można przekształcić bezpośrednio w adresy fizyczne (należy użyć funkcji virt_to_page).

Jérôme Pouiller
źródło