이곳은 개발을 위한 베타 사이트 입니다.
기여내역은 언제든 초기화될 수 있으며, 예기치 못한 오류가 발생할 수 있습니다.
기여내역은 언제든 초기화될 수 있으며, 예기치 못한 오류가 발생할 수 있습니다.
캐시 메모리
덤프버전 :
분류
1. 개요
2. 상세
2.1. 배경
2.2. 캐시에 사용되는 메모리의 종류
2.3. 멀티 레벨 캐시 메모리
2.4. 작동 원리: 데이터 지역성
2.5. 캐시 메모리의 목표
2.6. 캐시 메모리 성능의 요소
2.6.1. 캐시 적중과 캐시 부적중
2.6.2. 캐시 정책 및 알고리즘
2.6.2.1. 캐시 메모리의 논리적 기본 단위
2.6.2.2. 캐시 배치 정책 (Cache Placement Policy)
2.6.2.3. 캐시 포함 정책 (Cache Inclusion Policy)
2.6.2.4. 캐시 교체 정책 (Cache Replacement Policy)
2.6.2.5. 캐시 쓰기 정책 (Cache Writing Policy)
2.6.3. 캐시 일관성 (Cache Coherence)
2.6.4. 캐시 레이턴시
2.6.5. 캐시 쓰루풋 및 대역폭
2.6.5.1. 유효 대역폭
2.6.6. 병렬 처리
2.7. 캐시 메모리의 종류
2.8. 역사
2.9. 캐시 메모리와 버퍼 메모리
3. 관련 자료
4. 관련 문서
1. 개요[편집]
Cache Memory, Hardware Cache.
컴퓨터 시스템의 성능을 향상시키기 위해 별도로 탑재된 캐시 전용 메모리.
레지스터, 메인 메모리와 함께 메모리 계층 구조의 전통적인 핵심 계층 중 하나이다. 프로그램에서 직접적으로 읽거나 쓸 수 없고 하드웨어의 메모리 관리 시스템이 내부적으로 제어한다. 대부분 프로그램은 한번 사용한 데이터를 재사용할 가능성이 높고, 그 주변의 데이터도 곧 사용할 가능성이 높은 데이터 지역성을 가지고 있다. 데이터 지역성을 활용하여 메인 메모리에 있는 데이터를 캐시 메모리에 불러와 두고, 프로세서가 필요한 데이터를 캐시 메모리에서 먼저 찾도록 하면 시스템 성능을 향상시킬 수 있다.
캐시 메모리의 가격은 21세기 현재도 메모리 소자 중에서 가장 비싼 편이며, 지난 20년 간 가격이 3%정도 떨어지는 데 불과했다.
2. 상세[편집]
2.1. 배경[편집]
프로세서의 클럭 속도가 매우 빨라짐에 따라 프로세서 밖에 있는 메인 메모리와의 속도 차이가 현저하게 증가했는데, 이 때문에 프로세서 클럭 속도를 아무리 올려도 메인 메모리에서 데이터를 빠르게 제공해 주지 못하여 전체 시스템 성능이 증가하기 어렵게 되었다. 폰 노이만은 1946년 그의 논문 "Preliminary Discussion of the Logical Design of an Electronic Computing Instrument" 에서 캐시 메모리의 필요성을 예견했다.
2.2. 캐시에 사용되는 메모리의 종류[편집]
메모리 기술은 주로 축전기를 사용하는 DRAM과 플립플롭을 사용하는 SRAM으로 나뉘는데, DRAM은 가격이 싸고 용량 대비 크기가 작지만 속도가 느리고, SRAM은 속도는 빠르지만 가격이 매우 비싸고 용량 대비 크기가 크다는 단점이 있다. 그래서 DRAM을 사용자가 직접 장착하게 하는 대신, CPU와 DRAM 사이에 SRAM을 별도로 두어서 DRAM의 데이터를 직접 접근하는 것보다는 빠르게 접근할 수 있도록 한다.
현행 CPU 내부 캐시 메모리는 SRAM 중에서도 6T SRAM으로 사용되고 있는데, 물론 어디까지나 현세대 기준 일반적인 경우이고, SRAM이 무조건 캐시로만 활용된 것은 아니며, DRAM, 심지어 플래시 메모리도 캐시로 활용될 수 있다. 플래시 메모리 기반 SSD에서 지원하는 SLC 캐싱이 대표적인 예시.
2.3. 멀티 레벨 캐시 메모리[편집]
시스템에 장착된 캐시의 용량과 성능이 점점 증가하면서 캐시의 캐시로 사용되는 메모리가 추가되었는데, 이것을 적용된 순서대로 L(Level) 1, L2, L3 … 라고 호칭한다. 가장 고성능이자 작은 용량이 탑재된 L1 캐시 메모리에, L1 캐시 메모리에서 데이터를 퍼가기 위한 캐시 메모리로 사용하기 위해 L1보다는 용량이 많지만 그 대신 약간 더 느린 L2 캐시 메모리가 추가되었으며, L2 캐시 메모리에서 데이터를 퍼가기 위한 캐시 메모리로 사용하기 위해 이후 L2보다는 용량이 많지만 그 대신 약간 더 느린 L3 캐시 메모리가 추가되었고… 하는 식이다. L3 캐시 메모리가 마지막 레벨의 캐시 메모리일 경우, L3 캐시 메모리를 LLC라고 부르기도 한다.
2.4. 작동 원리: 데이터 지역성[편집]
캐시 메모리는 데이터 지역성(Locality)의 원리를 이용한다. 데이터 지역성은 시간 지역성(Temporal locality), 공간 지역성(Spatial Locality), 순차적 지역성(Sequential Locality)으로 나뉘는데, 시간 지역성이란 for나 while 같은 반복문에 사용하는 조건 변수처럼 한번 참조된 데이터는 잠시 후에 또 참조될 가능성이 높다는 것이고, 공간 지역성이란 A[0], A[1]과 같은 데이터 배열에 연속으로 접근할 때 참조된 데이터 근처에 있는 데이터가 잠시 후에 사용될 가능성이 높다는 것이며, 순차적 지역성이란 분기(branch)가 발생하는 비순차적 실행이 아닌 이상 명령어들이 메모리에 저장된 순서대로 실행하는 특성을 이용한 원리로 순차적일 수록 다음 순서의 데이터가 사용될 가능성이 높다.
쉽게 예를 들자면 무지하게 지랄맞고 부지런한 상사가 한 시간 전에 작년과 금년 재무결산 보고서를 가져오라고 했을 때, 어차피 순서대로 정리되어 있는 내년과 내후년 재무결산보고서도 가져오라고 할지 모르니까 그것도 묶음째로 근처에 준비해 놓는 식이다.
또 다른 예로는 캐시는 지갑이라고 생각하면 된다. 지갑 혹은 주머니가 없다면 우리가 현금(Cash)이 필요할 때마다 매번 은행이나 ATM에 가야 할 것이다. 이는 당연히 매우 귀찮고 시간도 많이 걸린다. 하지만 우리가 현금을 지갑에 넣고 다님으로써 시간을 절약할 수 있다.
CPU가 메모리에 데이터를 요청할 때, DRAM에 접근하기 전에 일단 캐시 메모리에 접근하여 데이터 존재 여부를 확인한다. 캐시 메모리는 메인 메모리인 DRAM보다는 그 사이즈가 매우 작아서 데이터를 모두 저장할 수 없다. DRAM이 보통 수 GB 단위 정도인데 인텔 i5, i7에 들어가는 캐시 메모리는 작게는 수 KB ~ 많게는 수 MB 정도이다. 캐시 메모리는 DRAM의 데이터 일부를 가지고 있다가 CPU가 요청한 데이터가 캐시 메모리에 없으면 CPU를 잠시 기다리게 한 후 DRAM에서 해당 데이터를 가져온 후 CPU에게 넘겨 준다. CPU는 캐시의 존재를 알고 있지만, 그 위에서 실행되는 프로그램은 메인 메모리의 주소만 지정하거나 캐시 적중률을 위해 힌트를 줄 수는 있어도[1] , 프로그래머가 캐시 메모리를 직접 지정할 수는 없다. 이렇게 그 존재가 외부에 드러나지 않기 때문에 캐시 메모리는 CPU에 투명(transparent)하다고 한다. 투명하지 않은 작은 온칩 메모리는 Scratchpad Memory라고 부른다.
캐시 메모리에 데이터를 저장할 때 공간 지역성을 최대한 활용하기 위해 해당 데이터뿐만 아니라 옆 주소의 데이터도 같이 가져와 미래에 쓰일 것을 대비한다. CPU의 경우, DRAM에는 프로그램을 수행하는 명령어(Instruction)와 그 명령이 실행되는 데이터(Data)가 함께 들어 있는데, 명령어는 읽기만 하고 데이터는 읽기와 쓰기를 동시에 하므로 캐시 메모리 내에 이들을 각각 명령어 캐시 메모리(Instruction Cache)와 데이터 캐시 메모리(Data Cache)에 저장한다.
보통 L1 캐시 메모리에는 명령어 캐시와 데이터 캐시 메모리가 따로 있고, L2 캐시 메모리는 딱히 둘의 구분 없이 하나의 캐시 메모리로 구성된다. L1 캐시 메모리는 CPU에 직접 데이터를 공급해 주기 때문에 빠른 접근 지연 시간(Access latency)이 매우 중요한데, 명령어는 보통 공간 지역성이 높고 데이터는 보통 시간 지역성이 높다. 이 둘을 나누어 서로 다른 지역성을 이용할 수 있다. 또한 명령어와 데이터를 동시에 읽어올 수 있게 함으로써 CPU의 파이프라이닝 성능을 향상시킬 수 있다.
2.5. 캐시 메모리의 목표[편집]
- 캐시 적중률의 최대화 & 부적중률(不的中率)의 최소화
- 캐시 레이턴시의 최소화
- 캐시 대역폭의 최대화
- 캐시 정책 및 알고리즘의 최적화
- 캐시 부적중에 따른 패널티의 최소화
- 데이터 일관성 보장
- 데이터 일관성에 따른 오버헤드 최소화
캐시 메모리는 궁극적으로 성능 향상을 목적으로 등장한 전용 메모리이다. 성능에 영향을 주는 요소에 대한 자세한 설명은 아래 항목에 후술.
2.6. 캐시 메모리 성능의 요소[편집]
캐시 메모리의 스펙을 따질 때 십중팔구 캐시 메모리 용량만 보는 경우가 많다. 제조사가 캐시 메모리 관련 스펙을 표기할 때 용량만 표기하기 때문. 대부분 DRAM으로 구성된 메인 메모리와 마찬가지로 레이턴시, 쓰루풋, 병렬 처리 능력이 캐시 메모리의 성능을 결정하는 주요 지표이지만, 수치화 할 수 있는 적중률(반대로는 적중 실패율), 수치화 하기 어려운 각종 캐시 정책(알고리즘)들과 캐시 일관성 프로토콜들도 캐시 메모리의 성능에 영향을 주므로 이론적인 성능과 실제 성능의 괴리감이 메인 메모리보다 더 클 수 있다.
2.6.1. 캐시 적중과 캐시 부적중[편집]
CPU가 데이터를 요청하여 캐시 메모리에 접근했을 때 캐시 메모리가 해당 데이터를 가지고 있다면 이를 '캐시 적중(cache hit)'이라고 부르고, 해당 데이터가 없어서 DRAM에서 가져와야 한다면 '캐시 부적중(cache miss)'라 부른다. 캐시 부적중할 경우의 처리 방법은 캐시 정책에 따라 다르며, 데이터를 읽어 오는 시점으로 사용하기도 한다. 캐시 적중의 정도를 나타내는 지표가 캐시 적중률(cache hit ratio)인데 퍼센트 단위(%)로 표현하려면 '(캐시 적중 횟수) / [ (캐시 적중 횟수) + (캐시 부적중 횟수) ]× 100' 또는 '(캐시 적중 횟수) / (전체 요청 및 접근 횟수) × 100'으로, 당연히 높을 수록 좋다. 반대 개념인 캐시 부적중률(cache miss ratio)은 '1 - (캐시 적중률)'이다.
2.6.1.1. 캐시 부적중의 종류[편집]
캐시 부적중(miss)이 나는 경우는 대부분의 경우 3가지로 나눌 수 있는데
- Compulsory miss(또는 Cold miss): 해당 메모리 주소를 처음 불렀기 때문에 나는 미스. 예를 들어 프로그램을 새로 켜거나 하는 경우 발생한다. 간혹 사용할 데이터를 미리 프리페치하는 경우가 아닌 이상 사실상 예방이 불가능한 캐시 미스지만, 전체 컴퓨터 이용 시간에 비하면 굉장히 드물게 나는 미스 유형이라 전체적인 성능에 영향을 미치는 정도는 작다.
- Conflict miss: 캐시 메모리에 A 데이터와 B 데이터를 저장해야 하는데, A와 B가 같은 캐시 메모리 주소에 할당돼서 나는 캐시 미스다. 예를 들어 내가 휴대폰과 따뜻한 커피캔은 항상 외투 오른쪽 주머니에만 넣는 습관이 있다고 하자. 평상시에는 오른쪽 주머니에 휴대폰만 넣고 다니는데, 어느 날 친구에게 커피캔을 받아서 잠시 휴대폰을 가방 속에 넣어두고 커피캔을 오른쪽 주머니에 넣었다. 이때 휴대폰을 오른쪽 주머니에서 찾으려고 한다면 그때 conflict miss가 난다. direct mapped cache에서 가장 발생빈도가 높고, n-associative cache에서 n이 커질수록 발생빈도가 낮아지지만 대신 n이 커질수록 캐시 속도가 느려지고 파워도 많이 먹는다.
- Capacity miss: 캐시 메모리에 공간이 부족해서 나는 캐시 미스. 위의 conflict miss는 캐시에 공간이 남아도는데도 불구하고 주소 할당 때문에 나는 미스지만, capacity miss는 주소 할당이 잘 되어있더라도 공간이 부족하면 나는 미스다. 캐시 공간이 작아서 벌어지는 일이므로 캐시 크기를 키우면 해결되지만, 캐시 크기를 키우면 캐시 접근속도가 느려지고 파워를 많이 먹는다는 단점이 생긴다.
만약 대부분의 메모리 요청이 캐시 미스라면 차라리 캐시 메모리를 안 쓰는 게 더 빠르다. 하지만 다행히도 캐시 적중 실패율이 단순 작업 기준으로 평균 10% 안쪽이기 때문에 캐시 메모리를 통해 컴퓨터 시스템의 평균 성능을 크게 향상시킬 수 있으며 클럭 속도, 코어 개수와 함께 컴퓨터 성능에서 매우 큰 비중을 차지한다. 그러나 많은 사람들이 캐시 메모리에 대해 잘 모르며 실제 캐시 메모리가 없이 클럭 속도가 더 높은 CPU가 클럭 속도는 낮지만 캐시 메모리가 있는 CPU보다 대체로 더 나쁜 성능을 보여준다.
어떤 이는 컴퓨터에 사용된 도박의 원리라고 하기도 하는데, 이는 캐시 메모리의 작동 원리가 도박에서 돈을 거는 것과 유사하기 때문이다. 캐시 적중 실패율이 낮으면 도박에 질 확률이 낮다는 의미이기도 하므로 대부분 이기는 도박이라 할 수 있다.
2.6.1.2. 응용 프로그램 특성별 캐시 적중률[편집]
렌더링 전문 작업에서의 캐시 적중률
게임에서의 캐시 적중률
위의 슬라이드 이미지는 인텔이 2019년 E3에서 공개한 자료로, 캐시 특성상 렌더링 작업의 경우 처리 과정이 게임보다 비교적 단순하기 때문에 캐시 적중률이 높게 측정된다. 반면에, 게임은 렌더링 작업과는 다르게 GPU에게 지시하는 렌더링 명령뿐만 아니라 프레임 업데이트, 물리 연산, 애니메이션 연산, 사운드 연산, 입출력, 네트워크 등 복합적으로 처리되는 과정이라서 캐시 적중률이 생각보다 높지 않다. 그렇기 때문에 게임이 렌더링 작업보다 캐시 용량에 더 민감한 편이다.
2.6.1.3. 캐시 부적중률의 중요성[편집]
캐시 적중에 관한 문제는 적중률을 기준으로 판단하는 경우가 많지만, 학계 및 관련 업계에서는 캐시 적중률보다는 캐시 '부적중률'에 초점을 맞춘다. 가령, 캐시 적중률이 98%에서 99%로 증가되었을 때, 적중률 기준으로 계산하면 겨우 약 1%밖에 향상되지 않은 것으로 해석할 수 있지만, 부적중률 기준으로 계산하면 2%에서 1%로 무려 50%나 감소된 것으로도 해석할 수 있기 때문.
캐시 적중률 98%와 99%의 차이가 별거 아닌 것처럼 보일지라도, 한 번이라도 캐시 부적중되면 캐시 메모리보다 느린 메인 메모리로 가야 하는 시간적인 패널티 뿐만 아니라, 지연된 시간으로 인한 전체적인 평균 대역폭 패널티까지 연쇄적으로 발생하기에 부적중률에 민감할 수밖에 없다.
2.6.2. 캐시 정책 및 알고리즘[편집]
캐시 메모리 성능 향상에 있어서 적절한 캐시 정책 및 알고리즘을 취해야 유효 레이턴시를 최소화하면서 유효 대역폭을 끌어 올릴 수 있다.
2.6.2.1. 캐시 메모리의 논리적 기본 단위[편집]
일반적인 캐시 메모리의 물리적 구조는 그냥 수많은 SRAM 셀들이 2차원 또는 3차원으로 배열된 모습일 뿐이다. 하지만, 캐시 메모리의 용량이 메인 메모리에 비해 매우 적어서 성능 향상을 목적으로 효율적으로 관리하기 위해서는 논리적 구조로써 파악할 필요가 있다.
| 캐시 엔트리 |<|1><-3><height=32><tablewidth=100%>
| 캐시 태그 |<width=20%> 태그 비트 ||<width=10%> 유효 비트 ||
||<|1><-1><height=32><width=70%> 캐시 블록 ||- 캐시 엔트리
- 캐시 블록 : 데이터 그룹 단위로, 캐시 메모리에 담겨질 실질적인 데이터가 이곳에 있다.
- 캐시 태그
- 태그 비트 : 캐시 블록의 고유 식별 값으로, 실질적인 데이터가 담겨져 있지 않지만 그 데이터들을 식별하기 위해 추가로 할당되어 있다.
- 유효 비트 : 해당 캐시 블록의 올바른 데이터가 있는지 판별해주는 플래그 비트로, 캐시 태그에 포함되어 있다.
캐시 엔트리는 캐시 메모리의 데이터를 구분하는 논리적인 최소 단위로, 이들이 모여서 캐시 메모리 전체를 구성한다. 흔히 몇 MB 캐시 메모리라는 것은 정확히 따지면 몇 MB만큼의 실질적인 데이터를 담을 수 있는 캐시 메모리를 의미하는데, 다시 말해서 캐시 태그에 할당된 용량을 제외한 용량이라는 뜻이다. 따라서, 캐시 메모리의 실제 용량은 캐시 태그에 할당된 용량만큼 더 추가된 용량인 셈이다. 다만, 캐시 태그가 실질적인 데이터가 아니기 때문에 일종의 오버헤드(overhead)로 취급되며, 식별 목적으로 쓰이므로 일반적으로 캐시 블록에 비하면 매우 작은 용량만 할당된다. 이 캐시 엔트리들을 어떻게 배치할 것인지는 캐시 배치 정책에 따른다.
2.6.2.2. 캐시 배치 정책 (Cache Placement Policy)[편집]
흔히 캐시 사상(Mapping) 구조라고도 부르는 정책으로, 여러 캐시 엔트리들을 배치하는 방법을 설명하는 정책이기도 하다.
- Direct Mapped Cache
| 캐시 라인 n개 |<|1><-2>
||<|5> ||<|5>캐시 라인 수 : [math(n)]개| 캐시 엔트리 0 | 캐시 태그 || 캐시 블록 ||
캐시 블록 수 : [math(n)]개
캐시 블록 용량 : [math(a)] Byte
캐시 메모리 용량 : [math(b \times 2^{c} = 2^{\log_2 b} \times 2^{c} = 2^{{(\log_2 b)}+{c}} = n×a)] Byte
메인 메모리 용량 : [math(d \times 2^{e} = 2^{\log_2 d} \times 2^{e} = 2^{{(\log_2 d)}+{e}})] Byte
메인 메모리 블록 수 : [math(2^{{(\log_2 d)}+{e}-{a}})]개
메인 메모리 주소 비트 : [math(\lceil(\log_2 d)\rceil +e)] bit
인덱스 필드 : [math(\lceil(\log_2 n)\rceil)] bit
블록 오프셋 필드 : [math(\lceil(\log_2 a)\rceil)] bit
태그 필드 : [math(\lceil(\log_2 d)\rceil + e - \lceil(\log_2 n)\rceil - \lceil(\log_2 a)\rceil)] bit ||