컴퓨터 성능 향상 기술 (버퍼, 스풀, 캐시 / 풀링, 인터럽트)

DanChu 🌟·2022년 8월 8일
0

버퍼

일반적으로 CPU와 보조기억장치 사이에서 사용되는 임시 저장공간

CPU가 작업을 수행할 때 처리될 데이터는 보조기억장치에 저장되어있다. 그런데 이 보조기억장치는 속도가 느려서 HDD의 경우 데이터 전송속도가 초당 100mb ~ 300mb밖에 되지 않는다. 반면에 작업을 처리하는 CPU는 초당 수십억 비트에 달하는 데이터를 처리할 수 있다. 이러한 속도 차이때문에 CPU에서는 데이터를 제때에 받지 못해 자신의 최대 성능을 내지 못하게 된다.

이럴때 사용하는 것이 버퍼로, CPU 내부의 캐시메모리만큼의 성능은 아니여도 보조기억장치보다는 훨씬 빠른 주기억장치(RAM)을 사용하여 데이터 전송을 원활하게 한다. 보조장치에서 CPU로 요청이 있을 때에 데이터를 보내기 시작하는 대신, 주기억장치의 버퍼로 마련한 공간에 데이터를 보낸다. 이렇게 쌓인 데이터는 CPU가 다른 일들을 처리하다가 중간 중간 확인되며, 1) 버퍼에 데이터가 쌓이면 한꺼번에 처리하는 방식으로 CPU 작업 효율이 높아진다.

버퍼는 속도차이가 나는 두 장치 사이에서 데이터 전송을 원활하게 해주는 역할 뿐 아니라, 2) 서로 자료 전송 사이즈가 다른 상황을 극복하는 역할을 한다. 데이터를 모아서 디스크에 써주는 DBMS의 경우 블록단위로 데이터를 쓰는데, 이렇게 작은 단위로 들어오는 데이터를 버퍼에 모아서 하나의 블록으로 쓰기를 실행한다.

그 외에도, 3) 데이터 입출력의 의미를 명확하게 하기 위해 사용한다. write() 시스템콜로 디스크 쓰기를 실행하는 경우에, write() 시스템콜은 애플리케이션에서 데이터를 저장하고 있는 버퍼의 내용을 커널의 버퍼로 복사하고, 이 커널의 버퍼에 복사된 내용이 디스크로 쓰여진다. 커널의 버퍼가 없어서 애플리케이션의 버퍼 내용이 바로 디스크에 쓰여지는 상태에서 애플리케이션의 내용이 write() 시스템콜이 호출 된 이후 수정된다면, 이때에 디스크에 저장되어야 할 내용이 write() 시점의 내용인지 수정된 시점의 내용인지 꼬이게 된다. 하지만 커널에 버퍼를 두는 것으로 데이터 입출력의 copy semantic이 명확해진다. 애플리케이션은 자신의 버퍼를 수정하고, 커널은 커널 버퍼에 복사된 내용을 기준으로 입출력을 수행하면 된다.

e.g. 메모리 버퍼

  • 모니터 버퍼
    : 그래픽 카드가 처리한 프레임 데이터를 저장 후, 순차적으로 프레임 단위의 데이터를 화면에 출력.
    -> 프로그램에서 처리한 결과를 출력할 때, 한줄이 다 차지않으면 출력이 안되는 경우가 생기는 이유
  • C언어 print("\n")
    : \n 이 줄바꿈이기도 하지만, 버퍼에 저장된 내용을 출력하라는 의미도 가짐.

스풀

Simultaneous Peripheral Operation On-Line, SPOOL
CPU와 입출력장치가 독립적으로 동작하도록 고안된 소프트웨어적 버퍼.
프린터의 스풀러 예에서, 스풀러는 인쇄할 내용을 순차적으로 출력하는 소프트웨어로 출력명령을 내린 프로그램과 독립적으로 동작한다. 프린터의 경우 하나의 프로세스가 프린팅을 수행하는동안에는 다른 프로세서의 요청을 처리할 수 없다. 이때 새로운 프린팅 요청은 대기를 하게 되는데, 이렇게 대기하게되는 작업들(데이터)를 위한 버퍼 공간을 만드는 것을 스풀링이라 한다. 스풀 개념을 통해 스풀러로 인쇄할 내용을 하드디스크의 스풀러 공간에 저장하고 워드로 다른 작업을 계속할 수 있다.

스풀러와 일반적인 버퍼의 차이점은 버퍼의 경우 여러 프로그램에 데이터들을 모아서 한번에 전송하지만 스풀러의 경우 한 인쇄물이 완료될때까지 다른 인쇄물이 끼어들 수 없다.

e.g. 하드웨어 안전제거

