레지스터 - 캐시메모리 - 메모리 - 저장장치

  • 구체적으로 크기와 성능에 얼마나 차이가 있습니까?
  • 이런 차이를 고려하여 하드웨어나 리눅스는 어떤 구조로 되어 있습니까?

캐시 메모리

컴퓨터의 동작 흐름(메모리로부터 명령어를 읽는 부분은 생략)

  1. 명령어를 바탕으로 메모리에서 레지스터로 데이터를 읽습니다.
  2. 레지스터에 있는 데이터를 바탕으로 계산
  3. 계산 결과를 메모리에 씀

레지스터에서 계산하는 시간은 엄청 빠르고 메모리에 접근하는 것은 엄청 느리다. 2가 아무리 빨라도 1, 3에서 느리기에 병목이 된다. 캐시메모리는 이런 레지스터 안에서 계산하는 것과 메모리에 접근하는 것 양쪽의 처리 시간의 차이를 메우는데 필요하다. 캐시메모리로부터 레지스터에 접근할 때의 레이턴시는 메로리에 접근할 때와 비교해보면 수배~수십배 빠르다. 일반적으로 캐시메모리는 CPU안에 내장되어있다. 캐시 메모리 처리는 커널을 통하지 않고 하드웨어 안에서 전부 처리된다.

처리 그림

캐시 메모리가 가득 찬 경우
캐시 메모리가 가득찼는데, 캐시메모리에 존재하지 않는 데이터를 추가로 읽으면 기존 캐시 메로리 중 1개를 파기합니다. 파기하는 캐시다 더티라면 동기화 작업 이후 파기하는데, 모든 캐시 라인이 더티라면 캐시 라인 안의 데이터가 자주 바뀌게되는 스래싱이 발생하여 성능이 크게 감소할 수 있습니다.

계층형 캐시 메모리
x86_64 아키텍처 cpu는 캐시메모리가 계층형 구조로 되어있다. 각 계층은 사이즈, 레이턴시, 어느 논리 cpu 사이에 공유하는가 등이 다르다. 계층형 구조를 구성하는 각 캐시메모리는 L1, L2, L3 등의 이름이 붙어있다. L1이가장 레지스터에 가깝고 용량이 적으며 숫자가 커질 수록 거리는 멀어지고 용량은 커지며 속도가 느려진다.

