현대 컴퓨터 구조의 가장 큰문제는
CPU, 메모리, 주변장치의 작업속도가 다르다는 것이다.
메인보드 내 메모리와 주변장치는 시스템 버스(FSB)로 연결되어 있고,
CPU 내 레지스터, 산술논리 연리장치, 제어장치는 CPU 내부 버스(BSB)로 연결되어 있다.
CPU 내부 버스의 속도가 시스템 버스의 속도보다 빠르기 때문에 메모리를 비롯한 주변장치의 속도가 CPU의 속도를 따라가지 못한다.
이러한 장치 간 속도 차이를 개선하고, 시스템의 작업 속도를 올리기 위해 개발 된 기술 중 운영체제와 연관된 기술을 살펴보자.
속도에 차이가 있는 두 장치 사이에서 그 차이를 완화하는 역할을 하는데
입출력장치에서 데이터를 읽을 때마다 전송하면 작업량에 비해 실제로 전송되는 데이터의 양이 매우 작지만, 일정량의 데이터를 모아 한꺼번에 전송하면 적은 노력으로도 많은 양의 데이터를 옮길 수 있다.
일정량의 데이터를 모아 옮김으로써 속도의 차이를 완화하는 장치이다.
하드디스크에는 메모리 버퍼가 있다. 하드디스크 사양이 1TB, 7200rpm, 32MB 라고 한다면 마지막이 버퍼의 용량이다.
스풀은 CPU와 입출력장치가 독립적으로 동작하도록 고안된 소프트웨어적인 버퍼로, 대표적인 예로 프린터에 사용되는 스풀러이다.
스풀러는 인쇄할 내용을 순차적으로 출력하는 소프트웨어로, 출력 명령을 내리는 프로그램과 독립적으로 동작한다.
스풀러를 사용하면 인쇄할 내용을 하드디스크의 스풀러 공간에 저장하고, 워드프로세서는 다른 작업을 할 수 있다. 문서 작업과 프린터 출력 작업이 독립적으로 진행되는 것이다.
버퍼를 사용하면 버퍼가 다 채워질 떄까지 저장장치 간에 데이터 전송이 지연되는데 USB와 같은 외부 저장장치에서 데이터를 복사한 후 바로 제거하는 경우, 버퍼에 있는 데이터가 전송되지 않아서 데이터가 유실될 수 있다. 하드웨어 안전 제거 기능과 같은 기능으로 제거해야 한다.
캐시는 메모리와 CPU 간의 속도 차이를 완화하기 위해, 메모리의 데이터를 미리 가져와 저장해두는 임시 장소이다.
버퍼의 일종으로, CPU가 앞으로 사용할 것으로 예상되는 데이터를 미리 가져다 놓는다.
캐시는 CPU 안에 있으며, CPU 내부 버스의 속도로 작동한다.
메모리의 경우 시스템 버스 속도로 동작하기 때문에 느리다.
캐시는 빠른 속도로 동작하는 CPU와 느린 속도로 작동하는 메모리 사이에서 두 장치의 속도 차이를 완화해준다.
원하는 데이터를 찾으면 캐시 히트(cache hit) 라고 하며, 그 데이터를 사용하고
원하는 데이터가 캐시에 없으면 메모리로 가서 데이터를 찾는데 이를 캐시 미스(cache miss) 라고 한다.
캐시 히트가 되는 비율을 캐시 적중률(cache hit ratio) 라고 한다.
캐시의 적중률을 높이는 방법 중 하나는 캐시의 크기를 늘리는 것이다.
캐시에 있는 데이터가 변경되는 경우, 이를 반영해야 하는 문제도 남아 있다.
반영하는 데에는 즉시 쓰기 방식과 지연 쓰기 방식이 있다.
즉시 쓰기(write through)
지연 쓰기(write back)
캐시는 명령어와 데이터의 구분 없이 모든 자료를 가져오는 일반 캐시
명령어와 데이터를 구분하여 가져오는 특수 캐시
라는 2가지 레벨로 구분되는데
명령어 캐시나 데이터 캐시는 CPU 레지스터에 직접 연결되어 있기 때문에 L1(Level 1) 캐시라고 부르며,
일반 캐시는 메모리와 연결되기 때문에 L2(Level 2) 캐시라고 부른다.
속도가 빠르고 값이 비싼 저장장치를 CPU 가까운 쪽에 두고, 값이 싸고 용량이 큰 저장장치를 반대쪽에 배치하여 적당한 가격으로 빠른 속도와 큰 용량을 동시에 얻는 방법이다.
초기의 컴퓨터 시스템에는 주변장치가 많이 없어서 CPU가 직접 입출력장치에서 데이터를 가져오거나 내보냈는데, 이러한 방식을 폴링(polling) 방식이라고 한다.
폴링 방식에서는 CPU가 입출력장치의 상태를 주기적으로 검사하여, 일정한 조건을 만족할 때 데이터를 처리한다. 명령어 해석과 실행이라는 본래 역할 외에 모든 입출력까지 관여해야 하므로 작업 효율이 떨어진다.
오늘날의 컴퓨터에는 많은 주변장치가 있어, CPU가 모든 입출력에 관여하면 작업 효율이 현저하게 떨어지므로 이 문제를 해결하기 위해 등장한 것이 인터럽트 방식이다.
CPU의 작업과 저장장치의 데이터 이동을 독립적으로 운영함으로써, 시스템의 효율을 높이는 방식으로 데이터의 입출력이 이루어지는 동안 CPU가 다른 작업을 할 수 있다. 즉 입출력은 입출력 관리자가 혹은 장치관리자 처리하는 것이다.
이때 입출력 관리자가 CPU에 보내는 완료 신호를 인터럽트라고 한다. CPU는 입출력 관리자에게 작업 지시를 내리고, 다른 일을 하다가 완료 신호를 받으면 하던 일을 중단하고 옮겨진 데이터를 처리한다.
CPU는 입출력 관리자에게 여러 개의 입출력 작업을 동시에 시킬 수 있는데 여러 작업이 동시에 완료되고 그때마다 인터럽트를 여러 번 사용해야 하는데 이는 매우 비효율적이다.
그래서 여러 개의 인터럽트를 하나의 배열로 만든 인터럽트 벡터를 사용한다.
CPU가 인터럽트 발생으로 인터럽트 벡터를 받아 관련 작업을 동시에 처리한다.
이외에도 다양한 종류의 인터럽트가 있다.
컴퓨터의 전원 버튼을 눌러 강제로 종료하면 CPU는 하던 일을 모두 멈추고 처리 중인 데이터를 안전하게 보관한 뒤 시스템을 종료한다던가
메모리에서 실행 중인 어떤 작업이 자신에게 주어진 메모리 영역을 넘어 작업을 하려하거나 0으로 숫자를 나누면 인터럽트가 발생한다.
입출력이 필요할 때 CPU는 입출력 관리자에게 입출력 요청을 보내고 자신은 하던 일을 계속한다. 입출력 관리자는 CPU가 요청한 데이터를 메모리에 가져다 놓아야 하는데 이때 문제가 있다.
메모리는 CPU만 접근 권한은 가진 작업 공간이라서 입출력 관리자는 접근이 불가능하다.
따라서 입출력 관리자에게 CPU의 허락 없이 메모리에 접근할 수 있는 권한이 필요한데, 이러한 권한은 직접 메모리 접근 이라고 한다.
직접 메모리 접근은 인터럽트 방식의 시스템을 구성하는 데 필수 요소이지만 사용하는 경우에는 메모리가 복잡해진다.
메모리에 CPU가 사용하는 데이터와 입출력 장치가 사용하는 데이터가 섞이기 때문이다.
직접 메모리 접근을 통해 들어온 데이터를 메모리에 아무렇게나 둔다면 CPU가 사용하는 데이터와 섞여서 관리하기 어려울 것이므로 이를 막기 위해 메모리를 나누어 사용하는 방법이 도입되었다.
메모리의 일정 공간을 입출력에 할당하는 기법을 메모리 매핑 입출력(Memory Mapped I/O, MMIO) 라고 한다.
입출력 장치도 직접 메모리 접근을 통해 메모리를 사용할 수 있게 되었다. 만약 CPU와 직접 메모리 접근이 동시에 메모리에 접근하려고 하면 어떻게 해야할까?
CPU의 작업속도 보다 입출력 장치의 속도가 느리기 때문에 직접 메모리 접근에 양보하는 것이 낫다.
이러한 상황을 사이클 훔치기(cycle stealing)이라고 부른다.
CPU입장에서 직접 메모리 접근이 사이클(순서)을 훔쳐 간 것이기 때문이다.
참조한 책 및 사이트
쉽게 배우는 운영체제