Linux Kernel 관련 온라인 강의 요약본입니다.
https://olc.kr/course/course_online_view.jsp?id=35&s_keyword=Kernel&x=0&y=0
들어가기 앞서
해당 강의의 제목은 Scheduling이라고 되어있지만 실상은 Interrupt에 대한 내용이 대부분입니다.
Terminology
Hz
Hz란 특정 주기를 갖는 반복된 현상이 1초에 몇 번 반복되는지를 의미합니다.
CPU에서 Hz는 clock 주파수를 의미하며, 1초에 몇 번의 clock 사이클이 발생하는지 나타냅니다.
Meaning in CPU
예를 들어 아래의 CPU의 경우 1초에 3GHz(30억) 번의 clock 사이클이 발생합니다.
인텔 코어i9-13세대 13900KF
CPU의 클럭이 높다는 것은 1초에 더 많은 동작을 수행할 수 있다는 뜻이며, 성능 = clock * IPC로 볼 수 있습니다.
Meaning in Hardware
아래와 같이 대부분의 아키텍처의 Hz는 100으로 설정되어 있습니다.
이는 1초에 몇 번 타이머 인터럽트가 발생하는지를 나타내며, 100이면 1초에 100번 타이머 인터럽트가 발생합니다.
jiffies
시스템이 부팅된 뒤 타이머 인터럽트가 발생한 빈도를 저장합니다. 전역변수로 저장됩니다.
HZ가 100이면 1초에 100번 증가합니다.
Hardware Clocks and Timers
운영체제에서 시간을 관리하는데, System Timer와 Real-Time Clock 두 가지를 사용합니다.
System Timer
CPU로 HZ 주기의 타이머 인터럽트를 발생시키며, 커널이 현재까지 몇 개의 타이머 tick이 지났는지 알아내기 위해 사용합니다.
Real-Time Clock(RTC)
전원이 꺼지더라도 내부에 배터리가 존재해서 유지되는 시계입니다. 현재 날짜와 시각(몇 년 몇 월 몇 시)를 알기 위해 사용합니다.
Timer Interrupt Handler
전에는 2.6.x 버전 코드로 분석하더니 지금은 2.5.x 버전입니다. 개념만 이해하면 되기 때문에 계속 진행하겠습니다.
HZ를 기준으로 1초에 100번 타이머 인터럽트가 호출됩니다.
해당 인터럽트가 발생하면 인터럽트 핸들러가 do_timer 함수를 호출하고, jiffies_64를 1 증가시킵니다.
void do_timer(struct pt_regs *regs)
{
jiffies_64++;
#ifndef CONFIG_SMP
/* SMP process accounting uses the local APIC timer */
update_process_times(user_mode(regs));
#endif
update_times();
}
C
복사
이후 update_process_times를 통해 현재 실행 중인 PCB에 커널 모드인지 사용자 모드인지에 따라 utime(user time), stime(system time)을 1 tick 증가시킵니다.
utime과 stime에 실행된 tick 수가 저장되며, tick / HZ를 계산하면 커널과 사용자에서 CPU를 점유한 시간을 계산할 수 있습니다.
Interrupt
인터럽트(interrupt)는 CPU에서 프로그램을 실행하고 있을 때, 일시적으로 실행을 중단하고 다른 특정 기능을 수행할 수 있도록 하는 메커니즘입니다.
아래의 그림의 경우 CPU가 프로그램을 실행하면서, fetch → decode → execution 단계를 반복합니다. 명령어 실행이 끝나면 PC(Program Counter)를 증가시켜 다음 명령어를 실행할 준비를 합니다.
이때 인터럽트(interrupt)가 발생하면 CPU는 내부에 Interrup request bit를 1로 설정되어 있으면, 현재 실행 상태(레지스터 값 등)를 저장한 뒤 PC를 인터럽트 핸들러 주소로 변경합니다.
이후 인터럽트 핸들러 역시 fetch → decode → execution 과정을 거쳐 실행됩니다.
부팅과 같이 인터럽트 요청이 들어와도 이를 처리하고싶지 않은 경우, CPU 내부에 존재하는 Interrupt request bit를 0으로 disable하여 요청을 무시하게 됩니다.
앞에서 말한 타이머 인터럽트란 CPU가 다른 프로그램을 실행하고 있을 때, 일정한 시간 간격(HZ)를 기준으로 실행을 중단하고 인터럽트 핸들러(ex. do_timer)를 실행하는 것 입니다.
Interrupt Controller
실제 인터럽트는 disk, printer, keyboard, mouse 등 많은 하드웨어 디바이스로부터 발생할 수 있습니다.
각 디바이스가 서로 다른 방식으로 인터럽트를 요청하게 되면, 커널 인터럽트 처리 로직이 복잡해지게 됩니다.
이를 방지하기 위해 커널은 Interrupt Controller를 두어, 여러 디바이스에서 발생하는 인터럽트를 일괄적으로 관리하고 CPU에 전달하도록 설계합니다.
PIC(Programmable Interrupt Controller)
우리가 사용하는 컴퓨터는 명령어(instruction)을 순차적이고 동기적으로 실행합니다.
반면, 프로그램의 흐름과 무관하게 예상하지 못한 시점에 발생하는 이벤트를 인터럽트(interrupt)라고 부르게 됩니다.
PIC(Programmable Interrupt Controller)는 여러 하드웨어 디바이스로부터 발생하는 인터럽트를 효율적으로 관리하고 처리하기 위해 만들어진 장치입니다.
각 디바이스는 인터럽트 요청을 IRQ(Interrupt ReQuest) 라인을 통해 PIC로 전달하고, PIC는 이를 정리하여 CPU가 처리할 수 있도록 전달합니다.
하나씩 PIC에 존재하는 레지스터를 보겠습니다.
1.
IMR(Interrupt Mask Register)
각 IRQ 라인을 차단 할지 여부를 저장하는 레지스터입니다.
2.
IRR(Interrupt Request Register)
요청된 인터럽트가 대기 중인지 기록합니다. IRQ 라인에 인터럽트가 들어오면 1로 설정됩니다.
3.
Priority register
여러 인터럽트가 동시에 들어올 때 어떤 IRQ를 먼저 처리할지 결정합니다.
4.
ISR(In-Service Register)
현재 CPU가 처리 중인 인터럽트를 기록합니다. CPU가 인터럽트 핸들러를 실행 중이면, 해당 IRQ 비트가 ISR에 설정됩니다.
5.
Encode IRQ line
선택된 IRQ 번호를 인터럽트 벡터 번호로 변환합니다.
6.
Send iterrupt signal to CPU
PIC가 CPU의 INTR 핀에 인터럽트 신호를 전달합니다.
7.
Waits for ack from CPU
CPU가 인터럽트를 인식하면 ACK(Interrupt Acknowledge) 신호를 PIC로 보냅니다.
전체적인 과정을 정리해서 말해보겠습니다.
1.
디바이스가 IRQ 라인을 통해 인터럽트를 요청합니다.
2.
PIC는 IMR을 확인하여 1로 마스크되어 있지 않다면, IRR(Interrupt Request Register)에 요청을 기록합니다.
3.
IRR(Interrupt Request Register)에 여러 인터럽트가 존재할 경우, Priority Register를 기준으로 가장 우선순위가 높은 IRQ를 선택합니다.
4.
선택된 IRQ가 CPU에 전달되면, 해당 IRQ는 ISR(In-Service Register)로 이동하여 현재 처리 중인 인터럽트로 표시됩니다.
5.
PIC는 CPU의 INTR 핀을 통해 인터럽트 신호를 전달합니다.
6.
CPU가 인터럽트를 인식하면 ACK(Interrupt Acknowledge) 신호를 PIC로 보냅니다.
7.
PIC는 ACK를 받은 후 해당 IRQ에 대응하는 인터럽트 벡터 번호를 CPU에 전달하고, CPU는 해당 인터럽트 핸들러를 실행합니다.
Many devices per IRQ line
실제로 PIC에는 여러 디바이스가 연결되어 있습니다.
각 디바이스는 특정 IRQ 라인에 연결되어 있으며, 인터럽트가 발생하면 해당 요청이 PIC로 전달됩니다.
PIC는 인터럽트 우선순위를 고려하여 CPU가 처리할 인터럽트를 선택해 전달합니다.
Interrupt Handling in Multiprocessor
다중 CPU(Core) 상태에서 인터럽트를 처리하는 방식에 대해서 알아보겠습니다.
Local & multi-APIC
아래의 그림에서는 두 개의 CPU가 물리적으로 존재하고 있습니다.
각 CPU는 자신만의 Local APIC(Advanced PIC)를 가지고 있습니다.
Local APIC는 CPU 전용 인터럽트 컨트롤러로 해당 CPU에 들어오는 인터럽트를 처리하고 타이머 인터럽트를 발생시킵니다.
모든 CPU는 하나의 bus를 통해 multi APIC와 연결됩니다.
multi APIC는 여러 I/O 디바이스에서 발생한 IRQ를 수집하고, 어떤 CPU에 인터럽트를 전달할지 결정하여 해당 CPU의 Local APIC로 인터럽트를 전달합니다.
Bus & I/O Interface
다시 좀 더 넓혀서 보면 CPU는 MMU(Memory Management Unit)와 연결되어 있습니다.
MMU는 CPU로부터 전달받은 가상 메모리 주소를 실제 메모리 주소로 변환하는 역할을 합니다.
이때 MMU에 전달된 가상 메모리 주소가 Low Address(0x000000 ~ 0x7777xxx)이면 물리 메모리 주소의 값을, High Address(0x7777xxx~0x777777)이면 I/O bus로 전달합니다.
I/O Interface
I/O interface는 CPU와 실제 하드웨어 디바이스 사이의 인터페이스입니다.
CPU는 디바이스를 직접 제어하지 않고, I/O interface에 존재하는 레지스터를 읽고 쓰는 방식으로 디바이스를 제어합니다.
I/O interface 구성요소
1.
address
디바이스 내부에서 어떤 레지스터를 접근할 지 지정합니다.
2.
data
CPU
디바이스 간 실제 데이터를 통신하는 공간입니다.
3.
control
디바이스에게 수행할 동작을 지시하는 레지스터입니다.
4.
status
디바이스의 현재 상태를 CPU에 알려주는 레지스터입니다.
5.
vendor id
디바이스 제조사를 식별하기 위한 값입니다.
6.
device id
제조사 내에서 디바이스 종류를 식별하기 위한 값입니다.
7.
interrupt line
해당 디바이스가 어떤 IRQ 라인을 사용하는지 나타냅니다.
Multiprocessing
SMP
대칭형 멀티 프로세싱(SMP)은 두 개 이상의 프로세서(CPU)가 하나의 메모리와 I/O 디바이스 자원을 공유하는 구조를 의미합니다.
하나의 운영체제를 공유하여 실행함으로 프로세스 스케줄링과 인터럽트 로드 밸런싱을 신경써야 합니다.
AMP(Asymmetric Multiprocessing)
비대칭형 멀티 프로세싱(AMP)은 두 개 이상의 프로세서(CPU)가 각자 자신만의 역할과 실행 환경을 가지는 구조입니다.
하나의 CPU가 전체 시스템을 관리하지 않기 때문에 SMP와 달리 중앙 집중적인 스케줄링이나 인터럽트 로드 벨런싱이 필요하지 않습니다.
SMP(Symeetric Multiprocessing)
아래 그림과 같이 disk에서 인터럽트 요청이 발생하면, APIC는 어떤 CPU에게 인터럽트 처리를 전달할 지 결정하기 위해 로드 밸런싱을 수행해야 합니다IRQ .
IRQ distribution algorithm
IRQ 로드 밸런싱 방법에는 다음 두 가지가 있습니다.
1.
Static distribution
IRQ를 특정 CPU에 고정해서 처리하는 방식입니다.
인터럽트가 항상 동일한 CPU로 전달된다는 특징이 있습니다.
2.
Dynamic distribution
시스템 부하를 고려해 IRQ를 여러 CPU로 분산하는 방식입니다.
커널이 CPU 상태를 기준으로 동적으로 결정하는 특징이 있습니다D.
Dynamic IRQ distribution algorithm
동적 IRQ 분배 방식은 현재 시스템 부하를 기준으로 가장 여유 있는 CPU에 인터럽트를 전달하는 방식입니다.
IRQ는 가장 낮은 우선순위 프로세스를 실행 중인 CPU로 전달됩니다. 만약 CPU가 동일한 우선순위 프로세스를 실행 중인 경우 Arbitration algorithm을 수행합니다.
Arbitration algorithm
각 CPU는 자신만의 counter 값이 존재합니다.
IRQ 분배 시 counter 값이 가장 큰 CPU를 선택하고, 선택된 CPU의 counter를 0으로 초기화합니다.
선택되지 않은 CPU들의 counter는 1씩 증가합니다.
이를 통해 counter 값을 기준으로 인터럽트를 공평하게 분배하는 로드 밸런싱을 수행합A니다.
AMP(Asymmetric Multiprocessing)
비대칭 멀티프로세싱(AMP)은 하나의 Master CPU만 커널과 I/O를 처리하고, 나머지 CPU들은 사용자 코드만 실행하는 비대칭 구조를 가집니다.
Master CPU
OS 커널을 실행하는 CPU입니다.
모든 시스템 콜과 모든 I/O 디바이스 제어를 수행하며, PIC와 직접 연결되어 인터럽트를 처리합니다.
Slave CPU
사용자 코드만 실행하는 CPU입니다.
시스템 콜이 필요한 경우, 요청을 Master CPU에게 전달하여 처리를 맡깁니다.
Multiprocessing
현대 시스템은 비대칭 멀티프로세싱(AMP)을 사용하지 않고 대칭 멀티프로세싱(SMP)을 사용합니다.
AMP는 하나의 Master CPU에게 모든 커널 처리와 I/O가 집중되어 병목 현상이 발생하고 CPU 자원을 효율적으로 활용하기 어렵습니다.
또한 Master CPU에 장애가 발생하는 경우 시스템 전체를 사용할 수 없다는 문제가 있습니다.
반면 SMP는 모든 CPU가 동일한 권한으로 커널을 실행할 수 있어 부하를 여러 CPU에 분산할 수 있으며, 확장성과 성능 면에서 유리하기 때문에 현대 시스템은 SMP 구조를 채택하고 있습니다.














