Memory Hierarchy
The Law of Storage
- Bigger capacity → Higher latency (걸리는 시간: SRAM < DRAM < SSD)
- Faster 비싸진다 (SRAM > DRAM > SSD)
Basic Principles
Locality
- 프로그램에서 어떤 address에 있는 data와 instruction을 사용했으면 조만간 비슷한 곳에서 사용할 가능성이 높다
- Temporal Locality: 최근에 reference했으면 또 사용할 가능성이높다. (ex. loop)
- Spatial Locality: 근처 주소에 있는 것을 또 reference할 가능성이 높다
Cost amortization

DRAM에 한 번 access해서 데이터를 가져온 다음에 cache에 저장을 하면 된다.
One-time-overhead = DRAM access 시간
Per-unit-cost = cache access 시간
Cache
Access time이 상대적으로 짧은 컴퓨터 메모리로, 최근에 사용했거나 자주 사용한 instruction/data 등을 저장해놓는 것이다.
Memory Hierarchy
자동으로 관리할 수도 있고, 수동으로 관리할 수도 있다. GPU, special-purpose processor 등에서는 수동으로 관리하기도 하지만 너무 번거로워서 잘 하지 않음.
Register file → L1 cache → L2 cache → L3 cache → Main memory(DRAM) → Hard disk/SSD

- Register spilling: Register file은 CPU 안에 있어서 매우 빠르다. 만약 필요한 variable이 register보다 많은 경우, 컴파일러가 일부분을 L1 cache로 “spill”한다. 이는 하드웨어가 아닌 compiled code에 의해서 관리된다.
- Automatic cache management: L1, L2, L3 cache 사이에 움직이는 것은 하드웨어가 처리한다.
- Automatic demand paging: 만약 프로그램이 DRAM에 없는 메모리를 access하려고 할 경우 paging이 일어난다. OS가 자동으로 필요한 page를 memory로 로딩한다.
Memory Hierarchy with a 5-stage pipeline

- L1 cache에 대해서는 I-cache랑 D-cache를 분리

- L2, L3, DRAM에 대해서는 unified 형태
cf. Cache Hierachy: CPU에 가까울수록 high (ex. L1 cache)
SRAM/DRAM:
SRAM (static random access memory)- 접근 속도가
Hierarchical Performance Analysis
각 memory hierarchy level에서의 access time이 t_i이라고 하자.
Ti=hi⋅ti+mi⋅(ti+Ti+1)
- hi: hit rate, 이 때 access time: ti
- mi: miss rate, 이 때 access time: ti+Ti+1
Cache as Request Filter

BR: Bandwidth requested
BP: Bandwidth provided
각각의 cache level을 일종의 필터처럼 생각할 수가 있다.
Hierarchy Design Considerations
- DRAM (Dynamic RAM)
- used for large memory
- optimized for Capacity/$
- SRAM (Static RAM)
- Static RAM, cache나 register file에 사용된다.
- Capacity, latency, Capacity/$ 등 다양한 compromise를 고려
- Working set: 어떤 process에서 현재 사용하고 있는 데이터
Cache design basics
Cache interface

Basic operation: cache는 어떻게 작동하는가?
- Address가 주어지면, cache에서 그 address를 찾는다
- Hit → data를 리턴한다
- Miss → Cache에 저장할 새로운 주소를 정한다
- Update cache
Basic Cache Parameters
- M-bit address: Address space의 전체 크기 (ex. 4GB address space라면 32-bit)
- C (capacity): cache의 총 데이터 사이즈 (ex. 16KB = 2^16 bits)
- G = 2g (granularity): 한 번에 몇 byte를 가져올 것인가? (4 bytes per word)
Direct-mapped cache
- Tag bank: 주소 중에서 tag 비트를 저장한다.
- Data bank: 실제 데이터를 저장하는 역할 (각 줄당 G bytes)
- Valid bit: cache에 있는 데이터가 초기화된 상태인지 확인

m-bit의 주소를 다음과 같이 나눈다.
- idx: 특정 cache block 선택
- tag: cache hit인지 아닌지 확인
- bo (block offset): 만약 hit이라면, 해당 block 안에서 가져올 byte를 선택
- g: 요청한 byte 수 (ex. lw: 4byte)
Cache hit logic
- Address에서 index를 확인해서 맞는 line을 찾는다.
- address에 있는 tag와 tag bank에 있는 tag를 비교한다.
- valid bit를 확인한다 (dirty, 즉 데이터가 초기화되지 않은 상태이면 안 되기 때문에)
→ 이 모든 게 다 맞으면 cache hit이다!
용어 정리를 하고 가자
- page: virtual memory system에 있는, 고정된 사이즈의 memory block.
- cache block/line: CPU가 cache하는 데이터의 단위.
- set: 같은 index를 가지는 cache block/line들의 모임.
Block size & Tag storage overhead
Block size가 작을 경우 tag space를 쓸데없이 낭비하게 된다.
Block size를 늘리면 어떻게 될까?
아래 그림의 cache 에서, 1 row = 1 cache block = 1 cache line
가로 길이가 block size, 세로 길이가 block의 개수라고 생각하면 된다.
오른쪽과 같이 block size를 늘리게 되면 한 번에 가져오는 data가 더 많아진다고 생각하면 됨.
따라서 tag가 전체 cache에서 차지하는 공간이 적어지게 된다.

