💡12장 목표
- I/O 하드웨어
- Application이 I/O interface를 어떻게 사용하는지
- I/O Subsystem
- I/O요청을 하드웨어 작동으로 바꾸는 것
- STREAMS
- 성능
커널은 프로세스 동기화, 메모리 관리, 파일 관리, I/O관리 등을 하는데 그 중 I/O 관리를 살펴본다.
- 시스템은 다양한 I/O 디바이스를 포함한다. (스토리지, 네트워크 장치, 키보드 같은 입력 장치 등)
- 각 디바이스는 고유한 특성과 작동방식을 가지고 있어서 해당 디바이스를 제어하는 컨트롤러를 가진다. 이 컨트롤러가 OS 간 통신 담당
- 디바이스 컨트롤러가 각 디바이스별로 처리하고,
- 그 위에 있는 I/O subsystem이 공통 처리를 진행
🔹I/O Hardware
I/O 관련 하드웨어
- 저장 장치(하드디스크, SSD 등), 전송 장치(네트워크 등), 사용자 인터페이스(키보드 등) 장치 등 다양한 종류가 존재
이 장치들과 컴퓨터 연결
- Port: 디바이스 연결을 위한 것(ex. USB포트, 랜포트), I/O디바이스와 컴퓨터가 연결되는 지점
- Bus: 데이터 전송 경로, 버스에 다양한 디바이스가 직렬로? 체인처럼 연결되있는 Daisy chain 방식으로 연결
- PCI bus: 메인 버스
- expansion bus: 느린 I/O장치를 위한 버스
- SAS: 디스크 인터페이스

Fibre channel(FC)
Register
- 각 디바이스는 명령어, 주소, 데이터 등을 저장하기 위한 레지스터를 가진다(디바이스 컨트롤러의 데이터 저장). CPU가 이 레지스터에 접근
- data-in register
- data-out register
- satus register: 디바이스 현재 상태 정보
- control register: 디바이스 동작 제어 명령 저장
Address
- 각 디바이스는 고유한 주소를 가진다. OS가 여러 디바이스를 구분하기 위해 이 주소를 사용한다.
- Direct I/O instruction: 주소로 직접 통신, 명령어
- Memory-mapped I/O: 디바이스의 레지스터가 프로세스의 주소 공간에 매핑

Polling
CPU가 I/O장치의 상태를 주기적으로 확인하여 데이터 전송을 관리하는 것
Interrupt
폴링의 비효율성 극복, I/O작업할 때 기다리게 하지 않음
- Interrupt handler: 인터럽트 처리
- Maskable: CPU가 특정 조건에 따라 인터럽트를 무시하거나 지연시키는 것
- Interrupt vector: 여러 인터럽트들 구별하기 위해

인터럽트 처리 과정
- 이를 통해 CPU 사용률 증가, CPU와 I/O의 속도 미스매치 해결
- 하지만 latency 발생
I/O말고도 Interrupt는 다양하게 활용됨
- 예외 처리, page fault, trap 등에서 사용
- Multi-CPU인 경우는 CPU마다 interrupt 처리 가능 (동시 처리)
DMA의 Interrupt
- DMA는 큰 I/O 데이터를 메모리로 전송할 때 CPU를 거치지 않고 전달하게 해주는 것
- CPU는 안쓰지만 CPU와 같은 버스를 공유하기 때문에, DMA로 데이터를 다 보냈으면 CPU에게 다했다는 interrupt 보냄

🔹Application I/O Interface
예를 들어, 파일 접근을 하는 경우,
프로세스가 I/O request를 하여 파일에 접근하고, I/O Subsystem이 파일이 디스크에 저장되어있음을 알아내고, 디스크에 접근하기 위해 디스크 디바이스 드라이버에 접근한다.
여기까지가 OS이고, HW적으로는 드라이버에 의해 디스크 디바이스 컨트롤러를 작동시키는 것이다.
이러한 구조가 I/O interface이다. 이는 I/O 시스템을 호출하는 과정의 추성화를 통해 애플리케이션이 디바이스의 다양성을 걱정하지 않고도 I/O작업을 할 수 있도록 한다. 디바이스 드라이버가 다양성을 처리해준다.
I/O디바이스들의 특징 (다양성)
I/O 디바이스 분류
OS는 다양한 I/O 디바이스를 효과적으로 관리하기 위해 분류
- Block Device: 블록 단위 데이터 처리 (디스크 드라이브)
- RAW I/O와 direct I/O 방식: 파일 시스템을 거치지 않고 블록에 직접 접근하는 방식이다. (원래 하드디스크와 메모리 사이 버퍼를 통해 캐싱을 하는데 이를 안하고)
- Character Device (Stream): 문자 단위 데이터 처리 (키보드, 마우스 등)
- Memory-mapped file access: 파일 내용을 가상 메모리 주소 공간에 매핑
- Network Device: 소켓 인터페이스 사용
- 소켓을 사용하여 어플리케이션이 통신 프로토콜을 쉽게 사용할 수 있도록 한다. (system call같은 느낌)
- 소켓 연결 후 read, write
- select(): 여러 소켓(포트)을 모니터링해 준비되면 데이터 read/write
Block, character 디바이스의 I/O방식에는 RAW I/O와 direct I/O가 있다. 이 방식은
- Clocks and Timers: 시간 관련 기능 제공
I/O 디바이스 특성 제어
- Unix의 ioctl() 함수: 디바이스 레지스터 값을 통해 특성 제어, 데이터 전송, 상태 확인 등을 함
I/O 디바이스 구분
- Unix, Linux는 다양한 디바이스들을 구별하기 위해 major번호와 minor 번호를 사용
- 주번호: 디바이스 종류
- 부번호: 그 종류의 몇번째 디바이스 인지
Vectered I/O
Unix의 readve()함수는 한 systemcall로 여러 I/O작업을 병렬처리한다.
Nonblocking and Asynchronous I/O
- Blocking: I/O 직업이 완료 될 때까지 반환 안함 → 그동안 프로세스 중단 및 기다림
- Nonblocking: I/O 호출 시 바로 반환, 만약 수행 못한대도 바로 (오류)반환 → 프로세스는 작업 완료를 기다리지 않음, 오류 처리 개발자가 해줘야함
- Asynchronous: I/O호출 시 바로 반환 및 완료 시 프로세스에게 신호 전송 → 오류 처리 수동 관리 필요 없음

