6장. 메모리 계층

· ☕ 6 min read · 👀... views

구체적으로 크기와 성능에 얼마나 차이가 있습니까?

이런 차이를 고려하여 하드웨어나 리눅스는 어떤 구조로 되어 있습니까?

라는 두 질문이 이 장에서 풀어나갈 내용.

캐시 메모리

컴퓨터의 동작 흐름은 다음과 같다.

  1. 명령어를 바탕으로 메모리에서 레지스터로 데이터를 읽습니다.
  2. 레지스터에 있는 데이터를 바탕으로 계산합니다.
  3. 처리 결과를 메모리에 씁니다.
    컴퓨터에서 처리 2가 아무리 빨라도 처리1 과 처리3에서 속도 상의 병목이 생겨 느려질 수 있음.
    캐시 메모리는 이런 레지스터 안에서 계산하는 것과 메모리에 접근하는 것, 양쪽의 처리 시간의 차이를 메우는데 필요.
    메모리에서 레지스터로 데이터를 읽어올 때는, 일단 캐시 메모리에 읽어온 뒤 같은 내용을 다시 레지스터로 읽어 들입니다. 이 때 읽어오는 크기는 CPU에서 정한 ‘캐시 라인 사이즈'만큼
    데이터를 덮어 쓸 때 쓰는 단위도 캐시 라인 사이즈 이며, 변경되었음을 나타내는 플레그를 사용하는데, 이를 ‘더티’ 라고 부름
    이 ‘더티’ 플레그가 붙어 있는 데이터는 나중에 백그라운드 처리로 메모리에 다시 기록되는데, 이러한 방법을 라이트 백(write back) 이라고 부르며, 더티가 아니게 됨
    CPU가 캐시 메모리에 있는 데이터에만 접근할 때에는 모든 접근이 캐시 메모리의 속도로 처리되므로 캐시 메모리가 없는 경우보다 훨씬 빠르게 처리됨.
캐시 메모리가 가득 찬 경우

기존의 캐시 메모리 중 1개를 파기, 그 후 비워진 캐시라인에 데이터를 복사
파기하는 캐시가 더티라면 대응되는 메모리에 덮어쓴 다음 버리는 동기화 작업이 일어남
만약, 캐시 메모리가 가득 차고 다 더티라면, 캐시 라인 안의 데이터가 자주 바뀌게 되는 스레싱(thrashing) 이 발생하여 성능이 크게 감소할 수 있음.

계층형 캐시 메모리

최근의 CPU는 캐시 메모리가 계층형으로 되어 있음.
계층형 구조를 구성하는 각 캐시 메모리는 L(Level)1, L2, L3 등의 이름이 붙어 있으며 번호가 늘어날 수록 레지스터로부터 멀어지며 용량이 커지고 속도가 느려짐.

메모리 참조의 국소성

프로세스의 데이터가 전부 캐시에 있는 동안에는 데이터에 접근하는 속도는 메모리에 접속하는 속도가 아니라 이보다 빠른 캐시에 접근하는 속도.
프로그램은 대부분 메모리 참조의 국소성(locality of reference) 이라고 하는 특성이 있음.

  1. 시간 국소성 : 특정 시점에서 접근하는 데이터는 가까운 미래에 다시 접근할 가능성이 큼, 전형적인 예로 루프 처리 중인 코드 영역
  2. 공간 국소성 : 특정 시점에 어떤 데이터에 접근하면 그 데이터와 가까운 주소에 있는 데이터를 접근할 확률이 높음, 전형적인 예로 배열의 전체 검색
    이러한 이유로 프로세스는 짧은 시간을 높고 생각해보면 자신이 획득한 메모리의 총량보다 훨씬 좁은 범위의 메모리에 접근하는 성향이 있음.

정리

속도를 중요시 하는 프로그램이라면 캐시 메모리의 효과를 최대한으로 끌어내기 위해 데이터의 배열이나 알고리즘 혹은 설정을 연구해서 단위 시간 당 메모리 접근 범위를 작게 하는 것이 중요.
한편, 시스템 설정을 변경했을 때 프로그램의 성능이 크게 나빠진 경우에는 프로그램의 데이터가 캐시 메모리에 전부 들어가지 않았을 가능성이 있음.

Translation Lookaside Buffer

프로세스는 다음과 같은 순서에 따라 가상 주소의 데이터에 접근

  1. 물리 메모리상에 존재하는 페이지 테이블을 참고하여 가상 주소를 물리 주소로 변환
  2. 1에서 구한 물리 메모리에 접근
    캐시 메모리를 사용하여 고속화하는 것은 2뿐 (1은 물리 메모리상에 있는 페이지 테이블에 접근해야 하므로)
    이 때문에 CPU에는 가상 주소에서 물리 주소로의 변환표를 보관하는 한편, 캐시 메모리와 똑같이 고속으로 접근 가능한 TLB라는 영역이 있고, 이를 가지고 1을 고속화함

