운영체제

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 코어에 전달하고 실행.