캐시 메모리 정보는 /sys/devices/system/cpu/cpu0/cache/index0/* 라는 디렉터리에 있는 파일의 내용을 보면 알 수 있다. type, shared_cpu_list, size, coherency_line_size

캐시 실험

메모리 참조의 국소성
프로세스는(짧은 시간을 놓고 생각해보면) 자신이 획득한 메모리의 총량보다 훨씬 좁은 범위의 메모리에 접근하는 성향이 있다.

  • 시간국소성: 특정 시점에 접근하는 데이터는 가까운 미래에 다시 접근할 가능성이 크다. 전형적인 예로는 루프 처리 중인 코드 영역을 들 수 있다.
  • 공간국소성: 특정 시점에 어떤 데이터에 접근하면 그 데이터와 가까운 주소에 있는 데이터를 접근할 확률이 높다. 전형적인 예로는 배열의 전체 검색 등이 있다.

정리
프로그램 워크로드를 캐시 메모리 사이즈에 들어가게 하면 성능을 크게 향상시킬 수 있다.
=> 데이터의 배열이나 알고리즘 혹은 설정을 연구해서 단위 시간 당 메모리 접근 범위를 작게 할 수 있다.

Translation Lookaside Buffer

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

  1. 물리 메모리상에 존재하는 페이지 테이블을 참고하여 가상 주로슬 물리 주소로 변환
  2. 1에서 구한 물리 메모리에 접근
    캐시 메모리를 사용하여 고송화 하는 것은 2뿐이다. 1은 물리 메모리상에 있는 페이지 테이블에 접근해야하므로 캐시가 동작할 수 없다. 이문제를 해결하기 위해
    • cpu에가상 주소에서 물리 주소로의 변환표를 보관
    • 캐시 메모리와 똑같이 고속으로 접근 가능한 TLB라는 영역을 만듦

페이지 캐시

페이지 캐시는 저장 장치 내의 파일 데이터를 메모리에 캐싱한 것이다. 페이지 캐시는 페이지 단위로 데이터를 다룬다. 프로세스가 파일의 데이터를 읽으면 커널은 일단 커널 메모리 내에 페이지 캐시라는 영역에 복사한 뒤 이 데이터를 프로세스의 메모리에 복사한다. 그리고 커널 자신의 메모리 안에 페이지 캐시에 캐싱한 파일과 그 범위 등의 정보를 보관하는 관리영역에 파일 이름/파일 오프셋/메모리 주소를 보관한다. 그리고 페이지 캐시에 존재하는 데이터를 다시 읽으면 커널은 페이지 캐시의 데이터를 돌려준다.

시스템 메모리가 비어있는 한 페이지 캐시 사이즈는 계속 증가한다. 시스템 메모리가 부족해지면 페이지 캐시를 해제하여 빈 영역을 만드는데, 그래도 부족하면 더티 페이지를 라이트백(변경된 내용을 저장장치에 복사하고고한 뒤 파기한다. 메모리 부족이 더티 페이지의 라이트 백을 자주 발생시켜서 시스템이 느려지는 일은 굉장히 자주 있다.

동기화된 쓰기

페이지 캐시에 더티페이지가 있는 상태로 전원이 꺼지면 캐시 데이터는 사라진다. 절대 이런일이 발생하면 안되는 파일에는. open() 시스템콜로 파일을 열 때 ‘O_SYNC’ 플래그를 설정해준다. 이렇게 하면 나중에 파일에 write() 시스템 콜을 수행할 때마다 데이터는 페이지 캐시 외에 저장 장치에도 동기화 된다.

버퍼 캐시

페이지 캐시와 비슷한 구조로 버퍼캐시가있다. 디바이스 파일을 이용하여 저장 장치에 접근하는 등의 목적으로 사용한다. -> 페이지 캐시와 버퍼 캐시를 합쳐서 저장 장치 안의 데이터를 메모리에 넣어두는 방식이다.

파일의 읽기/쓰기 테스트 함

pass

튜닝 파라미터

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

  • sysctl 의 vm.dirty_writeback_centisecs : 더티페이지의 라이트 백이 발생하는 주기, 단위는 1/100초, 기본값은 5초에 1번(500)
  • vm.dirty_background_ratio : 더티 페이지 / 물리메모리 가 해당 파라미터의 퍼셎ㄴ트를 초과한 경우 라이트 백 처리함, 기본값은 10, 시스템 메모리가 부족할 때 라이트 백 부하가 커지는 것을 방지
  • vm.dirty_background_bytes : 같은 기능인데 바이트 단위로 지정, 기본값은 0(사용 안함)
  • vm.dirty_ratio : 더티 페이지 / 물리 메모리가 해당 파라미터 퍼센트를 초과하면 프로세스에 의한 파일에 쓰기의 연장으로 동기적인 라이트백을 수행, 기본값은 20
  • vm.dirty_bytes : 같은 기능인데 바이트 단위로 지정, 기본 값은 0(사용 안함)

시스템의 페이지 캐시를 (완전히는 아니지만) 삭제하는 방법
/proc/sys/vm/drop_caches 라는 파일에 3을 넣어준다.

정리

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

하이퍼스레드

하이퍼스레드 기능은 CPU코어 안의 레지스터 등 일부 자원을 여러 개(일반적으로는 2개씩) 준비해두고, 시스템 입장에서는 각각 논리 CPU 로써 인식되는 하이퍼스레드라는 단위로 반할되는 하드웨어의 기능이다. 각각의 하이퍼스레드는 특정 조건에서 여러개가 동시에 실행 가능하다.