- tag: 현재 cache에 있는 address
- idx: cache 안에서의 line number를 선택
- bo (block offset): block 안에서 단어를 선택
- g: granularity (byte offset inside word)
Block size and miss rate
block size를 늘릴 때의 장점 (Total capacity C가 고정되어 있을 때)
- Spatial locality가 올라감 (한 번에 multi-word block을 fetch한다는 거 자체가 주변 block까지 가져온다는 뜻이기 때문에)
- Miss penalty는 block당 발생하기 때문에 페널티가 줄어들게 됨
- tag overhead 감소
block size를 늘릴 때의 단점:
- capacity 낭비
- latency 증가 (아래 써있음)
- block수가 줄어들기 때문에 cache 내부에서 conflict가 발생할 가능성이 올라감
Block size and Ti+1 (total access time)
- block이 커지면 loading time도 늘어남 (예를 들어 block의 맨 끝에 있는 단어를 load해야 될 경우 그 block 전체가 loading 될 때까지 기다려야 함!)
- 이를 해결하기 위한 2가지 방법이 있음
Conflicts in direct-mapped cache
= direct-mapped cache에서는 필연적으로 conflict miss가 발생하게 된다!

다음과 같은 Direct mapped cache 그림을 다시 생각해 보자. address가 다르더라도 index가 같으면 같은 cache block으로 매핑되게 된다.
예를 들어, cache size C = 16KB = 2^14 B 이고 block size B = 64B 라고 생각해보면 index는 log_2^C/B = 256개가 된다. 따라서 256번째 memory block마다 collision이 일어난다.
Set-associative cache
📌 Key Point
- Direct-mapped cache는 하나의 index당 저장할 수 있는 위치가 하나만 존재해서 conflict가 일어나게 된다.
- 그렇다면 여러 개의 direct-mapped cache를 묶어서 쓰면 하나의 index가 여러 위치에 저장되어, collision을 최소화할 수 있지 않을까?

📌 기본적인 구조
- Cache를 ”set”으로 나눠서, 각각의 set는 a개의 cache line으로 구성되어 있다.
- 하나의 index가 하나의 set으로 매핑되는데, 각각의 set 안에서는 a개 중 어디에나 들어갈 수 있게 된다.
- set당 여러 개의 line으로 매핑된다
|
Field
|
Bits
|
Role
|
|
Tag
|
remaining bits
|
compared to identify the cache line(block)
|
|
Index
|
log₂(# sets)
|
selects the set
|
|
Offset
|
log₂(B)
|
selects byte within cache line(block)
|
Replacement policy for set-associative cache
LRU (Least Recently Used): 제일 나중에 쓰던 memory block부터 제거한다
Fully associative cache
Block 개수가 C/B개인 cache이다.
각 row마다 tag, valid bit, data가 존재한다.

주소가 주어지면 모든 block에서 tag를 비교해서, 맞으면 hit,
저 삼각형 모양들이 사실 하나의 큰 mux이며, C/B개의 cache line이 input이고 tag 일치 여부 && valid bit 이 control signal이다.
Fully associative cache의 특징
- C/B - way associative cache와 같다.
- CAM = Content-Addressable Memory이다.
시험 문제 풀이
ex. 2021 final 2-A, 2-B
Memory address: 16-bit = 2^16 Cache line size: 16 bytes = 2^4 Cache capacity: 64 bytes = 2^6 Set-associativity: 2
A. How many bits are required for a tag for a cache line in this cache?
sol) tag / idx / offset로 비트를 나눌 수 있다.
cache line이 16 bytes → offset = 4 bits
Cache size = # of sets * line size * associativity 에서
64 = ? * 16 * 2 , # of sets = 2
so, index: 1 bit
tag = 16-4-1 = 11 bits
offset: 32-11-1=20
B. What is the total storage overhead per cache line other than the tag bits?
Storage overhead: 전체 cache 안에서 tag bits가 차지하는 byte 수
valid bit 1 bit + dirty bit 1 bit + LRU bit 0.5 bit = 2.5bits
total 128 bits → 2.5/128
- Total cache size = C, block size = B, associativity = a
- Number of sets = C / (B × a)
- Tag, index, offset 계산:
ex. 2021 final 3-A
Page size: 4 KB = 2^12 B Cache capacity: 128 KB = 2^17 B Cache set-associativity: 4 Cache line size (= block size): 64 bytes = 2^6 B
- How many copies of the same data can exist in the cache due to the synonym problem?
- Page offset = 12 bits
- cache size = block size * cache sets * set associativity
- block offset = 6 bits
- 따라서 cache lookup에 필요한 총 bit 수는 9(index)+6(offset) = 15 bits이다.
- 그러나 page offset은 12 bits이므로, 2^3 =8개의 synonym이 발생하게 된다.
14. Memory Hierarchy 2
Classification of cache misses
→ Cold, Capacity, Conflict miss!
- Cold miss
- 어떤 address를 처음으로 access할 때 발생하는 miss
- 어쩔 수 없이 일어난다는 의미에서 compulsory miss라고도 부른다.
- Domination: Locality가 적을 때 (여기저기서 불규칙적으로 access할 때)

