Programowanie Systemów Wbudowanych
Transkrypt
Programowanie Systemów Wbudowanych
Programowanie Systemów Wbudowanych Zarzadzanie ˛ pamieci ˛ a˛ Iwona Kochańska Katedra Systemów Elektroniki Morskiej WETI PG May 24, 2016 Pamieć ˛ wirtualna I I Przestrzeń adresowa pamieci ˛ wirtualnej: od zera do 0xffffffff (dla procesorów 32-bitowych), podzielona na strony o rozmiarze 4 kB Przestrzeń adresowa podzielona na przestrzeń użytkownika (user space) i przestrzeń jadra ˛ (kernel space) GUT – Intel 2015/16 2/40 Pamieć ˛ wirtualna I Podział miedzy ˛ przestrzeń użytkownika a przestrzeń jadra: parametr PAGE_OFFSET konfiguracji jadra ˛ I I I I typowy system 32-bitowy: PAGE_OFFSET = 0xc0000000, niższe 3GB - przestrzeń użytkownika przestrzeń użytkownika alokowana dla procesu przestrzeń jadra ˛ - wspólna dla wszystkich procesów. Memory Management Unit (MMU) - mapowanie adresów w przestrzeni wirtualnej na adresy w pamieci ˛ fizycznej GUT – Intel 2015/16 3/40 Pamieć ˛ wirtualna Każda strona pamieci ˛ wirtualnej może być: I niemapowana (próba dostepu ˛ -> SIGSEGV -> komunikat segmentation fault) I mapowana na strone˛ fizyczna˛ pamieci ˛ prywatna˛ dla procesu I mapowana na strone˛ fizyczna˛ pamieci ˛ współdzielona˛ z innym procesem I mapowana i współdzielona z flaga˛ “copy on write” I I gdy istnieje potrzeba współdzielenia wzglednie ˛ dużej ilości danych, co do których nie ma pewności, że zostana˛ zmodyfikowane przez używajace ˛ je obiekty zamiast rzeczywistego, kosztownego kopiowania pamieci ˛ zwracany jest wskaźnik do oryginalnych danych; kopiowanie jest wykonywane dopiero, gdy zachodzi potrzeba ich modyfikacji. GUT – Intel 2015/16 4/40 Pamieć ˛ wirtualna Każda strona pamieci ˛ wirtualnej może być: I mapowana na strone˛ fizyczna˛ pamieci ˛ używana˛ przez jadra ˛ I jadro ˛ może dodatkowo mapować strony p. wirtualnej na obszary pamieci ˛ zarezerwowane dla np. buforów pamieci ˛ sterowników Zalety: I niepoprawne odwołania do pamieci ˛ przechwytywane i sygnalizowane przez SIGSEGV I proces działa we własnej przestrzeni pamieci, odizolowany od innych procesów I efektywne wykorzystanie pamieci ˛ - współdzielenie cz˛eści kodu i danych ( np. bibliotek) I możliwość zwiekszenia ˛ ilości pamieci ˛ poprzez pliki wymiany (swap files) GUT – Intel 2015/16 5/40 Pamieć ˛ wirtualna Wady: I trudno ustalić, jakie jest aktualne zużycie pamieci ˛ (przez aplikacje) ˛ I “overcommit” - praktyka przedzielania pamieci ˛ wirtualnej bez gwarancji, że dostepna ˛ jest odpowiednia ilość pamieci ˛ fizycznej I opóźnienia wprowadzane przez zarzadzanie ˛ pamieci ˛ a˛ i obsługe˛ wyjatków ˛ (page faults) GUT – Intel 2015/16 6/40 Obszar pamieci ˛ jadra ˛ Przestrzeń pamieci jadra ˛ - każdej alokacji w przestrzeni wirtualnej odpowiada przestrzeń fizyczna! I jadro ˛ (kod i dane załadowane z obrazu jadra ˛ podczas rozruchu systemu) I I segmenty: .text, .init, .data, .bss pamieć ˛ alokowana przez kmalloc() I slab allocator - efektywny mechanizm alokacji; I I eliminuje fragmentacje˛ pamieci ˛ alokacja pamieci ˛ zawierajacej ˛ obiekty danych do reużycia dla obiektów danych tego samego typu GUT – Intel 2015/16 7/40 Obszar pamieci ˛ jadra ˛ I pamieć ˛ alokowana przez vmalloc() I wieksze ˛ obszary pamieci ˛ niż kmalloc() (przestrzeń adresowa wirtualna - ciagła, ˛ ale fizyczna - niekoniecznie) I pamieć ˛ dla sterowników urzadze ˛ ń I moduły jadra ˛ GUT – Intel 2015/16 8/40 Ile pamieci ˛ używa jadro? ˛ I rozmiar obrazu jadra ˛ I I zwykle jadro ˛ jest małe w porównaniu z całkowita˛ ilościa˛ pamieci ˛ budowa małego jadra ˛ ( Linux-tiny, Linux Kernel Tinification), projekt https://tiny.wiki.kernel.org/. GUT – Intel 2015/16 9/40 Ile pamieci ˛ używa jadro? ˛ I Odczyt /proc/meminfo GUT – Intel 2015/16 10/40 Ile pamieci ˛ używa jadro? ˛ Kernel memory usage to suma: I Slab: pamieć ˛ alokowana przez slab allocator I wiecej ˛ informacji - odczyt /proc/slabinfo I KernelStack: przestrzeń adresowa stosu I PageTables: pamieć ˛ do przechowywania tablic stronicowania I VmallocUsed: pamieć ˛ alokowana przez vmalloc() I wiecej ˛ informacji - odczyt /proc/vmallocinfo GUT – Intel 2015/16 11/40 Ile pamieci ˛ używa jadro? ˛ lsmod - ile pamieci ˛ zużywa kod i dane modułów jadra? ˛ GUT – Intel 2015/16 12/40 Obszar pamieci ˛ użytkownika I Stronicowanie na żadanie ˛ (Demand-paging) - Linux mapuje strony pamieci ˛ fizycznej tylko wtedy, gdy program odwołuje sie˛ do odpowiedniego miejsca w pamieci ˛ wirtualnej malloc(3) zwraca wskaźnik do pamieci ˛ wirtualnej operacja odczytu/zapisu przechwytywana przez jadro ˛ page fault jadro ˛ znajduje obszar pamieci ˛ fizycznej i dodaje go 13/40 do tablicy stronicowania GUT – Intel 2015/16 Obszar pamieci ˛ użytkownika I Bład ˛ stronicowania (page fault) - gdy jadro ˛ przechwytuje dostep ˛ do strony pamieci ˛ nie mapowanej na pamieć ˛ fizyczna˛ I Dwa rodzaje błedów ˛ stronicowania: I I minor - rozwiazaniem ˛ jest znalezienie przez jadro ˛ wolnego obszaru pamieci ˛ fizycznej i powiazanie go z przestrzenia˛ adresowa˛ procesu w pamieci ˛ wirtualnej major - pamieć ˛ wirtualna jest mapowana na plik (np. za pomoca˛ mmap(2)). Próba odczytu z takiej pamieci: ˛ I I jadro ˛ musi znaleźć obszar pamieci ˛ fizycznej jadro ˛ musi wypełnić pamieć ˛ fizyczna˛ danymi z pliku GUT – Intel 2015/16 14/40 Mapa pamieci ˛ procesu Dostep ˛ do mapy pamieci ˛ procesu - przez system plików proc I Przykład: mapa pamieci ˛ procesu init (PID 1) ... I Pierwsze trzy kolumny: adres poczatku ˛ i końca pamieci ˛ wirtualnej, flagi uprawnień: r = read w = write x = execute s = shared p = private (copy on write) I Mapowanie pamieci ˛ zwiazanej ˛ z plikiem: kolumna 4: przesuniecie ˛ wzgledem ˛ poczatku ˛ pliku, kolumna 5: numer urzadzenia ˛ blokowego, kolumna 6: inod pliku, kolumna 7: nazwa pliku GUT – Intel 2015/16 15/40 Partycja wymiany (Swap) Partycja wymiany służy do tymczasowego przechowywania danych w sytuacji, gdy ich ilość przekracza zasoby wolnej pamieci ˛ RAM lub gdy z różnych powodów korzystniej jest przechowywać je na dysku twardym I zwiekszenie ˛ efektywnego rozmiaru pamieci ˛ fizycznej I koszt obsługi partycji wymiany jest duży w systemie o małej ilości pamieci ˛ fizycznej I mechanizm rzadko używany w systemach wbudowanych (swap nie sprawdza sie˛ z nosnikami flash) GUT – Intel 2015/16 16/40 Wykorzystanie partycji wymiany do kompresji pamieci ˛ (zram) I sterownik zram tworzy urzadzenia ˛ blokowe: /dev/zram0, /dev/zram1, itd. I zawartość pamieci ˛ jest kompresowana przed zapisem do zram I współczynnik kompresji: 30% - 50% I całkowity zysk wolnej pamieci: ˛ 10% I koszt: kompresja (przetwarzanie), zwiekszone ˛ zużycie mocy I stosowane w niektórych urzadzeniach ˛ Android GUT – Intel 2015/16 17/40 Mapowanie pamieci ˛ I Proces rozpoczyna swoje życie z pewna˛ ilościa˛ pamieci ˛ I I I I segment kodu programu (text) segment danych (data) biblioteki wspóldzielone Proces może alokować dodatkowa pamieć ˛ I I na stosie (heap), podczas działania, za pomoca˛ malloc(3); domyślnie bez ograniczeń na stercie (stack), za pomoca˛ alloca(3); domyślnie - max. 8 MB, Alokacja przekraczajaca ˛ limit -> sygnał SIGSEGV I Ładowanie bibliotek współdzielonych - dlopen(3). GUT – Intel 2015/16 18/40 Mapowanie pamieci ˛ (mmap) I Proces może też alokować pamieć ˛ za pomoca˛ mmap(2) mapuje length bajtów pamieci ˛ z pliku od deskryptorze fd, poczawszy ˛ od offset w pliku i zwraca wskaźnik do obszaru pamieci; ˛ prot - parametr ochrony (kombinacja read, write, execute i flagi MAP_SHARED lub MAP_PRIVATE) GUT – Intel 2015/16 19/40 Mapowanie pamieci ˛ (mmap) I Alokacja pamieci ˛ prywatnej I I I flaga MAP_ANONYMOUS i fd = -1. malloc(3) w glibc alokuje pamieć ˛ do 128kB, potem woła mmap Alokacja pamieci ˛ współdzielonej I flaga MAP_SHARED i fd = shm_open() shm_open(3) - create POSIX shared memory objects GUT – Intel 2015/16 20/40 Mapowanie pamieci ˛ (mmap) I Alokacja pamieci ˛ urzadzenia ˛ I I I dokładna implementacja - zależna od sterownika Przykład 1: Linux frame buffer, /dev/fb0. Interfejs zdefiniowany w /usr/include/linux/fb.h, funkcja ioctl zwraca rozmiar ekranu i liczbe˛ bitów na pixel mmap - prośba do sterownika wideo o udostepnienie ˛ bufora ramek dla aplikacji do odczytu/zapisu Przykład 2: interfejs strumieniowy wideo, V4L2 (/usr/include/linux/videodev2.h) GUT – Intel 2015/16 21/40 Ile pamieci ˛ używa aplikacja? I polecenie free - ile wolnej pamieci ˛ widzi jadro ˛ I jadro ˛ wykorzystuje wolna˛ pamieć ˛ na bufory i cache-e, które moga˛ być zwolnione/skompresowane w każdej chwili GUT – Intel 2015/16 22/40 Ile pamieci ˛ używa aplikacja? I Wymuszenie zwolnienia cache-ów: echo 3 > /proc/sys/vm/drop_caches Numer 3 (lub 1 lub 2) - maska bitowa: GUT – Intel 2015/16 23/40 Ile pamieci ˛ używa aplikacja? Dwie metryki ilości pamieci ˛ używanej przez proces I Vss (virtual set size) - nazywana VSZ w komendzie ps i VIRT w top I I całkowita ilość pamieci ˛ mapowanej przez proces (suma obszarów pokazanych w /proc/<PID>/maps) Rss (resident memory size) - nazywana RSS w ps i RES w top I I całkowita ilość pamieci ˛ mapowanej na pamieć ˛ fizyczna˛ wartość wieksza ˛ od rzeczywistej pamieci ˛ fizycznej zużywanej przez proces - obszary współdzielone policzone wielokrotnie! GUT – Intel 2015/16 24/40 Komenda ps I Komendy top i ps z BusyBox - ograniczona ilość informacji I Pakiet procps - pełne wersje top i ps I Komenda ps - pokazuje VSZ i RSS GUT – Intel 2015/16 25/40 Komenda top I top - podsumowanie pamieci ˛ wolnej i zużywanej przez procesy Jesli Rss procesu ciagle ˛ rośnie -> przeciek pamieci ˛ (memory leak)! GUT – Intel 2015/16 26/40 Narz˛edzie smem Rok 2009 - dwie nowe metryki I Uss (unique set size) - ilość pamieci ˛ zwiazanej ˛ z pamieci ˛ a˛ fizyczna, ˛ unikalna dla procesu; ilość pamieci, ˛ ktora sie˛ zwolni po zakończeniu działania procesu I Pss (propotional set size) - dzieli sume˛ obszarów pamieci ˛ współdzielonej, zwiazanych ˛ z pamieci ˛ a˛ fizyczna, ˛ na liczbe˛ procesów mapujacych ˛ te obszary; GUT – Intel 2015/16 27/40 Narz˛edzie smem Informacja dostepna ˛ w /proc/<PID>/smaps GUT – Intel 2015/16 28/40 Narz˛edzie smem smem - narz˛edzie zbierajace ˛ dane z plików smaps I I Strona projektu: https://www.selenic.com/smem. Napisane w Python-ie, instalacja w systemie wbudowanym wymaga obecności środowiska Python, co może być problemem smemcap - program zbierajacy ˛ informacje z plików smaps i zapisujacy ˛ je w formie archiwum TAR, które moga˛ być nastepnie ˛ analizowane na komputerze hosta GUT – Intel 2015/16 29/40 Narz˛edzie smem GUT – Intel 2015/16 30/40 Narz˛edzie smem GUT – Intel 2015/16 31/40 Narz˛edzie smem GUT – Intel 2015/16 32/40 Wykrywanie przecieków pamieci ˛ I Przeciek pamieci ˛ (memory leak) - pamieć ˛ jest alokowana, ale nie jest zwalniana, kiedy przestaje być używana I W systemach wbudowanych: I I I urzadzenia ˛ maja˛ mało pamieci ˛ urzadzenia ˛ działaja˛ długo bez ponownego uruchomienia Narz˛edzia do wykrywania przecieków: mtrace i Valgrind. GUT – Intel 2015/16 33/40 Wykrywanie przecieków pamieci ˛ - mtrace I mtrace - komponent glibc śledzacy ˛ wywołania malloc(3), free(3) i pokrewnych funkcji Wywołanie mtrace() w programie rozpocz˛ecie śledzenia (mtrace-example.c) Runtime: przypisanie log-a do zmiennej środowiskowej MALLOC_TRACE I komenda mtrace do odczytu log-a I informacja o przecieku - po zakończeniu programu GUT – Intel 2015/16 34/40 Wykrywanie przecieków pamieci ˛ - Valgrind I Valgrind - narz˛edzie do identyfikacji problemów z pamieci ˛ a˛ I I I nie trzeba re-kompilować sprawdzanych programu i bibliotek, ale warto kompilować z opcja˛ -g (symbole debuggera) uruchamia program w środowisku emulowanym wada: program działa z obniżona˛ wydajnościa˛ (słaba możliwość testowania programów działajacych ˛ w czasie rzeczywistym) GUT – Intel 2015/16 35/40 Wykrywanie przecieków pamieci ˛ - Valgrind I Narz˛edzia diagnostyczne Valgrind: I I I I I I memcheck: domyślne narz˛edzie, wykrywa przecieki pamieci ˛ cachegrind: zwraca liczbe˛ odwołań do pamieci ˛ cache procesora (cache hit rate) callgrind: zwraca koszt wywołań funkcji helgrind: wskazuje na niepoprawne użycie Pthread API, potencjalne zakleszczenia, wystapienia ˛ wyścigu DRD: inne narz˛edzie analizy użycia Pthread API massif: użycie stosu i sterty I Wybór narz˛edzia: opcja -tool I Dostepne ˛ jako pakiet zarówno dla Yocto Project jak i Buildroot GUT – Intel 2015/16 36/40 Wykrywanie przecieków pamieci ˛ - Valgrind Wykrywanie przecieków - narz˛edzie memcheck z opcja˛ –leakcheck=full (drukuje linie gdzie wykryto przeciek) GUT – Intel 2015/16 37/40 Wykrywanie przecieków pamieci ˛ - Valgrind Wykrywanie przecieków - narz˛edzie memcheck z opcja˛ –leakcheck=full (drukuje linie gdzie wykryto przeciek) GUT – Intel 2015/16 38/40 Brak pamieci ˛ I Standardowy mechanizm alokacji pamieci ˛ to “over-commit” jadro ˛ pozwala na alokacje˛ pamieci ˛ dla aplikacji bez sprawdzania, czy dostepna ˛ jest pamieć ˛ fizyczna I Out of Memory (OOM): gdy cała pamieć ˛ wirtualna została przydzielona. I I I System operacyjny próbuje odzyskać pamieć ˛ i wyjść ze stanu OOM wywołujac ˛ nisokopriorytetowy proces OOM Killer (zabija procesy, aż problem zniknie). Działajace ˛ procesy, które napotykaja˛ sie˛ na stan OOM, próbujac ˛ zarezerwować pamieć, ˛ używajac ˛ funkcji malloc(), napotykaja˛ bład. ˛ Dobrze napisane programy powinny być przygotowane na taka˛ sytuacje. ˛ Oblicza “badness score” pomiedzy ˛ 0 i 1,000 dla każdego procesu i zamyka ten z najwyższym wynikiem GUT – Intel 2015/16 39/40 Brak pamieci ˛ Zmiana parametru sposobu alokacji pamieci ˛ przez jadro: ˛ /proc/sys/vm/overcommit_memory: I Option 0: heuristic over-commit (this is the default) I Option 1 (always over-commit, never check) I I I przydatne tylko gdy program pracuje z dużymi, rzadkimi tablicami i alokuje duże obszary pamieci, ˛ ale zapisuje tylko mała˛ cz˛eść tego obszaru rzadko spotykane w systemach wbudowanych Option 2 (always check, never over-commit) I I I systemy czasu rzeczywistego, apliacje “safety-critical” nie udaje sie˛ alokacja obszaru wiekszego, ˛ niż dopuszczalny limit, który wynosi: limit = sizeof(swap)+(total memory)*over-commit ratio over-commit ratio jest kontrolowane przez /proc/sys/vm/overcommit_ratio (domyślnie 50%) GUT – Intel 2015/16 40/40