이번 문서의 목표: 이 파일을 다 읽으면 프로그램 제어 I/O·인터럽트 기반 I/O·DMA 세 방식의 차이를 설명하고, 버스 구조가 이들을 어떻게 지원하는지 이해하며, DMA의 사이클 스틸이 CPU 실행 속도에 미치는 영향을 계산할 수 있다.
왜 입출력 방식이 여러 가지인가
CPU는 계산을 빠르게 하지만, 키보드·디스크·네트워크 카드 같은 입출력 장치(I/O device)는 CPU보다 훨씬 느리다. 예를 들어 키보드는 사람이 누르는 속도로만 데이터를 주고, 디스크도 CPU 클록 주기에 비하면 매우 느리다. 이 속도 차이를 어떻게 다루느냐에 따라 입출력 방식이 세 가지로 나뉜다: 프로그램 제어 I/O, 인터럽트 기반 I/O, DMA(Direct Memory Access, 직접 기억장치 접근).
쉽게 말하면: 셋의 차이는 “느린 장치를 기다리는 동안 CPU가 무엇을 하는가”에 있다. 계속 물어보며 기다리는지(프로그램 I/O), 다른 일을 하다가 알림을 받는지(인터럽트), 아예 CPU를 거치지 않고 장치와 메모리가 직접 데이터를 주고받는지(DMA)의 차이다.
프로그램 제어 I/O: CPU가 계속 물어본다
프로그램 제어 I/O(programmed I/O)는 CPU가 입출력 장치의 상태 레지스터(status register)를 반복해서 읽으며 “준비됐는지” 계속 확인하는 방식이다. 이렇게 상태를 반복 확인하는 것을 폴링(polling)이라 한다. 장치가 준비됐다는 신호를 줄 때까지 CPU는 오직 그 확인 루프만 돈다.
- 장점: 구현이 단순하고, 하드웨어 비용이 거의 들지 않는다.
- 단점: 장치가 느릴수록 CPU가 아무 일도 못 하고 낭비하는 시간(busy-wait, 바쁜 대기)이 길어진다. CPU 자원의 명백한 낭비다.
인터럽트 기반 I/O: 다른 일을 하다가 알림을 받는다
인터럽트 기반 I/O(interrupt-driven I/O)는 CPU가 입출력을 요청한 뒤 계속 확인하지 않고 다른 프로그램(또는 다른 작업)을 실행한다. 장치가 준비되면 인터럽트(interrupt) 신호를 CPU에 보내고, CPU는 하던 일을 잠시 멈춘 뒤(12편에서 다룬 인터럽트 처리 흐름을 그대로 따른다) 필요한 데이터를 주고받고, 다시 원래 하던 일로 돌아간다.
- 장점: CPU가 장치를 기다리며 낭비하는 시간이 사라지고, 그 시간에 다른 작업을 수행할 수 있다.
- 단점: 데이터를 한 단어(word)씩 주고받을 때마다 매번 인터럽트가 발생하므로, 대량의 데이터(예: 디스크 파일 전체)를 옮길 때는 인터럽트 처리 오버헤드(문맥 저장·복원 등)가 누적되어 비효율적이다.
DMA: CPU를 거치지 않고 장치와 메모리가 직접 통신한다
쉽게 말하면: DMA는 CPU에게 “이 주소부터 이만큼 옮겨 놔”라고 딱 한 번만 지시하고, 실제 데이터 전송은 CPU를 완전히 거치지 않은 채 DMA 컨트롤러가 장치와 메모리 사이에서 직접 처리하는 방식이다.
DMA(Direct Memory Access)는 CPU 대신 DMA 컨트롤러(DMA controller)라는 전용 하드웨어가 입출력 장치와 주기억장치 사이의 데이터 전송을 도맡는 방식이다. CPU는 DMA 컨트롤러에게 시작 주소·전송할 데이터 양·전송 방향(읽기/쓰기) 같은 정보를 딱 한 번 설정해 주고, 이후에는 다른 명령어를 계속 실행한다. DMA 컨트롤러가 전송을 마치면 그때 한 번의 인터럽트로 CPU에 완료를 알린다.
- 장점: 대량의 데이터를 옮길 때 CPU가 단어 하나하나에 개입할 필요가 없어, CPU는 그 시간에 다른 계산을 계속할 수 있다.
- 단점: DMA 컨트롤러가 버스(bus)를 사용하는 동안에는 CPU가 버스를 쓰지 못하므로(뒤에서 다룰 사이클 스틸), 완전히 “공짜”는 아니다. 또한 DMA 컨트롤러 자체가 별도의 하드웨어 비용이다.
세 방식 비교표
| 구분 | 프로그램 제어 I/O | 인터럽트 기반 I/O | DMA |
|---|---|---|---|
| CPU 개입 방식 | 상태를 계속 폴링(반복 확인) | 준비될 때까지 다른 일을 하다가 인터럽트로 알림 | 시작만 설정, 전송 자체는 개입하지 않음 |
| 데이터 전송 단위당 CPU 부담 | 매우 큼(계속 대기) | 단어(word) 단위마다 인터럽트 처리 | 전송 전체가 끝나야 인터럽트 1회 |
| 대량 데이터 전송 효율 | 매우 낮음 | 중간(단어마다 오버헤드 누적) | 높음 |
| 필요한 추가 하드웨어 | 거의 없음 | 인터럽트 컨트롤러 | DMA 컨트롤러 |
| CPU와 버스의 관계 | CPU가 버스를 계속 점유 | CPU가 버스를 필요할 때만 점유 | DMA 컨트롤러가 버스를 일시적으로 점유(사이클 스틸) |
시험 함정: “인터럽트 기반 I/O와 DMA 모두 CPU가 놀지 않게 해 준다”는 점은 같지만, DMA는 데이터 전송 자체에 CPU가 전혀 관여하지 않는다는 점이 다르다. 인터럽트 기반 I/O는 여전히 CPU가 한 단어씩 직접 옮기고, DMA는 데이터 이동 자체를 하드웨어(DMA 컨트롤러)가 전담한다. “인터럽트 방식도 대량 전송에 DMA만큼 효율적이다”는 진술은 틀린 설명이다.
버스: CPU·메모리·I/O 장치를 잇는 공용 통로
쉽게 말하면: 버스(bus)는 CPU, 메모리, 입출력 장치가 서로 데이터를 주고받기 위해 함께 쓰는 공용 전선 다발이다. 한 번에 한 쪽만 쓸 수 있어서 “누가 지금 버스를 쓸지” 정하는 규칙이 필요하다.
버스는 보통 세 종류의 선으로 구성된다.
- 주소 버스(address bus): 어느 위치(메모리 주소 또는 장치 번호)에 접근할지를 실어 나른다.
- 데이터 버스(data bus): 실제로 주고받을 데이터를 실어 나른다.
- 제어 버스(control bus): 읽기/쓰기 신호, 인터럽트 요청, 버스 사용 요청·승인 신호 같은 제어 정보를 실어 나른다.
버스는 한 번에 하나의 장치(또는 CPU)만 데이터를 실을 수 있는 공용 자원이므로, DMA 컨트롤러가 버스를 쓰려면 CPU로부터 버스 사용권을 넘겨받아야 한다. 이 과정을 버스 중재(bus arbitration)라 하며, DMA 컨트롤러가 버스 요청(bus request) 신호를 보내면 CPU가 현재 진행 중인 버스 사이클을 마친 뒤 버스 승인(bus grant) 신호로 응답해 버스 사용권을 넘겨준다.
DMA의 사이클 스틸: 버스를 잠깐씩 빌려 쓰는 방식
쉽게 말하면: 사이클 스틸(cycle stealing)은 DMA 컨트롤러가 CPU의 버스 사용을 완전히 막지 않고, CPU가 버스를 쓰지 않는 아주 짧은 순간순간을 “몰래 빌려” 한 워드씩 전송하는 방식이다.
DMA가 데이터를 전송하는 방법은 크게 두 가지다.
- 버스트 모드(burst mode): DMA 컨트롤러가 버스를 한 번에 넘겨받아 전송할 데이터 전체를 연속으로 옮긴 뒤 반환한다. 전송은 빠르지만 그동안 CPU는 버스를 전혀 쓸 수 없다.
- 사이클 스틸(cycle stealing): DMA 컨트롤러가 한 워드(word)를 옮길 때마다 버스 사용권을 짧게 빌렸다가 곧바로 반환한다. CPU 입장에서는 명령어 실행 사이사이에 아주 짧은 지연이 간간이 끼어드는 것처럼 느껴진다.
사이클 스틸이 CPU 성능에 미치는 영향 계산
조건: 주기억장치의 메모리 사이클 시간(한 번의 메모리 접근에 걸리는 시간)이 다. 입출력 장치가 ()마다 워드 하나씩 전송을 요청하며, 요청이 올 때마다 DMA가 메모리 사이클 1회(200ns)를 훔쳐 쓴다.
1단계: 장치가 요청하는 주기(5000ns) 동안 CPU가 원래 쓸 수 있었던 메모리 사이클 수를 구한다.
2단계: 이 25사이클 중 DMA가 훔쳐 가는 사이클 수를 확인한다. 조건에서 요청 1회당 1사이클을 훔친다고 했으므로 1사이클이다.
3단계: DMA가 차지하는 비율(사이클 스틸로 인한 CPU 성능 저하율)을 계산한다.
결과 해석: CPU는 원래 25사이클 모두 자신의 명령어 실행에 쓸 수 있었지만, DMA가 그중 1사이클을 가로채면서 실질적으로 4%의 시간을 DMA에게 내주는 셈이다. 즉 CPU의 실행 속도가 이론상 최대 대비 약 4% 느려진다고 볼 수 있다. 만약 장치의 전송 요청 주기가 더 짧아지면(예: 로 두 배 빨라지면) 25사이클이 12.5사이클로 줄어 저하율은 로 커진다 — DMA를 쓰는 장치가 빠를수록(자주 요청할수록) CPU가 내주는 사이클 비율도 커진다는 뜻이다.
시험 함정: 사이클 스틸은 CPU를 완전히 멈추는 것이 아니라 메모리 사이클 하나만 짧게 지연시키는 것이다. “DMA 사이클 스틸 동안 CPU가 완전히 정지한다”는 진술과, “사이클 스틸이 인터럽트 방식과 동일하게 문맥 저장·복원을 수행한다”는 진술 모두 틀렸다. 사이클 스틸은 인터럽트가 아니라 버스 사용권을 아주 짧게 빌리는 하드웨어적 지연이다.
자주 틀리는 점
- DMA를 “CPU 개입이 전혀 없는 방식”으로 착각하기 쉽지만, 정확히는 전송 도중의 개입이 없을 뿐 시작 설정(주소·길이·방향)과 완료 후 인터럽트 처리에는 CPU가 관여한다.
- 폴링(프로그램 제어 I/O)과 인터럽트를 “CPU가 신호를 받는다”는 점에서 같다고 착각하기 쉽다. 폴링은 CPU가 능동적으로 계속 물어보는 것이고, 인터럽트는 장치가 능동적으로 CPU에 신호를 보내는 것으로 방향이 반대다.
- 버스트 모드와 사이클 스틸을 혼동하는 경우가 많다. 버스트 모드는 “한 번에 몰아서”, 사이클 스틸은 “조금씩 나눠서” 버스를 쓰는 방식이다.
핵심 정리
- 프로그램 제어 I/O는 CPU가 계속 폴링하고, 인터럽트 기반 I/O는 준비될 때까지 다른 일을 하다가 알림을 받으며, DMA는 데이터 전송 자체를 DMA 컨트롤러가 전담한다.
- 대량 데이터 전송에서는 DMA가 가장 효율적이고, 프로그램 제어 I/O가 가장 비효율적이다.
- 버스는 주소·데이터·제어 버스로 구성되며, 여러 장치가 공용으로 쓰므로 버스 중재로 사용 순서를 정한다.
- DMA는 버스트 모드(한 번에 몰아서 전송)와 사이클 스틸(짧게 나눠서 전송) 두 방식으로 버스를 쓸 수 있다.
- 사이클 스틸의 성능 저하율은 (훔치는 사이클 수) / (요청 주기 동안 원래 쓸 수 있던 사이클 수)로 계산하며, 장치가 빠를수록 저하율이 커진다.