- Capacity miss
- cache size가 data size보다 작을 때
- Domination: C (Cache capacity) < W (Working set size) 일 때 (Cache size가 작은 거)

- Conflict miss
- Direct-mapped, set-associative cache에서 collision에 의해 miss가 날 때
- Domination: C (Cache size) ≈ W (Working set size)일 때, C/B (같은 건 아니지만 associativity)가 작을 때

Cache read/write (issues)
- Read access: tag, data bank에 동시에 접근
- Write access: tag bank에 먼저 접근하고, write-hit인 경우에만
- 문제: Partial-word write

Store buffer
- Tag bank → data bank 이렇게 순차적으로 접근하면 Store가 여러 cycle 걸리는데, 다음 instruction도 memory instruction이면 structural hazard 발생
- Store buffer:
- Memory forwarding: 같은 address에서 load했을 때 업데이트되기 전의 데이터를 보면 안 되기 때문에, store buffer를 먼저 확인하고 load해서 RAW correctness를 보장한다.
Blocking vs non-blocking cache
- Blocking cache: Cache miss가 발생했을 때 CPU가 완전히 stall
- Non-blocking cache: Cache miss가 발생해도 다른 instruction을 계속 실행.
MSHR (Miss Status Handling Register)
non-blocking cache에서 사용하는 방법
말 그대로 miss인 cache register를 트래킹하는 것을 의미한다.

각 MSHR의 구성은 다음과 같다.
- block address: 어느 cache line이 fetch되고 있는가?
- list of pending loads: dest register, format (byte/word, signed/unsigned), block offset
- Cache miss 발생 → 새로운 MSHR를 할당 (primary miss), 다른 instruction들은 정상적으로 실행
- 새로운 cache miss 발생
- 더 이상 할당할 MSHR entry가 없을 경우 pipeline을 stall한다.
Write-hit / Write-miss policy
데이터를 memory에 store하려고 할 때, write할 주소가 이미 cache에 있으면 Write-hit, 없으면 Write-miss이다.
Write hit: write-back or write-through?
Write-back: Cache에만 쓰고 “Dirty” bit로 지정한 후, 나중에 write back을 한다.
- Dirty: cache에서는 update되었는데 main memory에서는 아직 update되지 않은 것을 의미.
- Dirty가 아니면 write-back을 할 필요가 없음
- L1 cache와 같이 낮은 hierarchy에서 필요한 bandwidth를 줄일 수 있다. (MB/s)
Write-through: Cache에도 쓰고, 아래 레벨에 있는 cache와 memory 등에 모두 쓴다. (ex. L1 cache에서 write hit이 발생했으면 L2, L3를 거쳐서 순차적으로 main memory까지 모두 update한다)
Write miss: write-alloc or write no-alloc?
Write-allocate: Block을 cache에 load한 후에 update한다.
- temporal locality를 활용할 수 있다. (근처에 있는 address를 load할 경우 미리 cache에 로딩을 해놨기 때문에)
Write no-allocate: Block을 cache가 아닌, lower-level memory에 직접 쓴다.
- store와 load 사이에 locality가 높지 않을 경우 굳이 그 데이터를 cache에다가 저장해놓을 필요가 없어서 효율적일 수 있다.
cf. C/B effect: Cache size/block size 의미로
Design tradeoffs
Hierarchy가 높을수록 (ex. L1 cache)
- C는 작아진다 (capacity): 안에 들어 있는 SRAM에 따라 access time이 결정되기 때문에 규모가 작아야 한다
- B는 작아진다 (block size): spatial locality, C/B (cache block)의 개수에 영향을 받음
- a: 적당히
Hierarchy가 낮을수록 (ex. LLC cache)
- C, B가 커진다
Inclusive vs Exclusive cache
LLC (last level cache)


Inclusive cache
- L1에 있는 block이라면 L2, L3에도 있다.
- 문제점: Back invalidation: LLC에서 evict되면 모든 다른 upper level cache에서도 evict 된다.
Exclusive cache
- 문제점: 예를 들어, L1에서 cache miss → LLC까지 cache miss가 났을 때, inclusive cache는 바로 DRAM access하면 되지만 Exclusive cache는 다른 L1도 확인해봐야 함.
'cs > csed311' 카테고리의 다른 글
| Synchronization & Consistency (0) | 2025.07.07 |
|---|---|
| Virtual memory (0) | 2025.07.07 |
| 12. Advanced CPU (0) | 2025.04.14 |
| 11. Exceptions and Interrupt (0) | 2025.04.14 |
| 10. Pipelined CPU - Branch Prediction (0) | 2025.04.14 |