페이지 캐시

CPU로부터 메모리에 접근하는 속도에 비해 저장 장치에 접근하는 속도는 엄청나게 느림.
페이지 캐시는 캐시 메모리와 매우 비슷, 캐시 메모리가 메모리의 데이터를 캐싱하는 것과 비슷하게 저장 장치 내의 파일 데이터를 메모리에 캐싱
캐시 메모리는 캐시 라인 단위로 데이터를, 페이지 캐시는 페이지 단위로 데이터를 다룸
프로세스가 파일의 데이터를 읽어 들이면 커널은 프로세스의 메모리에 파일의 데이터를 직접 복사하는 것이 아니라 일단 커널의 메모리 내에 있는 페이지 캐시라는 영역에 복사한 뒤 이 데이터를 프로세스 메모리에 복사.
이 방법은 저장 장치에 직접 접근하는 경우에 비해 훨씬 빠르며, 페이지 캐시는 전체 프로세스 공유의 자원이므로 읽어들인 프로세스는 최초에 파일 데이터에 접근한 프로세스와 다른 프로세스여도 상관 없음
캐시와 비숫하게 더티 페이지가 존재.
각 프로세스가 접근하는 파일의 데이터가 전부 페이지 캐시에 있으면 시스템 파일의 접근 속도는 저장 장치가 아닌 메모리 접근 속도에 근접하므로 시스템 전체가 빠르게 동작

동기화된 쓰기

페이지 캐시에 더티 페이지가 있는 상태로 시스템의 전원이 강제로 꺼지면, 데이터가 사라짐. 이런 사태가 벌어지지 않게 하기 위해서는 Open() 시스템 call 로 파일을 열 때, O_SYNC 플레그를 설정 이렇게 하면 파일에 write() 시스템 call을 수행할 때마다 데이터는 페이지 캐시 외에 저장 장치에도 동기화되어 쓰기가 수행됨

버퍼 캐시

페이지 캐시와 비슷한 구조.
페이지 캐시와 버퍼 캐시를 합쳐서 저장 장치 안의 데이터를 메모리에 넣어두는 방식

튜닝 파라미터

페이지 캐시를 제어하기 위한 튜닝 파라미터가 존재

더티 페이지의 라이트 백이 발생하는 주기

sysctl vm.dirty_writeback_centisecs
기본값은 5초에 1번 라이트 백

시스템 메모리가 부족할 때 라이트 백 부하가 커지는 것을 방지

sysctl vm.dirty_background_ratio
기본 값은 10

더티 페이지가 차지하는 비율이 지정된 퍼센트를 초과할 경우 동기적인 라이트 백을 수행

sysctl vm.dirty_ratio
기본 값은 20

이러한 파리미터를 잘 조절해서 시스템 메모리가 부족해 갑자기 더티 페이지의 라이트 백이 자주 발생하는 일이 없도록 하는 것이 좋음

정리

파일의 데이터가 페이지 캐시에 있다면 없는 경우와 비교해서 파일 접근이 매우 빨라짐. 설정 변경이나 시간이 지나면서 시스템의 성능이 갑자기 느려졌다면 파일의 데이터가 페이지 캐시에 제대로 들어가지 못했을 수 있음.
sysctl 파라미터를 잘 튜닝한다면 페이지 캐시의 라이트 백이 자주 발생하여서 생기는 I/O 부하를 막을 수 있음.

하이퍼스레드

CPU의 계산 처리 소요 시간에 비해 메모리 접근의 레이턴시가 매우 느림. 거기에 캐시 메모리의 레이턴시도 CPU의 계산 처리에 비교하면 비교적 느린 편. 그렇기에 대부분의 시간이 메모리 혹은 캐시 메모리로부터 데이터를 기다리는 일로 낭비됨
하이퍼스레드의 기능은 CPU 코어 안의 레지스터 등 일부 자원을 여러개 (일반적으론 2개) 준비해두고, 시스템 입장에서는 각각 논리 CPU로써 인식되는 하이퍼스레드라는 단위로 분할되는 하드웨어 기능
베스트 케이스라고 할지라도 2배의 성능을 내는 것은 아니며 현실적으론 20~30% 의 성능 향상이 나오면 훌륭하다고 할 수 있음.
하이퍼스레드는 항상 성능이 좋다고 할 수 없으므로, 하이퍼스레드가 있는 경우와 없는 경우의 성능 측정을 한 다음, 사용 여부를 판단하는 것이 좋음.

Share on

snack
WRITTEN BY
snack
Web Programmer


What's on this Page