31.12.2025
W Linuksie 6.6 pojawił się planista EEVDF, algorytm planowania procesora nowej generacji skoncentrowany na sprawiedliwym podziale czasu procesora i szybkości reakcji.
W Linuksie 6.6 pojawił się planista EEVDF, algorytm planowania procesora nowej generacji skoncentrowany na sprawiedliwym podziale czasu procesora i szybkości reakcji.
W jądrze Linuksa w wersji 6.6 wprowadzono znaczącą aktualizację do planowania procesów, zastępując prawie dziesięcioletni Completely Fair Scheduler (CFS) planistą Earliest Eligible Virtual Deadline First (EEVDF) [1]. Nowy planista spełnia tę samą funkcję co CFS, dzieląc czas procesora pomiędzy procesy, ale robi to bardziej skutecznie, z mniejszymi opóźnieniami i bardziej przewidywalnym zachowaniem. EEVDF opiera się na algorytmie z artykułu badawczego z połowy lat 90. XX w. i został połączony pod kierunkiem weterana rozwoju jądra, Petera Zijlstry. Dla osób zarządzających systemami linuksowymi (od serwerów lokalnych po środowiska chmurowe) EEVDF zapewnia potencjalny wzrost wydajności i płynniejszą wielozadaniowość bez konieczności wprowadzania fundamentalnych zmian w oprogramowaniu przestrzeni użytkownika. W niniejszym artykule pokażę, jak działa EEVDF, jak go skonfigurować i zoptymalizować oraz dlaczego ma on znaczenie dla nowoczesnych dystrybucji Linuksa i obciążeń roboczych.
W przeciwieństwie do swojego poprzednika, EEVDF przyjmuje bardziej algorytmiczne podejście do sprawiedliwości i szybkości reakcji, usuwając wiele heurystyk ad-hoc i pokręteł strojenia, na których polegał CFS. Projekt zapewnia, że zadania, które nie otrzymały sprawiedliwego udziału procesora, są automatycznie faworyzowane, podczas gdy zadania, które nadmiernie wykorzystały procesor, są delikatnie ograniczane w kolejnych decyzjach dotyczących planowania. Ten czysty mechanizm proporcjonalnego podziału poprawia opóźnienia dla zadań, które CFS może nieumyślnie zagłodzić lub opóźnić, a wszystko to bez konieczności stosowania złożonych parametrów strojenia. W praktyce, administratorzy systemu i deweloperzy powinni zobaczyć bardziej spójne planowanie zadań i mniej problemów związanych z przypadkami brzegowymi. Deweloperzy jądra ostrzegają, że kilka konkretnych obciążeń może odnotować początkowe regresje wydajności pod EEVDF, ale oczekuje się, że będą one rzadkie i zostaną rozwiązane w kolejnych łatkach.
Dlaczego zmienił się planista
CFS był domyślnym planistą od czasu Linuksa 2.6.23 (2007), więc zastąpienie go było dużym przedsięwzięciem. Główną motywacją było wyeliminowanie nietrwałej heurystyki i zgadywania, których CFS używał do obsługi różnych obciążeń, zwłaszcza zadań wrażliwych na opóźnienia. W CFS zaimplementowano sprawiedliwe planowanie (fair scheduling), śledząc wirtualny czas działania każdego zadania i próbując zapewnić równy czas procesora wszystkim zadaniom o równym priorytecie. Jednakże, aby dostosować się do zachowań interaktywnych i wsadowych, CFS zgromadził wiele przestrajalnych parametrów i heurystyk. Wymagały one starannego wyważenia i mogły błędnie przewidywać niektóre scenariusze, prowadząc do nieoptymalnej wydajności lub szybkości reakcji. Administratorzy mogą pamiętać o dostosowywaniu parametrów CFS lub korzystaniu z narzędzi takich jak nice/renice, aby wpływać na planowanie, co czasami wydawało się czarną sztuką w systemach wielodostępnych lub o dużym obciążeniu.
EEVDF upraszcza to poprzez zastosowanie formalnego modelu proporcjonalnego podziału. Wprowadza dwie kluczowe koncepcje do planisty Linuksa: opóźnienie i wirtualne terminy. Każde zadanie nadal ma wirtualny czas działania (dostosowany przez wagę/priorytety podobne do CFS), ale EEVDF oblicza opóźnienie każdego zadania jako różnicę między czasem procesora, który powinien otrzymać (idealny sprawiedliwy udział), a tym, co faktycznie otrzymał. Zadania, które mają dodatnie opóźnienie, nie otrzymały swojego sprawiedliwego udziału i są oznaczone jako kwalifikujące się do uruchomienia, podczas gdy zadania z ujemnym opóźnieniem (co oznacza, że ostatnio wykonały więcej niż ich sprawiedliwy udział) stają się tymczasowo niekwalifikowalne. Niekwalifikujące się zadania pozostaną poza CPU, dopóki ich ujemne opóźnienie nie spadnie do zera (ich uprawnienia „nadrobią”), w którym to momencie ponownie staną się kwalifikowalne. W ten sposób EEVDF zapewnia ścisłą sprawiedliwość: żadne zadanie nie dostaje więcej niż jego uprawniony kawałek w czasie, a każde zadanie, które pozostało w tyle, jest traktowane priorytetowo jako następne. To zachowanie jest wbudowane, a nie heurystyczne, i jest oparte na matematyce wirtualnego rozliczania czasu.
Oprócz sprawiedliwości, EEVDF odnosi się do wymagań dotyczących opóźnień poprzez koncepcję wirtualnego terminu dla każdego zadania. Wirtualny termin jest zasadniczo czasem, w którym zadanie powinno zostać uruchomione jako następne, aby zachować sprawiedliwość, obliczonym na podstawie kwalifikującego się czasu zadania plus wycinka czasu procesora. Co ważne, EEVDF zawiera metrykę drugiego priorytetu, często nazywaną wrażliwością na opóźnienia. Zadanie wrażliwe na opóźnienia ma przypisane krótsze wycinki czasu, co naturalnie daje mu wcześniejsze wirtualne terminy. EEVDF stosuje następnie politykę „najpierw najwcześniejszy wirtualny termin” wśród kwalifikujących się zadań, co oznacza, że zadanie, którego wirtualny termin jest najszybszy, jest uruchamiane jako następne. W efekcie zadania, które nie wymagają dużej ilości procesora, ale potrzebują szybkiej odpowiedzi, są uruchamiane wcześniej (częściej, w małych seriach), bez pozwalania im na zużycie większej ilości czasu procesora niż ich sprawiedliwy udział. Jest to czyste rozwiązanie problemu, z którym CFS radził sobie za pomocą częściowych środków. W CFS trzeba było albo uruchamiać procesy wrażliwe na opóźnienia z wyższym priorytetem (niższa wartość nice), co również dawało im więcej całkowitego czasu procesora, albo polegać na łatkach „tolerancji opóźnień”. Z EEVDF, zadanie może być responsywne bez bycia niesprawiedliwym: dostaje CPU szybko, gdy jest to potrzebne, ale nie przyćmiewa innych zadań w całkowitym użyciu przez długi czas. Przyjęcie EEVDF przez jądro Linuksa miało na celu uniknięcie konieczności stosowania starej łatki latency nice poprzez zintegrowanie responsywności z podstawowym algorytmem planisty.
Wpływ na wydajność
Jednym z najważniejszych pytań dotyczących każdego nowego planisty jest „jak sprawdza się on w rzeczywistych obciążeniach?”. Wczesne testy i testy porównawcze Linuksa 6.6 z EEVDF wykazały obiecującą poprawę. Wyniki testów Phoronix na 128-rdzeniowym serwerze EPYC 9754 „Bergamo” wykazały znaczną poprawę w różnych obciążeniach bazodanowych i analitycznych po aktualizacji z Linuksa 6.5 (CFS) do Linuksa 6.6 (EEVDF). Są to znaczące ulepszenia dla pojedynczego skoku wersji jądra.
Warto zauważyć, że największe korzyści z EEVDF pojawiają się w sytuacjach, w których wiele możliwych do uruchomienia zadań rywalizuje o procesor. Duże serwery, kontenery we wdrożeniach w chmurze lub moduły CI/CD z wieloma równoległymi zadaniami mogą skorzystać z bardziej spójnego rozkładu czasu planisty. Na typowych komputerach stacjonarnych lub maszynach wirtualnych o niskiej liczbie rdzeni różnice mogą być mniej wyraźne. W rzeczywistości w testach Phoronix zauważono, że na systemach o niższej liczbie rdzeni (takich jak typowe laptopy deweloperskie lub małe maszyny wirtualne w chmurze) nie zaobserwowano dramatycznych zmian wydajności w codziennych zadaniach. Sugeruje to, że algorytm sprawiedliwości EEVDF wyróżnia się, gdy problem szeregowania jest złożony (wiele zadań/rdzeni), podczas gdy w przypadku lekkiego użytkowania można nie zauważyć zmiany, co jest dobrą rzeczą (oznacza to, że w typowym przypadku nie ma regresji).
Co z opóźnieniami i szybkością reakcji? Z założenia EEVDF zapewnia zadaniom wrażliwym na opóźnienia bardziej natychmiastowy dostęp do procesora, a wstępne wyniki to potwierdzają. Spójność algorytmu EEVDF pomaga również w przypadku opóźnień ogonowych, czyli opóźnień w najgorszym przypadku, co ma kluczowe znaczenie dla umów SLA w usługach korporacyjnych i chmurowych. Wszystkie te ulepszenia pojawiają się przy zachowaniu sprawiedliwości: w przeciwieństwie do zwykłego upiększania ważnych procesów, EEVDF nie pozwala im wiecznie uciekać z procesorem, więc zadania w tle nadal otrzymują należną im część.
Korzystanie z EEVDF w systemach Linux
Dobrą wiadomością dla administratorów systemu jest to, że nie ma nic specjalnego, co trzeba zrobić, aby „włączyć” EEVDF. Jeśli korzystasz z jądra Linux 6.6 lub nowszego, EEVDF jest domyślnym planistą procesów. Innymi słowy, po aktualizacji jądra wszystkie normalne procesy są automatycznie obsługiwane przez EEVDF zamiast CFS. Nie ma przełącznika runtime ani opcji jądra GRUB do przełączania planistów procesora w locie. Linux nie obsługuje wymiany planisty w czasie wykonywania; jest to podstawowa część jądra. Tak więc, aby rozpocząć korzystanie z EEVDF, podstawowym krokiem jest uruchomienie jądra w wersji 6.6 lub nowszej. Wiele popularnych dystrybucji Linuksa włącza EEVDF, gdy ponownie bazują na nowszych jądrach:
Z punktu widzenia konfiguracji migracja do EEVDF jest prosta, ponieważ większość istniejących ustawień jest przenoszona. Wszelkie niestandardowe konfiguracje CFS (takie jak powinowactwo procesora, limity procesora c-grup, ładne poziomy) nadal działają w EEVDF. Planista respektuje normalne interfejsy Linuksa: wartości Nice nadal określają wagę (udział procesora), tak jak wcześniej, a polityki czasu rzeczywistego pozostają niezmienione i mają pierwszeństwo przed EEVDF dla tych uprzywilejowanych zadań. Jeśli kontrola przepustowości procesora została skonfigurowana za pomocą c-grup, mechanizm ten nadal działa. Wewnętrzny kontroler przepustowości CFS jądra działa teraz z EEVDF. Jedną z ostatnich poprawek w EEVDF była poprawa interakcji z ogranicznikiem przepustowości c-grup, która zapewnia, że limity i limity procesora na grupę będą nadal działać poprawnie w nowym planiście. Oznacza to, że w środowiskach wielodostępnych (takich jak maszyny wirtualne w chmurze lub kontenery) można uaktualnić do EEVDF bez utraty możliwości egzekwowania limitów procesora ze względów bezpieczeństwa lub jakości usług.
Jak można sprawdzić, czy EEVDF jest aktywny w systemie? Ponieważ planista jest wbudowany w jądro, nie ogłasza się wyraźnie za pomocą narzędzia wiersza poleceń. Można to wywnioskować z wersji jądra i informacji o kompilacji. Uruchomienie uname -r pokaże wersję jądra; jeśli jest to 6.6 lub wyższa i używasz standardowego jądra dystrybucji, możesz być pewien, że EEVDF jest w użyciu (ponieważ CFS został usunięty i zastąpiony kodem EEVDF w tych wersjach). Inną wskazówką jest sprawdzenie obecności (lub nieobecności) niektórych ustawień planisty w /proc/sys/kernel. Wiele przestrajalnych parametrów CFS pozostaje widocznych dla kompatybilności, ale niektóre mogą nie mieć takiego samego efektu. Na przykład, na jądrze 6.6, jeśli uruchomisz
sysctl -A | grep sched
nadal będziesz widział wyniki takie jak kernel.sched_autogroup_enabled, kernel.sched_cfs_bandwidth_slice_us, itp. -- nazwy nie uległy zmianie (interfejsy jądra często zachowują cfs w nazwach dla zachowania ciągłości). Wartość sched_autogroup_enabled (która zarządza automatycznym grupowaniem zadań dla powłok interaktywnych) będzie prawdopodobnie 1 w dystrybucji desktopowej, co jest w porządku. Autogrupowanie działa w połączeniu z EEVDF tak samo jak w przypadku CFS, grupując zadania według sesji w celu poprawy interaktywności pulpitu.
Optymalizacja i najlepsze praktyki
Jedną z zalet projektu EEVDF jest to, że zmniejsza on potrzebę ręcznego dostrajania. W erze CFS dostosowanie wydajności oznaczało czasami dostosowanie pokręteł /proc/sys/kernel/sched_* lub zmianę zachowania planisty dla określonych scenariuszy (na przykład zwiększenie sched_wakeup_granularity_ns w celu zmniejszenia częstotliwości przełączania zadań na serwerach zorientowanych na przepustowość lub obniżenie jej dla komputerów stacjonarnych w celu poprawy interaktywności). W EEVDF wiele z tych pokręteł albo już nie istnieje, albo odgrywa mniejszą rolę. Planista sam dostosowuje się na podstawie algorytmu lag/deadline.
Poziomy nice i c-grupy
Pozostają one głównymi narzędziami do wpływania na alokację czasu procesora. Jeśli masz zadania wsadowe lub usługi działające w tle (np. indeksowanie danych, kopie zapasowe) oraz usługi wrażliwe na opóźnienia (serwery WWW, interaktywne sesje SSH itp.), nadal korzystaj z priorytetów uniksowych (wartości nice lub udziały CPU c-grup), aby nadać zadaniom w tle wyższy poziom nice (czyli niższy priorytet), aby inne zadania mogły lepiej korzystać z procesowa. EEVDF będzie wymuszać sprawiedliwe planowanie, ale z określonymi wagami.
Zrozumienie "latency-nice"
Jądro pozwala na dostosowanie wymagań opóźnienia zadania poprzez wywołanie systemowe sched_setattr(). Domyślnie jądro przypisuje wartości latency-nice wewnętrznie. W większości przypadków nie będziesz musiał tego dotykać. Ale jeśli rozwijasz lub wdrażasz oprogramowanie, które jest wyjątkowo krytyczne pod względem opóźnień (na przykład miękki system kontroli w czasie rzeczywistym lub silnik handlu o wysokiej częstotliwości) i nie może działać jako proces czasu rzeczywistego, możesz zbadać interfejs API sched_setattr, aby nadać mu niższą tolerancję opóźnień. W ten sposób nakazujesz EEVDF, aby dał mu krótsze wycinki czasu.
Optymalizacje dla procesorów hybrydowych (big.LITTLE)
Jeśli uruchamiasz Linuksa na heterogenicznym sprzęcie CPU (takim jak Intel Alder Lake 12. generacji lub nowszy, z rdzeniami P i E lub serwerami ARM big.LITTLE), pamiętaj, że Linux 6.6 ponownie wprowadził klastrowe planowanie dla takich procesorów. W praktyce oznacza to, że planista jest świadomy grupowania rdzeni CPU o podobnej wydajności i będzie dążył do bardziej inteligentnego utrzymywania zadań w odpowiednich klastrach. Jako administrator, upewnij się, że Twoje jądro ma CONFIG_SCHED_CLUSTER (większość jąder dystrybucji umożliwiających EEVDF zawiera to dla hybryd Intela). Nie ma ręcznego przełącznika w czasie wykonywania, ale dobrze wiedzieć, że EEVDF będzie teraz lepiej obsługiwać planowanie hybrydowe. Nadal powinieneś ustawić powinowactwo procesora lub politykę, jeśli wymagasz, aby niektóre zadania pozostały na określonych typach rdzeni z powodów licencyjnych lub innych. Ogólnie rzecz biorąc, pozwól EEVDF zarządzać rdzeniami, ponieważ zmniejszy to niepotrzebną migrację zadań między różnymi rdzeniami, co poprawi wykorzystanie pamięci podręcznej i ogólną przepustowość w projektach hybrydowych.
Wnioski
Wprowadzenie planisty EEVDF w Linuksie 6.6 jest znaczącym postępem w sposobie przydzielania czasu procesora przez jądro, mającym na celu poprawę wydajności, szybkości reakcji i skalowalności dla nowoczesnych obciążeń. EEVDF w dużej mierze „po prostu działa”, wymagając minimalnych zmian w konfiguracji, ale oferuje solidniejsze podstawy do uruchamiania wszystkiego, od baz danych w chmurze po aplikacje działające w czasie rzeczywistym. Widzieliśmy, jak algorytmiczne podejście EEVDF zapewnia sprawiedliwość (poprzez koncepcję opóźnienia) i szybką reakcję na interaktywne zadania (poprzez wirtualne terminy), skutecznie łącząc teoretyczne koncepcje planowania z praktycznymi korzyściami. Dzięki usunięciu wielu pokręteł strojenia, nowy planista upraszcza optymalizację, a systemy działają dobrze w szerokim zakresie warunków bez potrzeby dodatkowej konfiguracji, choć zrozumienie podstawowych koncepcji może pomóc w diagnozowaniu problemów lub dostrajaniu ekstremalnych przypadków.
Info
[1] EEVDF Scheduler: https://docs.kernel.org/scheduler/sched-eevdf.html
