운영체제
MSI-X 인터럽트는 어떻게 동작할까?
joonior
2025. 4. 1. 01:33
MSI-X는 PCIe 장치가 인터럽트를 발생시키는 고성능 인터럽트 방식으로, 기존의 레거시 인터럽트(IRQ) 및 MSI(Message Signaled Interrupts) 방식보다 더 유연하고 확장성이 뛰어나다.
NVMe SSD나 NIC이 사용하는 인터럽트 방식이다.
개요
MSI-X는 기존 인터럽트 방식의 단점을 해결하기 위해 설계되었다.
- 레거시 인터럽트(IRQ)
- 모든 장치가 인터럽트 라인을 공유하기 때문에 충돌할 수 있다.
- 순차적으로 처리되기 때문에 인터럽트 처리 성능이 낮다.
- MSI(Message Signaled Interrupts)
- 인터럽트를 메모리 쓰기 방식으로 전달하여 기존 레거시 인터럽트에 비해 성능이 뛰어나다.
- 인터럽트 벡터 수가 제한적이다. (최대 32개)
- MSI-X
- 기존 MSI에서 인터럽트 벡터를 2048개까지 확장하였다.
- 각 인터럽트 벡터를 개별 CPU 코어에 할당 가능하다.
MSI-X 동작 과정
1. 인터럽트 설정
- 운영체제는 PCIe 컨트롤러를 통해 MSI-X를 활성화한다.
- MSI-X 테이블과 PBA(Pending Bit Array) 영역이 PCIe 장치의 BAR(Base Address Register) 메모리에 생성된다.
- MSI-X Table: 인터럽트 벡터와 해당 인터럽트의 처리 주소를 저장하는 테이블이다.
- PBA: 발생한 인터럽트의 Pending 상태를 저장한다.
2. 인터럽트 발생
- PCIe 장치는 MSI-X 테이블을 참조하여 적절한 인터럽트 벡터를 선택한다.
- 인터럽트 정보를 메모리에 써서 CPU에 인터럽트 정보를 전달한다.
- 해당 인터럽트 벡터를 처리할 CPU 코어가 인터럽트 핸들러를 실행한다.
3. 인터럽트 핸들링
- CPU는 인터럽트 요청을 확인하고, 해당 인터럽트 핸들러를 실행한다.
- PCIe 장치는 PBA를 업데이트하여 인터럽트 상태를 갱신한다.
- 인터럽트 처리가 완료되면 PBA 비트를 클리어하고, 인터럽트는 종료된다.
MSI-X의 주요 특징
1. 인터럽트 벡터 확장
- MSI는 최대 32개의 인터럽트 벡터만 지원하지만, MSI-X는 최대 2048개의 인터럽트 벡터를 제공한다.
- 이는 NVMe, 고속 네트워크 카드(NIC) 등의 고성능 PCIe 장치에서 중요한 역할을 한다.
2. 각 인터럽트를 특정 CPU 코어에 할당 가능
- 멀티코어 CPU 환경에서 특정 코어에 인터럽트를 할당하여 캐시 로컬리티(Cache Locality) 최적화가 가능하다.
- ex) 네트워크 카드(NIC)의 RX/TX 큐 또는 NVMe SSD의 큐를 특정 CPU에 고정.
3. 인터럽트 Coalescing 지원
- 짧은 시간 내 너무 많은 인터럽트가 발생하면 인터럽트를 묶어서(Coalescing) 처리 가능하다.
- 네트워크 카드(NIC) 및 고속 스토리지에서 인터럽트 부하를 줄이는 데 사용된다.
4. 레거시 인터럽트 비의존
- 기존의 IRQ(Interrupt Request Line) 방식을 사용하지 않으며, PCIe 기반에서 독립적으로 동작한다.
MSI-X 인터럽트가 코어에 할당되는 과정과 처리 방식
MSI-X 인터럽트는 PCIe 장치가 메모리에 인터럽트 요청(Write)을 기록하면, CPU의 인터럽트 컨트롤러(APIC)가 이를 감지하고 해당 코어에 인터럽트를 전달하는 방식으로 동작한다.
1. 인터럽트 할당 과정: CPU 코어에 어떻게 배정되나?
MSI-X는 각 인터럽트 벡터를 특정 CPU 코어에 할당할 수 있도록 설계되었다. 인터럽트가 특정 코어에 할당되는 과정은 다음과 같다.
(1) 운영체제가 인터럽트 벡터를 설정
- PCIe 장치가 MSI-X를 지원하면, OS는 PCIe Configuration Space에서 MSI-X Table과 PBA(Pending Bit Array) 주소를 읽고 설정함.
- OS는 MSI-X 테이블을 수정하여 특정 인터럽트 벡터를 특정 CPU 코어에 할당.
- 이때 IRQ Affinity를 조정하여 특정 CPU 코어에서만 해당 인터럽트를 처리하도록 설정 가능.
- 예: echo <CPU_ID> > /proc/irq/<IRQ_NUM>/smp_affinity
(2) 인터럽트 발생 시, PCIe 장치가 특정 벡터를 선택
- PCIe 장치는 MSI-X 테이블을 참조하여 인터럽트 벡터를 선택.
- 선택된 벡터에 대한 인터럽트 요청을 PCIe 메모리 쓰기(Write) 방식으로 CPU에 전달.
(3) 인터럽트 컨트롤러(APIC)가 이를 감지하고 코어에 전달
- PCIe 장치가 메모리 쓰기 방식으로 특정 주소(Interrupt Vector Table)에 데이터를 기록하면,
- APIC(Advanced Programmable Interrupt Controller)가 이를 감지하고,
- 인터럽트를 해당 벡터에 할당된 CPU 코어로 라우팅.
- APIC는 IO-APIC(Input/Output APIC) → LAPIC(Local APIC) 순서로 인터럽트를 전달.
2. 메모리에 기록된 인터럽트는 어떻게 읽는가?
(1) PCIe 장치가 인터럽트 요청을 메모리에 씀
- PCIe 장치는 인터럽트 요청을 처리하기 위해 특정 메모리 주소에 데이터를 씀.
- 이는 일반적인 PCIe Memory Write 트랜잭션이며, CPU의 인터럽트 컨트롤러가 이를 감지.
(2) 인터럽트 컨트롤러(APIC)가 해당 메모리 주소를 감시
- APIC는 특정 주소 범위를 감시하여, 해당 메모리에 값이 기록되면 인터럽트를 인지함.
- MSI-X 방식에서는 실제 인터럽트 컨트롤러가 특정 주소의 쓰기 이벤트를 감지하여 동작.
(3) 인터럽트 컨트롤러가 인터럽트 벡터를 확인하고 해당 CPU에 인터럽트 전달
- IO-APIC는 MSI-X 테이블을 참조하여 해당 인터럽트가 어느 CPU로 가야 하는지 결정.
- 해당 벡터를 CPU의 Local APIC (LAPIC)에 전달하여 인터럽트 핸들링 시작.
3. 인터럽트 컨트롤러(APIC)의 역할
인터럽트 컨트롤러는 APIC(Advanced Programmable Interrupt Controller)로 구성되며, 두 가지 주요 컴포넌트가 있음.
(1) IO-APIC (Input/Output APIC)
- IO-APIC는 외부 장치(PICe, 네트워크 카드 등)에서 발생하는 인터럽트를 수집하는 역할.
- MSI-X 방식에서는 PCIe 장치의 메모리 쓰기를 감지하여 인터럽트를 처리.
- OS가 특정 인터럽트를 특정 CPU 코어로 보내도록 설정 가능 (/proc/irq/ 활용).
(2) Local APIC (LAPIC)
- LAPIC는 각 CPU 코어에 존재하는 인터럽트 컨트롤러.
- IO-APIC에서 받은 인터럽트를 해당 CPU 코어에 전달하고 실행.