Sterowanie przerwaniami sprzętowymi w systemie Linux
Napisał: Patryk Krawaczyński
24/06/2011 w Administracja Brak komentarzy. (artykuł nr 320, ilość słów: 2314)
Z
a każdym razem, kiedy część naszego sprzętu komputerowego takiego jak np. dysk twardy, czy karta sieciowa – wymaga poświęcenia uwagi ze strony procesora (CPU) – wywołuje przerwanie (ang. interrupt) lub żądanie przerwania (IRQ – Interrupt ReQuest). Przerwanie takie “mówi” procesorowi, że właśnie zaistniało pewne zdarzenie, które musi zostać natychmiast obsłużone – dlatego procesor powinien porzucić swoją dotychczasową pracę i zająć się tym zdarzeniem. W celu uniknięcia zgłaszania przez wiele urządzeń tych samych przerwań, system IRQ został tak zaplanowany, aby każde urządzenie w systemie komputerowym posiadało swój własny, specjalny nr przerwania, czyniący go niepowtarzalnym.
Zaczynając od wersji jądra 2.4 system Linux otrzymał możliwość przypisywania określonych przerwań do określonych procesorów (lub ich grup). Pierwotnie funkcja ta opracowywana w ramach projektu Red Hat Content Accelerator została rozwinięta jako niezależny mechanizm jądra określany terminem SMP IRQ Affinity (ang. Symmetric MultiProcessing Interrupt ReQuest Affinity) i pozwala na sterowanie sposobem w jaki nasz system będzie odpowiadał na różne zdarzenia związane ze sprzętem. Daje nam to możliwość przydzielania i rozkładania pracy, którą obciążony jest nasz serwer. Oczywiście, w celu wykorzystania tej technologii potrzebna nam będzie maszyna, która posiada więcej niż jeden procesor (SMP) oraz jądro w wersji 2.4 lub wyższej.
SMP Affinity jest kontrolowane i może być manipulowane przez pliki znajdujące się w wirtualnym systemie plików /proc
, a dokładniej katalogu /proc/irq/
. W katalogu tym znajdują się inne katalogi, których nazwy odpowiadają numerom przerwań sprzętowych znajdujących się w naszym systemie (jednak nie wszystkie mogą być tutaj wyszczególnione). W każdym z tych katalogów znajduje się plik o nazwie “smp_affinity“. To za jego pomocą określamy, który i ile procesorów ma zająć się danym przerwaniem. Pierwszym krokiem do wyskalowania odpowiednich urządzeń jest zorientowanie się, którego przerwania używa jakie urządzenie. Informacje te dostępne są w pliku /proc/interrupts
:
root@darkstar:~# cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 0: 29 7 8 6 IO-APIC-edge timer 1: 1 0 2 1 IO-APIC-edge i8042 8: 0 1 0 0 IO-APIC-edge rtc0 9: 0 0 0 0 IO-APIC-fasteoi acpi 14: 12498 14 12818 17 IO-APIC-edge ata_piix 15: 0 0 0 0 IO-APIC-edge ata_piix 16: 182383 144 279295 162 IO-APIC-fasteoi hda_intel, nvidia 18: 139573 56 249 78 IO-APIC-fasteoi uhci_hcd:usb4, snd0106 20: 56159 1873 3019 1848 IO-APIC-fasteoi ahci 21: 5274 382153 5294 382136 IO-APIC-fasteoi ehci_hcd:usb1, usb2 22: 0 0 0 0 IO-APIC-fasteoi uhci_hcd:usb3 23: 0 0 0 0 IO-APIC-fasteoi uhci_hcd:usb5 NMI: 0 0 0 0 Non-maskable interrupts LOC: 1155507 1131555 1300727 1159863 Local timer interrupts SPU: 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 Performance monitoring interrupts IWI: 0 0 0 0 IRQ work interrupts RES: 41001 37232 35187 40728 Rescheduling interrupts CAL: 8153 32832 6373 6241 Function call interrupts TLB: 32092 41628 36624 44183 TLB shootdowns TRM: 0 0 0 0 Thermal event interrupts THR: 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 Machine check exceptions MCP: 22 22 22 22 Machine check polls ERR: 3 MIS: 0
Jak widać powyżej jest to 4 procesorowa maszyna (w rzeczywistości są to dwa procesory dwurdzeniowe). Pierwsza kolumna (bez etykiety) jest listą IRQ używanych w systemie. Wiersze opisane literami (np. “NMI”, “LOC”) są częścią innych sterowników używanych w systemie, które nie są dla nas dostępne z tego poziomu. Na przykład NMI (ang. Non-Maskable Interrupts) są to przerwania, których nie można wyłączyć za pomocą maski przerwań. Służą one do obsługi nienaprawialnych błędów wymagających natychmiastowej uwagi – takie jak błędy chipsetu, czy pamięci (bit parzystości, ECC).
Od drugiej aż do czwartej kolumny (z etykietami CPU0 – CPU3) pokazywana jest ilość razy jaką dany procesor obsłużył wybrane żądanie IRQ. Na przykład wszystkie dwa procesory obsłużyły mniej więcej taką samą liczbę przerwań dla IRQ 14 (CPU0 – 12498, CPU2 – 12818). Zanim dojdziemy do szóstej kolumny należy w tym momencie wspomnieć, że systemy wieloprocesorowe (uniprocesorowe produkowane od 2 września 2000 r. – PC 2001) sterują statyczną i dynamiczną dystrybucją przerwań pomiędzy procesorami za pomocą układów APIC (ang. Advnaced Programmable Interrupt Controller). To właśnie zaawansowane programowalne kontrolery przerwań są odpowiedzialne za obsługę przerwań sprzętowych (stały się zamiennikami dla kontrolerów przerwań w stylu PC, obsługującym SMP). Te rozproszone układy składają się z I/O APIC (APIC wejścia / wyjścia), który znajduje się w chipsecie płyty głównej oraz Local APIC (lokalnym APIC) znajdującym się w samym procesorze. Docierające poprzez linie IRQ przerwanie jest rejestrowane przez I/O APIC, które następnie informuje o tym Local APIC. Ten z kolei pozwala podejmować decyzję, czy dana jednostka obliczeniowa może w danej chwili współpracować z magistralą APIC. Między innymi dlatego w systemach SMP zaleca się stosowanie jednakowych, lokalnych układów APIC w każdym procesorze wchodzącym w skład serwera. W praktyce oznacza to używanie procesorów dokładnie z tej samej serii produkcyjnej np. dwóch procesorów Intel(R) Xeon(R) CPU E5420 @ 2.5 GHz. W starszych komputerach jednoprocesorowych APIC lokalny i I/O były domyślnie wyłączone i musiały być włączane ręcznie za pomocą parametru jądra apic
. Aktualnie (szczególnie dla systemów 64-bitowych) są one domyślnie włączone. To samo tyczy się systemu Linux, który standardowo posiada obsługę tego kontrolera.
Wracając do szóstej kolumny – mówi ona nam o tym, czy sterownik danego urządzenia jest powiązany z obsługą przerwań za pomocą kontrolera I/O APIC. Głównym powodem, dla którego należy zwracać uwagę na tę kolumnę jest fakt, że przypisywanie określonych przerwań do określonych procesorów jest możliwe tylko dla tych urządzeń, których przerwania obsługiwane są przez I/O APIC. Ostatnia – siódma kolumna – określa jakie urządzenie jest przypisane do jakiego przerwania. Jeśli skróty te nam nic nie mówią możemy wykorzystać polecenie: lspci -v | more, w celu uzyskania bardziej szczegółowego opisu:
00:1f.2 SATA controller: Intel SATA AHCI Controller (rev 09) (prog-if 01 [AHCI 1.0]) Subsystem: Dell Device 01c1 Flags: bus master, 66MHz, medium devsel, latency 0, IRQ 20 I/O ports at fe00 [size=8] I/O ports at fe10 [size=4] I/O ports at fe20 [size=8] I/O ports at fe30 [size=4] I/O ports at fec0 [size=32] Memory at f0000000 (32-bit, non-prefetchable) [size=1K] Capabilities:Kernel driver in use: ahci Kernel modules: ahci
W ten sposób wiemy, że kontroler dysków SATA obsługiwany jest przez IRQ 20, a te z kolei przetwarzane jest przez I/O APIC. Spójrzmy teraz jak wygląda rzeczywista obsługa tego przerwania przez procesory:
root@darkstar:~# cat /proc/irq/20/smp_affinity 01
Wartość 01 jest maską bitową określającą, do którego procesora będą kierowane żądania IRQ 20. Liczba znajdująca się w pliku “smp_affinity” jest przedstawiona w formacie szesnastkowym, a każda zapisana w nim cyfra reprezentuje grupę 4 procesorów (pierwsze 4 procesory z lewej reprezentowane są przez ostatnią wartość z prawej). Dlatego w celu prawidłowej manipulacji przerwaniami musimy przekształcić nasz układ bitów z binarnego na szesnastkowy jeszcze przed ich ustawieniem w wirtualnym systemie plików /proc
.
Binarny Hex CPU 0 0001 1 CPU 1 0010 2 CPU 2 0100 4 CPU 3 1000 8
Czyli wartość heksadecymalna 01 oznacza, że do obsługi IRQ 20 został wyznaczony pierwszy procesor – CPU0. Jeśli chcemy teraz, aby przerwanie to było obsługiwane zarówno przez CPU0 oraz CPU2 musimy dodać wartości binarne 0001 oraz 0100, co da nam 0101 (hex: 1+4 = 5):
echo 05 > /proc/irq/20/smp_affinity
Dla wszystkich czterech procesorów dodajemy wszystkie wartości: 1+2+4+8 = F (1111):
echo 0f > /proc/irq/20/smp_affinity
Jeśli dla danego przerwania zostanie zdefiniowanych wiele procesorów – będzie ono zawsze używało najmniej obciążonego. Nazywa się to najniższym priorytetem routingu APIC (ang. lowest priority APIC routing). Jakie zastosowanie może mieć SMP IRQ Affinity w codziennym użytkowaniu serwerów wieloprocesorowych? Na przykład możemy rozłożyć obciążenie związane z wieloma kartami sieciowymi w wieloprocesorowej maszynie pełniącej rolę routera – przypisując przerwania jednej karty do jednego z wielu procesorów. W przypadku serwerów bazodanowych możemy przypisać określoną liczbę procesorów do obsługi kontrolerów dyskowych, a wydzielając jeden do obsługi ruchu sieciowego w celu poprawienia jego czasów odpowiedzi. Wszystko tak naprawdę zależy od ilości posiadanych jednostek obliczeniowych i roli jaką pełni nasz serwer. Jeśli nie zależy nam na ręcznym rozkładaniu przerwań sprzętowych możemy również skorzystać z IRQ Balance, który służy do “niewidzialnego” dla nas rozdzielania przerwań na procesory i rdzenie znajdujące się w naszym systemie komputerowym, w celu znalezienia kompromisu pomiędzy wydajnością, a oszczędnością energii (i nie tylko).
Więcej informacji: źródła jądra: /Documentation/x86/i386/IO-APIC.txt, /Documentation/IRQ-affinity.txt, Bagiński M., K. Wasielewska, “Sprzętowa implementacja SMP w systemie Linux” (2003), SMP IRQ Affinity, irqbalance