🔹Kernel I/O Subsystem
다양한 디바이스들에 대한 공통 작업 처리, 표준 인터페이스를 제공
-
I/O Scheduling: 여러 프로세스가 한 디바이스에 I/O요청을 보낼 때, 어떤 요청을 먼저 처리할 것인지
-
Buferring: 디바이스 간 전송 중에 데이터를 메모리에 저장하는 것
- 속도/크기 불일치 해결
- 디바이스 별 속도는 아래처럼 다르고, 데이터 형태도 다르니까

- Double Buferring도 있다. 버퍼 두개 써서 더 효율적으로 처리
-
Device-status table: I/O 디바이스들을 관리하는 테이블, 대기중인 요청들이 linked list로 연결
-
Caching: 빠른 CPU와 느린 I/O 사이 버퍼를 두고 캐싱하여 → 이거 교수님이 말해주신건데.. 이게 맞나
- 빠른 장치가 데이터의 복사본을 보관 (주로 메모리에서 데이터를 임시로 저장)
- 버퍼링과 함께 사용
-
Spooling: 디바이스 출력 데이터를 임시로 저장하는 버퍼의 일종
- ex) 프린터는 여러 출력물을 처리하기 위해 스풀링
-
Device Reservation: 특정 디바이스에 대한 독점 접근 제공
- 여러 프로세스가 동시에 장치에 접근하는걸 방지
- 디바이스의 할당 및 해제
-
Error Handling: OS는 I/O작업 중 발생할 수 있는 다양한 오류 처리 메커니즘을 가짐 (read write 에러, 디바이스 사용 불가 등)
-
I/O Protection: OS는 I/O를 보호해주는 기능을 가짐
- OS는 모든 I/O 명령을 previleged로 정의, 프로세스는 커널을 통해 접근할 수 있음
- 프로세스가 I/O 작업을 수행하기 위해 system call을 사용하면, 커널로 trap이 발생하고 커널은 해당 system call을 사용할 권한이 있는지 확인하고 작업을 수행한다. 그리고 다시 유저모드로 돌아간다.

Kernel data structure
커널은 I/O 구성요소의 상태 정보를 유지하기 위한 데이터 구조를 가진다. I/O 상태 정보는 open file table, network connection, character device state 등이 있다.
- 복잡한 데이터 구조를 버퍼로 관리여 I/O 작업 성능을 최적화
- 버퍼에 캐시했을 때, 수정된 데이터가 있으면 디스크에 기록한 후 그 자리에 새로 쓰여질 수 있도록 해야된다.
- WIndow는 micro kernel을 사용하여 많은 기능들이 유저 모드에서 독립적인 프로세스로 동작하는데, I/O 기능도 포함된다. 근데 message passing 기법이라 느림
- UNIX의 kernel structure는 아래와 같다

Power management
디바이스는 전력을 소모한다. 우리는 이를 소프트웨어적으로 관리해줘야 함
- Cloud computing은 서버 급 컴퓨터로 많은 디바이스들이 연결되어있어 전기를 많이 사용한다.
- Moblie computing은 저전력 설계가 중요하다.
이러한 것이 등장하면서 전력 관리가 더 중요해짐
- 안쓰는거 끄기~ 다시 쓰면 깨우기(latency는 있음)
📌 그래서 Kernel I/O Subsystem의 주요 기능을 다시 보면
- 파일 및 디바이스 종류 관리
- 파일 및 디바이스 접근 권한 관리
- 버퍼링, 캐싱, 스풀링
- I/O Scheduling
- 에러 처리
- 디바이스 드라이버 구성
- 전력 관리
I/O요청이 HW 디바이스 컨트롤러까지 가는 과정
🔹 STREAMS
유저 레벨 프로세스와 디바이스 사이에서 해야하는 일들을 STREAM이라는 모듈로 관리
- read queue와 write queue로 stream을 유연하게 추가/제거 가능

I/O처리의 성능은 고려 사항이 아주 많다. 아래와 같이 많은 단계를 거치기 때문이다.
성능을 향상시키려면
- context switch를 줄이기
- data copying을 줄이기 (계층별 이동, 저장공간 이동 과정 하나하나가 다 copy다. 공유 데이터 공간을 만들고 각자 접근하게 한다면 줄일 수 있음)
- 큰 데이터를 한 번에 전달하여 interrupt 줄이기, CPU와 I/O가 효율적으로 동시에 일할 수 있는 smart controller 사용
- DMA 사용하기
- 스마트 하드웨어 장치 사용하기
- CPU, 메모리, 버스, I/O 간의 성능을 균형있게 조정하기, 공평하게 일하기 (병목현상 방지)
- 커널 스레드를 사용하여 효율적으로 처리하기
- 알고리즘 구현 시 특징에 따라 적절한 계층 선택하기
- 위로 갈수록 유연하고 개발이 간편하고 싸지만 처리 속도가 느리고
- 아래로 갈수록 처리 속도가 빠르고 추상화할 수 있지만 비싸다

스토리지의 I/O 성능은 아래와 같다. (저장용량 및 처리 속도)