
Linux Scheduler Szeregowanie procesów w systemie Linux Andrzej Ambroziewicz Piotr Marat Mieszko Michalski Zawartość prezentacji ● Linux Scheduler 2.4 ● Linux Scheduler 2.6 ● CFS ( Completely Fair Scheduler ) ● Porównanie i testy Klasy procesów ● Procesy czasu rzeczywistego SCHED_RR i SCHED_FIFO ● Zwalniają procesor gdy: a) W kolejce procesów gotowych pojawi się proces o wyższym priorytecie (to może być tylko proces czasu rzeczywistego) b) Zablokują się w oczekiwaniu na zasób c) Dobrowolnie zrezygnują z procesora d) Zakończą się e) SCHED_RR gdy skończy się kwant czasu ● Procesy użytkownika SCHED_NORMAL Szeregowanie w jądrze 2.4 ● Plik: kernel/sched.c (1398 linii kodu) ● Napisany całkowicie od nowa ● Złożoność O(n) ● Jedna kolejka procesów nawet dla systemów wieloprocesorowych Szeregowanie w jądrze 2.4 Metryka procesu – task_struct Jądro 2.4 ● need_resched – flaga mówiąca czy należy wywołać schedule() “przy następnej okazji” ● counter – licznik taktów zegara pozostałych procesorowi z kwantu czasu ● nice – statyczny priorytet ● rt_priority – priorytet czasu rzeczywistego ● policy – klasa procesu (SCHED_RR, SCHED_FIFO, SCHED_OTHER + SCHED_YIELD) Funkcja schedule() Jądro 2.4 1) Jeśli current->active_mm == NULL podnosimy błąd (proces zawsze musi mieć to pole ustawione) 2) Zapamiętujemy na zmiennych prev i this_cpu aktualny proces działający i procesor 3) Zwalniamy główną blokadę jądra (kernel_lock) 4) Zaczynamy manipulacje na kolejce procesów gotowych: zakładamy blokadę na runqueue 5) Jeśli proces był typu SCHED_RR i wykorzystał swój kwant czasu przydzielamy mu nowy kwant I umieszczamy na koncu kolejki. Funkcja schedule() Jądro 2.4 6) Jeśli proces był w stanie TASK_INTERRUPTIBLE i nadszedł jakiś sygnał zmieniamy stan na TASK_RUNNABLE. Jeśli był w stanie TASK_RUNNABLE zostawiamy go, w przeciwnym wypadku jest usuwany z kolejki 7) Wybieramy proces, który ma działać następny. Domyślnie ustawiamy idle ale oceniamy go bardzo nisko (-1000). Przechodzimy listę procesów gotowych i obliczamy dla nich parametr goodness(), wybieramy najwyższy Funkcja schedule() Jądro 2.4 8) Funkcja goodness(task_struct * p, int this_cpu,mm_struct *this_mm) a) Jeśli proces sam oddał procesor (SCHED_YIELD) zwracamy -1. b) Jeśli jest to proces zwykły ustawiamy parametr na wartość pola, counter (jeśli to 0 to wychodzimy – proces wykorzystawł już czas) 1) faworyzujemy procesy działające na naszym procesorze (+15) 2) dodajemy +1 jeśli proces korzysta z załadowanej pamięci I dla wątków jądra 3) uwzględniamy parametr nice c) dla procesów czasu rzeczywistego wstawiamy wartość 1000+rt_priority 9) Jeśli po przejściu całej listy maksymalna wartość wynosi 0 to znaczy, że wszystkim procesom skończył się kwant czasowy i należy obliczyć je od nowa (procesy z większym priorytetem mogą działac dłużej) 10)Jeśli trzeba, przełączamy kontekst ( makro switch_to() ) Zmiany w jądrze 2.6 ● Pliki kernel/sched.c (7200+ linii kodu) ● Napisany całkowicie od nowa ● Złożoność O(1) ● Osobna kolejka procesów dla każdego procesora Zmiany w jądrze 2.6 ● Inna metoda wyznaczania priorytetów dynamicznych (static_prio, prio, NICE_TO_PRIO(nice), sleep_avg, timestamp) ● 2 kolejki priorytetowe (indeksowane priorytetami 0..139) expired i active, pamiętana bitmapa i ilość procesów ● schedule() i scheduler_tick() ● Wywłaszczenie w trybie jądra(fully preemptive kernel) ● Wsparcie dla maszyn wieloprocesorowych – zrównoważenie obciążenia 2.4 vs 2.6 Wywłaszczanie ● Flaga need_resched mówi, że trzeba wykonać schedule() gdy tylko będzie można. Ustawiana jest w procedurach scheduler_tick() i try_to_wake_up() gdy proces budzony ma większy priorytet ● Jest trzymana w thread_info() w task_struct, bo jest tam szybciej osiągalna niż zmienne globalne Wywłaszczenie (tryb użytkownika) ● Jądro sprawdza flagę need_resched przy powrocie do trybu użytkownika w związku z zakończeniem wywoływania funkcji systemowej lub obsługi przerwania ● Jest to stan bezpieczny, możemy wywołać schedule() Wywłaszczanie (tryb jądra) Jądro 2.6 ● Wprowadzone w 2.6, wiele systemów nie obsługuje wywłaszczania w trybie jądra (kod jądra wywołuje się aż do zakończenia) ● Możemy wywłaszczać tylko wtedy gdy jesteśmy w stanie bezpiecznym, ręcznie wywołaliśmy schedule lub aktualne zadanie oczekuje na zdarzenie. ● Jesteśmy w stanie bezpiecznym gdy nie są założone żadne blokady, zwiększamy wtedy licznik preempt_count w task_struct Zrównoważenie obciążenia procesorów Jądro 2.6 (SMP) ● Uruchamiamy proces stale na tym samym procesorze ● Sprawdzamy czy nie powstała przez to różnica w obciążeniu procesorów ● Jeśli tak, dokonujemy zrównoważenia ● Procedura wywoływana jest w schedule() oraz co 1 (jeśli system jest bezczynny) lub 200 milisekund ● Uruchamiana jest z wyłączonymi przerwaniami i założoną blokadą na lokalną kolejkę, aby wykluczyć jednoczesne zrównoważenia Zrównoważenie obciążenia procesorów Jądro 2.6 (SMP) ● Sprawdzamy czy jest kolejka dłuższa od naszej o conajmniej 25% ● Wybiera kolejke, z której wyciągane będą procesy (pierszeństwo ma expired, bo procesy z niej najczęściej nie trzymają już nic w pamięci podręcznej) ● Przerzucamy procesy o najwyższych priorytetach, przy czym sprawdzamy, czy proces nie działa na tym procesorze, czy można go przerzucić i czy nie ma niczego w pamięci podręcznej Materiały ● R. Love – Linux Kernel Development (rozdział 3) ● http://www.informit.com/articles/article.aspx?p=101760 ● http://lxr.linux.no/ - Linux Cross Reference ● Google ● students/SO – Wykład 3 ● http://www.faqs.org/docs/kernel_2_4/lki-2.html ● http://kerneltrap.org/ Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów Przykład: 2 wątki w systemie – dla priorytetu 0 przydzielony czas to 100 ms: Niemiły wątek - nice=0 Milszy wątek - nice=19 Dostanie Dostanie 100 ms 5ms 100/105 Tylko 5/105 czasu czasu Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów Przykład: 2 wątki w systemie – dla priorytetu 0 przydzielony czas to 100 ms, tym razem równe priorytety: Niemiły wątek - nice=0 Tak samo niemiły wątek - nice=0 Dostanie Dostanie 100 ms 100 ms 100/200 100/200 czasu czasu Ale co jeśli zamiast nice=0, każdy z nich będzie miał priorytet nice=19? Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów Przykład: 2 wątki w systemie – dla priorytetu 0 przydzielony czas to 100 ms, tym razem równe priorytety: Miły wątek - nice=19 Tak samo miły wątek – nice=19 Dostanie Dostanie 5 ms 5 ms 5/10 cza- 5/10 cza- su su Choć stosunek jest taki sam, to dużo częstszy jest czas przełączania kontekstu, a co za tym idzie spada wydajność systemu. Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów ➢Niesprawiedliwa zależność pomiędzy priorytetami Przykład: 2 wątki w systemie – dla priorytetu 0 przydzielony czas to 100 ms, priorytety różnią się o 1 Niemiły wątek - nice=0 Milszy wątek – nice=1 Dostanie Dostanie 100 ms 95 ms 95/195 100/195 czasu czasu Oba wątki dostaną po prawie tyle samo czasu Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów ➢Niesprawiedliwa zależność pomiędzy priorytetami Przykład: 2 wątki w systemie – dla priorytetu 0 przydzielony czas to 100 ms, priorytety różnią się o 1 Miły wątek - nice=18 Jeszcze milszy wątek – nice=19 Dostanie Dostanie 10 ms 5 ms 5/15 cza- 10/15 su czasu Wątek z priorytetem 19 dostanie 2 razy mniej czasu niż ten z priorytetem 18. Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów ➢Niesprawiedliwa zależność pomiędzy priorytetami ➢Nieefektywne budzenie wątków - Przydziela za mało czasu procesora na takie usługi jak wyświetlanie interfejsu lub odtwarzanie multimediów. Obudzony wątek trafia do „active array” zgodnie z priorytetem, zatem wykonywany wątek, który ostatnio zasnął, może powrócić do „active array”, zamiast do „expired array”. Dopóki w „active array” są wątki, dopóty wątki z „expired array” nie otrzymają czasu procesora. Ten fakt może powodować, że ciągły strumień budzących się wątków opóźni na dowolnie długo wątki z „expired array”. Zatem można ma- jąc nawet tylko kilka wątków stworzyć sytuację, gdzie opóźnienie się- ga kilku sekund. Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów ➢Niesprawiedliwa zależność pomiędzy priorytetami ➢Nieefektywne budzenie wątków - Przydzielał on za mało czasu procesora na takie usługi jak wyświetlanie interfejsu lub odtwarzanie multimediów. Obudzony wątek trafia do „active array” zgodnie z priorytetem, zatem wykonywany wątek, który ostatnio zasnął, może powrócić do „active array”, zamiast do „expired array”. Dopóki w „active array” są wątki, dopóty wątki z „expired array” nie otrzymają czasu procesora. Ten fakt może powodować, że ciągły strumień budzących się wątków opóźni na dowolnie długo wątki z „expired array”. Zatem można ma- jąc nawet tylko kilka wątków stworzyć sytuację, gdzie opóźnienie się- ga kilku sekund. Active array Expired array 0 0 1 1 2 2 3 3 . 137 137 138 138 139 139 Wady poprzedniego: ➢Czasami bezsensowne przydzielanie czasu względem priorytetów ➢Niesprawiedliwa zależność pomiędzy priorytetami ➢Nieefektywne budzenie wątków Zły podział może prowadzić do zapchania systemu: O ile 2 pierwsze problemy mogłyby być wyeliminowane poprzez pewne modyfikacje w bazowym algorytmie, o tyle z 3 był o wiele większy problem. Zatem potrzebna była gruntowna zmiana „vanilla scheduler”. Twórca Ingo Molnar powiedział: "80% Of CFS's design can be summed up in a single sen- tence: CFS basically models an 'ideal, precise multi-tasking CPU' on real hardware." ● W ciągu 62 godzin (środa 8 rano – piątek 22) Ingo
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages64 Page
-
File Size-