USB, 외부저장장치에 데이터를 기록할때 컴퓨터에서 해당 드라이브를 eject한 후 연결선을 해제해야한다. 그 이유는 버퍼가 차지 않아서 작업한 내용이 사라질 수 있기 때문. 이때에 eject를 요청하면 버퍼가 차지않아 아직 옮겨지지 않은 남은 데이터들을 마저 옮기는 작업이 실행되기때문에 작업내용 손실없이 드라이브 제거가 가능해진다.

캐시

메모리와 CPU사이의 속도차이를 완화하기 위해 메모리의 데이터를 미리 가져와 저장해두는 버퍼 일종의 임시저장소.
CPU가 앞으로 사용할 것으로 예상되는 데이터를 미리 가져다놓는데, 이를 prefetch라고 하며, 이 prefetch된 데이터가 저장되는 공간이 캐시이다. 주로 SRAM을 사용하며 고가이기 때문에 용량의 제한이 있다. 시스템 버스의 속도로 작동하는 메모리와 달리, CPU안에서 CPU내부 버스의 속도로 동작하는 캐시는 속도가 훨씬 빠르다. 따라서 메모리의 느린 속도와 CPU의 빠른 처리 속도 차이를 완화해줄 수 있다.

CPU가 메모리 접근이 필요한 상황에 캐시에서 원하는 데이터가 있는지 찾는다. 이때에 원하는 데이터가 있다면 cache hit, 없다면 cache miss가 나서 직접 메모리에 접근한다. (cache hit 수) / (전체 참조횟수) = cache hit ratio(캐시 적중률) 이라고 하는데, 이 캐시 적중률이 높을수록 컴퓨터 사양이 올라간다. 일반적인 컴퓨터는 90% 정도의 캐시 적중률을 가진다.

캐시 적중률을 높이려면 1) 캐시의 크기를 늘리는 방법이 있으나, 앞서 언급했듯이 용량과 가격의 제한이 있다. 또 다른 방법으로는 2) 앞으로 많이 사용 될 데이터를 가져오는 것이다. 현재 사용되고 있는 데이터와 위치적으로 가까운 데이터가 사용될 확률이 더 높다는 지역성(locality)를 따르는 방법도 있다.

e.g. 웹브라우저 캐시

  • 방문한 웹사이트의 텍스트, 이미지 등을 캐시에 저장해두고 다시 방문시에 새로 로딩하지 않고 캐시의 정보를 사용자에게 뿌려줌으로서 해당 웹사이트로의 접속시간을 단축시켜준다.

풀링

CPU가 작업을 진행할 때 입출력 명령을 만나면 직접 입출력 장치에서 데이터를 가져오는 방식으로, 반복문(스레드)가 실행될 때마다 해당 지점에 들러서 상태를 체크. 예를 들어 키보드 입력을 받는 코드가 실행되었다면 값이 입력되었는지 주기적으로 확인을 하는 것이다. CPU가 이러한 체크를 직접하기때문에 다른 작업을 할 수 없고, 파일 입출력을 기다리고 있다면 이 입출력이 처리될 때까지 다른 작업들은 기다려야된다. 즉 작업효율이 매우 떨어지는 과거의 방식으로 현재는 사용하지 않는다.

인터럽트

과거의 풀링 방식의 문제점대신 인터럽트를 사용한다. CPU가 직접 입출력이나 기타 예외 상황을 확인하는 대신, CPU에서 입출력을 받아야하는 코드가 실행되면 입출력을 받을 때까지 CPU는 다음 스레드 작업을 수행한다. 그리고 입출력이 완료되면 이 상태를 CPU가 직접 확인하지 않고 인터럽트가 발생해 CPU에 알림을 띄우게 된다. 인터럽트의 경우 벡터 형태의 자료구조로 구현이 가능하며, 각각의 인덱스 번호가 해당 인터럽트 종류를 나타내는데 개별 인터럽트에 맞는 처리방법은 인터럽트 핸들러에 저장되어 있다. 이 핸들러의 주소는 포인터로 등록되어 인터럽트를 처리할 때 값에 접근이 가능해진다.

인터럽트 구현으로 한 메모리가 CPU를 비정상적으로 독점하는 것을 방지할 수 있으며, 프로세스/스레드 간 context switching 이 가능해져 여러 프로세스가 동시에 실행되는 것처럼 사용자가 응용프로그램들을 사용할 수 있게된다.

인터럽트의 종류로는:

하드웨어 인터럽트, HW Interrupt

  • CPU상의 기능적 문제 발생
  • 타이머에 대한 인터럽트 (보통 0번)
  • 컴퓨터 파워 다운, 정전 등
  • 각 장치들에는 IRQ라는 번호가 붙여져 있는데(e.g. 1번 키보드, 2번 마우스) 이러한 장치에서 발생하는 인터럽트

소프트웨어 인터럽트, SW Interrupt

  • 0으로 나누기 (division by 0)
  • 오버플로우 (overflow)
  • 예외상황 (exception)

시그널: 사용자 요청에 의한 Interrupt

e.g. ctrl + c 와 같은 명령어로 프로세스 종료하는 경우


references

0개의 댓글