메모리 계층 구조

메모리 계층 구조

개요

컴퓨터 시스템에서 CPU와 메모리 간의 속도 차이는 성능의 주요 병목입니다. 메모리 계층 구조(Memory Hierarchy)는 속도, 용량, 비용의 트레이드오프를 최적화하여 이 문제를 해결합니다. 이 레슨에서는 메모리 계층 구조의 원리, 지역성의 개념, 그리고 각 계층의 특성을 학습합니다.

난이도: ⭐⭐

선수 지식: 컴퓨터 시스템 개요, CPU 구조 기초


목차

  1. 메모리 계층 구조의 필요성
  2. 지역성 원리
  3. 메모리 기술 비교
  4. 메모리 계층
  5. 메모리 대역폭과 지연시간
  6. 메모리 성능 최적화
  7. 연습 문제

1. 메모리 계층 구조의 필요성

1.1 CPU-메모리 속도 격차

CPU와 메모리 성능 발전 추이 (1980-2020):

성능
  │
  │                                        ●────────── CPU
  │                                   ●
  │                              ●
  │                         ●
  │                    ●
  │               ●
  │          ●                               ◆───────── 메모리
  │     ●                              ◆
  │ ●                            ◆
  │                        ◆
  │                  ◆
  │            ◆
  │      ◆
  │ ◆
  └─────────────────────────────────────────────────── 연도
   1980    1990    2000    2010    2020

CPU: 연간 ~50% 성능 향상 (1980-2000)
메모리: 연간 ~7% 성능 향상

결과: "Memory Wall" - 메모리가 시스템 성능의 병목

1.2 이상적인 메모리 vs 현실

이상적인 메모리:
┌─────────────────────────────────────────┐
│  - 무한대 용량                           │
│  - 0 접근 시간                           │
│  - 무료                                 │
└─────────────────────────────────────────┘

현실:
┌─────────────────────────────────────────────────────────────┐
│  속도 ↑ = 비용 ↑, 용량 ↓                                     │
│  용량 ↑ = 비용 ↑, 속도 ↓                                     │
│  비용 ↓ = 속도 ↓, 용량 제한                                   │
└─────────────────────────────────────────────────────────────┘

해결책: 메모리 계층 구조
- 여러 종류의 메모리를 계층적으로 배치
- 빠르고 작은 메모리를 CPU 가까이
- 느리고 큰 메모리를 멀리
- 자주 사용하는 데이터를 빠른 메모리에 유지

1.3 메모리 계층 개념

                        ┌───────────┐
                        │ 레지스터   │  ← 가장 빠름, 가장 작음, 가장 비쌈
                        │   ~1KB    │
                        └─────┬─────┘
                              │
                        ┌─────┴─────┐
                        │ L1 캐시   │
                        │  ~64KB   │
                        └─────┬─────┘
                              │
                    ┌─────────┴─────────┐
                    │     L2 캐시        │
                    │    ~256KB-1MB     │
                    └─────────┬─────────┘
                              │
            ┌─────────────────┴─────────────────┐
            │            L3 캐시                  │
            │           ~2-32MB                 │
            └─────────────────┬─────────────────┘
                              │
    ┌─────────────────────────┴─────────────────────────┐
    │                   메인 메모리                        │
    │                  ~8-128GB                         │
    └─────────────────────────┬─────────────────────────┘
                              │
┌─────────────────────────────┴─────────────────────────────┐
│                        SSD/HDD                             │
│                     ~256GB-10TB                            │  ← 가장 느림, 가장 큼, 가장 저렴
└───────────────────────────────────────────────────────────┘

위로 갈수록: 빠름, 작음, 비쌈, CPU에 가까움
아래로 갈수록: 느림, 큼, 저렴, CPU에서 멀음

2. 지역성 원리

2.1 지역성이란?

프로그램이 메모리를 접근하는 패턴에는 규칙성이 있습니다. 이를 지역성(Locality)이라 하며, 메모리 계층 구조가 효과적인 이유입니다.

2.2 시간적 지역성 (Temporal Locality)

정의: 최근에 접근한 데이터는 가까운 미래에 다시 접근될 가능성이 높음

예시 1: 반복문의 변수
┌─────────────────────────────────────┐
 for (i = 0; i < 1000; i++) {       
     sum += array[i];               
 }                                  
└─────────────────────────────────────┘
  변수 'sum', 'i' 1000 반복 접근

예시 2: 자주 호출되는 함수
┌─────────────────────────────────────┐
 while (running) {                  
     process_event();  // 반복 호출  
     update_state();   // 반복 호출  
 }                                  
└─────────────────────────────────────┘
  함수 코드는 계속 재사용됨

시간적 지역성 활용:
- 최근 접근한 데이터를 캐시에 유지
- 다시 접근  캐시에서 빠르게 제공

2.3 공간적 지역성 (Spatial Locality)

정의: 접근한 데이터 주변의 데이터도  접근될 가능성이 높음

예시 1: 배열 순차 접근
┌─────────────────────────────────────┐
 for (i = 0; i < N; i++) {          
     sum += array[i];               
 }                                  
└─────────────────────────────────────┘

메모리 레이아웃:
주소:  0x100  0x104  0x108  0x10C  0x110  0x114
       ┌──────┬──────┬──────┬──────┬──────┬──────┐
array:  a[0]  a[1]  a[2]  a[3]  a[4]  a[5] 
       └──────┴──────┴──────┴──────┴──────┴──────┘
                                       
       순차적으로 접근 - 공간적 지역성 높음

예시 2: 구조체 접근
┌─────────────────────────────────────┐
 struct Point { int x, y, z; };     
 Point p;                           
 distance = sqrt(p.x*p.x +          
                 p.y*p.y +          
                 p.z*p.z);          
└─────────────────────────────────────┘
  p.x, p.y, p.z는 메모리상 인접

공간적 지역성 활용:
- 캐시 라인(블록) 단위로 데이터 로드
-  번에 여러 인접 데이터 가져옴
- 64바이트 캐시 라인 = 16 int 포함

2.4 지역성을 활용한 최적화

좋은 코드 (높은 지역성):

//  우선 순회 - 메모리 레이아웃에 맞춤
for (i = 0; i < N; i++) {
    for (j = 0; j < N; j++) {
        sum += matrix[i][j];
    }
}

메모리 접근 패턴:
[0,0] [0,1] [0,2] [0,3] ... [1,0] [1,1] ...
                              
순차적 접근  캐시 히트율 높음


나쁜 코드 (낮은 지역성):

//  우선 순회 - 메모리 레이아웃과 불일치
for (j = 0; j < N; j++) {
    for (i = 0; i < N; i++) {
        sum += matrix[i][j];
    }
}

메모리 접근 패턴:
[0,0] [1,0] [2,0] [3,0] ... [0,1] [1,1] ...
                              
N개 간격 점프  캐시 미스 빈번


성능 차이 (N=1024, 8바이트 원소):
-  우선: ~50ms
-  우선: ~500ms (10 느림)

2.5 Working Set

정의: 특정 시간 구간 동안 프로그램이 활발히 사용하는 메모리 영역

┌─────────────────────────────────────────────────────────────┐
                                                              
  프로그램 실행 단계별 Working Set 변화                         
                                                              
  단계 1: 초기화                                               
  Working Set: [초기화 코드] + [설정 데이터]                   
  크기: ~100KB                                                
                                                              
  단계 2: 데이터 처리                                          
  Working Set: [처리 코드] + [입력 버퍼] + [출력 버퍼]          
  크기: ~10MB                                                 
                                                              
  단계 3: 결과 출력                                            
  Working Set: [출력 코드] + [출력 버퍼]                       
  크기: ~500KB                                                
                                                              
└─────────────────────────────────────────────────────────────┘

캐시 크기와 Working Set:
- Working Set < 캐시 크기: 높은 히트율
- Working Set > 캐시 크기: 스래싱 발생 가능

3. 메모리 기술 비교

3.1 SRAM (Static RAM)

SRAM 셀 구조 (6T SRAM):

        Vdd                         Vdd
         │                           │
      ┌──┴──┐                     ┌──┴──┐
      │ P1  │                     │ P2  │
      └──┬──┘                     └──┬──┘
         │          ┌───┐            │
         ├──────────┤   ├────────────┤
         │          └───┘            │
      ┌──┴──┐                     ┌──┴──┐
      │ N1  │        Word         │ N2  │
      └──┬──┘        Line         └──┬──┘
         │            │              │
         │         ┌──┴──┐           │
         │         │ N3  │           │
         │         └──┬──┘           │
         │            │              │
        Bit         GND            ~Bit
        Line                       Line

특징:
- 6개 트랜지스터로 1비트 저장
- 전원 공급 시 데이터 유지 (리프레시 불필요)
- 빠른 접근 속도 (~1-2ns)
- 높은 비용, 낮은 집적도
- 용도: 캐시 메모리, 레지스터 파일

3.2 DRAM (Dynamic RAM)

DRAM 셀 구조 (1T1C DRAM):

    Word Line
        │
     ┌──┴──┐
     │  T  │ (트랜지스터)
     └──┬──┘
        │
     ┌──┴──┐
     │  C  │ (커패시터)
     └──┬──┘
        │
    Bit Line

특징:
- 1개 트랜지스터 + 1개 커패시터로 1비트 저장
- 커패시터 누수로 인해 주기적 리프레시 필요 (~64ms)
- 느린 접근 속도 (~50-100ns)
- 저렴한 비용, 높은 집적도
- 용도: 메인 메모리 (DDR4, DDR5)

DRAM 접근 과정:
1. Row Activate (RAS): 행 선택, 센스 앰프로 데이터 이동
2. Column Read (CAS): 열 선택, 데이터 출력
3. Precharge: 다음 접근 준비

┌─────────────────────────────────────────────────────┐
│ RAS Latency │ CAS Latency │ Precharge │ = 전체 지연 │
└─────────────────────────────────────────────────────┘
    ~15ns        ~15ns         ~15ns       ~45ns+

3.3 플래시 메모리 (SSD)

NAND Flash 구조:

     Word Line 0  Word Line 1  Word Line 2
          │           │           │
    ┌─────┼───────────┼───────────┼─────┐
    │  ┌──┴──┐     ┌──┴──┐     ┌──┴──┐  │
    │  │Cell │     │Cell │     │Cell │  │ String 0
    │  └──┬──┘     └──┬──┘     └──┬──┘  │
    │     │           │           │     │
    │  ┌──┴──┐     ┌──┴──┐     ┌──┴──┐  │
    │  │Cell │     │Cell │     │Cell │  │ String 1
    │  └──┬──┘     └──┬──┘     └──┬──┘  │
    └─────┼───────────┼───────────┼─────┘
          │           │           │
       Bit Line    Bit Line    Bit Line

특징:
- 플로팅 게이트에 전하 저장
- 비휘발성 (전원 없어도 데이터 유지)
- 읽기: ~25us, 쓰기: ~250us, 삭제: ~2ms
- 블록 단위 삭제만 가능
- 용도: SSD, USB 드라이브, SD 카드

3.4 메모리 기술 비교표

┌──────────────┬───────────┬───────────┬───────────┬───────────┐
│    특성       │   SRAM    │   DRAM    │  NAND     │   HDD     │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 접근 시간     │  1-2ns    │  50-100ns │  25us     │  5-10ms   │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 비용/GB      │  ~$5000   │  ~$3-5    │  ~$0.1    │  ~$0.02   │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 휘발성       │    Yes    │    Yes    │    No     │    No     │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 일반 용량    │  ~32MB    │  ~128GB   │  ~4TB     │  ~20TB    │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 밀도         │    낮음    │   높음    │  매우 높음 │  매우 높음 │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 전력 소비    │    높음    │   중간    │   낮음    │   높음    │
├──────────────┼───────────┼───────────┼───────────┼───────────┤
│ 주 용도      │  캐시     │ 메인 메모리│   SSD    │ 대용량 저장│
└──────────────┴───────────┴───────────┴───────────┴───────────┘

4. 메모리 계층

4.1 레지스터

위치: CPU 내부
용량: 수십 ~ 수백  (x86-64: 16 범용 + 기타)
속도: 1 사이클 (0.3ns @ 3GHz)

레지스터 종류:
┌────────────────────────────────────────────────────────┐
 범용 레지스터     RAX, RBX, RCX, RDX, RSI, RDI, ...   
├────────────────────────────────────────────────────────┤
 프로그램 카운터   RIP (Instruction Pointer)           
├────────────────────────────────────────────────────────┤
 스택 포인터      RSP, RBP                             
├────────────────────────────────────────────────────────┤
 플래그 레지스터   RFLAGS (Zero, Carry, Sign, ...)    
├────────────────────────────────────────────────────────┤
 벡터 레지스터    XMM0-15, YMM0-15, ZMM0-31 (SIMD)    
├────────────────────────────────────────────────────────┤
 부동소수점       ST0-ST7 (x87), XMM (SSE)            
└────────────────────────────────────────────────────────┘

레지스터 vs 메모리 성능:
- 레지스터 연산: ADD R1, R2, R3   1 사이클
- 메모리 연산:   ADD R1, [mem]    4+ 사이클 (L1 히트)

4.2 캐시 메모리

캐시 계층 (현대 CPU):

┌─────────────────────────────────────────────────────────────┐
│                          Core 0                              │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  ┌──────────────┐    ┌──────────────┐               │    │
│  │  │ L1 I-Cache   │    │ L1 D-Cache   │               │    │
│  │  │   32KB       │    │   32KB       │               │    │
│  │  │   4 cycles   │    │   4 cycles   │               │    │
│  │  └──────┬───────┘    └──────┬───────┘               │    │
│  │         │                   │                        │    │
│  │         └─────────┬─────────┘                        │    │
│  │                   │                                  │    │
│  │         ┌─────────┴─────────┐                        │    │
│  │         │     L2 Cache      │                        │    │
│  │         │      256KB        │                        │    │
│  │         │     12 cycles     │                        │    │
│  │         └─────────┬─────────┘                        │    │
│  └───────────────────┼──────────────────────────────────┘    │
│                      │                                       │
├──────────────────────┼───────────────────────────────────────┤
│                      │           Core 1                      │
│                      │     (동일 구조)                        │
├──────────────────────┼───────────────────────────────────────┤
│           ┌──────────┴──────────┐                            │
│           │     L3 Cache         │                            │
│           │   8-32MB (공유)       │                            │
│           │    40 cycles         │                            │
│           └──────────┬──────────┘                            │
└──────────────────────┼───────────────────────────────────────┘
                       │
                       ▼
              ┌─────────────────┐
              │   Main Memory   │
              │   100+ cycles   │
              └─────────────────┘

캐시 특성 요약:
┌───────┬──────────┬───────────────┬──────────────────────────┐
│ 레벨  │   용량    │  지연시간     │         특징              │
├───────┼──────────┼───────────────┼──────────────────────────┤
│  L1   │  32-64KB │   4 cycles    │ 코어 전용, I/D 분리       │
├───────┼──────────┼───────────────┼──────────────────────────┤
│  L2   │ 256KB-1MB│  12 cycles    │ 코어 전용 또는 공유       │
├───────┼──────────┼───────────────┼──────────────────────────┤
│  L3   │  8-64MB  │  40 cycles    │ 전체 코어 공유            │
└───────┴──────────┴───────────────┴──────────────────────────┘

4.3 메인 메모리 (DRAM)

현대 메모리 시스템 구조:

          ┌─────────────────────────────────────────────┐
          │               Memory Controller              │
          │            (CPU 또는 노스브리지 내장)         │
          └──────────────────┬──────────────────────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────┴────┐         ┌────┴────┐         ┌────┴────┐
    │Channel 0│         │Channel 1│         │Channel 2│
    └────┬────┘         └────┬────┘         └────┬────┘
         │                   │                   │
    ┌────┴────┐         ┌────┴────┐         ┌────┴────┐
    │ DIMM 0  │         │ DIMM 0  │         │ DIMM 0  │
    │ 16GB    │         │ 16GB    │         │ 16GB    │
    └─────────┘         └─────────┘         └─────────┘

DDR (Double Data Rate) 발전:
┌────────┬─────────────┬──────────────┬───────────────────┐
│ 세대    │  클럭 속도   │  대역폭/채널  │     특징          │
├────────┼─────────────┼──────────────┼───────────────────┤
│ DDR3   │  800-2133   │  6.4-17GB/s  │ 1.5V             │
├────────┼─────────────┼──────────────┼───────────────────┤
│ DDR4   │ 1600-3200   │ 12.8-25.6GB/s│ 1.2V, 뱅크 그룹   │
├────────┼─────────────┼──────────────┼───────────────────┤
│ DDR5   │ 3200-6400+  │ 25.6-51.2GB/s│ 1.1V, 내장 ECC   │
└────────┴─────────────┴──────────────┴───────────────────┘

4.4 보조 기억장치

SSD 구조:
┌─────────────────────────────────────────────────────────────┐
│                        SSD Controller                        │
│  ┌─────────────────────────────────────────────────────┐    │
│  │ Flash Translation Layer (FTL)                        │    │
│  │ - 논리 주소 → 물리 주소 변환                          │    │
│  │ - Wear Leveling                                     │    │
│  │ - Garbage Collection                                │    │
│  └─────────────────────────────────────────────────────┘    │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ NAND    │ │ NAND    │ │ NAND    │ │ NAND    │           │
│  │ Package │ │ Package │ │ Package │ │ Package │           │
│  │   0     │ │   1     │ │   2     │ │   3     │           │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘           │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ NAND    │ │ NAND    │ │ NAND    │ │ NAND    │           │
│  │ Package │ │ Package │ │ Package │ │ Package │           │
│  │   4     │ │   5     │ │   6     │ │   7     │           │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘           │
└─────────────────────────────────────────────────────────────┘

HDD vs SSD 비교:
┌─────────────────┬────────────────┬────────────────┐
│      특성        │      HDD       │      SSD       │
├─────────────────┼────────────────┼────────────────┤
│ 순차 읽기       │   150 MB/s     │  500-7000 MB/s │
├─────────────────┼────────────────┼────────────────┤
│ 랜덤 읽기       │   0.5 MB/s     │  50-500 MB/s   │
├─────────────────┼────────────────┼────────────────┤
│ 지연시간        │   5-10 ms      │   0.02-0.1 ms  │
├─────────────────┼────────────────┼────────────────┤
│ IOPS (랜덤)    │    ~200        │  10K-1M        │
├─────────────────┼────────────────┼────────────────┤
│ 내충격성        │    약함         │    강함        │
├─────────────────┼────────────────┼────────────────┤
│ GB당 가격       │   $0.02        │   $0.10        │
└─────────────────┴────────────────┴────────────────┘

5. 메모리 대역폭과 지연시간

5.1 대역폭 (Bandwidth)

정의: 단위 시간당 전송 가능한 데이터  (bytes/second)

계산:
대역폭 = 버스  × 전송 속도

예시 (DDR4-3200):
- 버스 : 64비트 = 8바이트
- 전송 속도: 3200 MT/s (Mega Transfers per second)
- 대역폭 = 8 × 3200 = 25,600 MB/s = 25.6 GB/s (채널당)

듀얼 채널: 25.6 × 2 = 51.2 GB/s
쿼드 채널: 25.6 × 4 = 102.4 GB/s

시스템별 메모리 대역폭:
┌─────────────────────────┬────────────────────────┐
        시스템                   대역폭           
├─────────────────────────┼────────────────────────┤
 일반 데스크톱 (DDR4)         25-50 GB/s        
├─────────────────────────┼────────────────────────┤
 하이엔드 워크스테이션       100-200 GB/s       
├─────────────────────────┼────────────────────────┤
 서버 (8채널 DDR5)          300-400 GB/s       
├─────────────────────────┼────────────────────────┤
 GPU (HBM2)                 1-2 TB/s           
└─────────────────────────┴────────────────────────┘

5.2 지연시간 (Latency)

정의: 데이터 요청부터 수신까지 걸리는 시간

메모리 계층별 지연시간:

레벨         지연시간 (cycles)  지연시간 (ns)  상대 비용
────────────┼───────────────────┼───────────────┼───────────
레지스터             1              ~0.3         1x
L1 캐시            4-5             ~1.5         4x
L2 캐시           12-14            ~4          12x
L3 캐시           40-50           ~15          40x
메인 메모리       100-300         ~60-100      200x
SSD           10,000-50,000      25-100us    50,000x
HDD         10,000,000+           5-10ms     20,000,000x

시각화:
┌───────────────────────────────────────────────────────────┐
                                                           
 L1:                                                     
 L2:    ●●●                                               
 L3:    ●●●●●●●●●●●●●                                      
 RAM:   ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●● 
                                                           
 SSD:   [...]                    (너무 길어 표시 불가)       
 HDD:   [...]                    (더더욱 표시 불가)          
                                                           
└───────────────────────────────────────────────────────────┘

5.3 Latency vs Bandwidth 관계

Little's Law:
동시 요청 수 = 대역폭 × 지연시간

메모리 시스템에서의 의미:
- 대역폭 활용을 위해 다수의 동시 요청 필요
- 지연시간이 길면 더 많은 동시 요청 필요

예시:
- 대역폭: 50 GB/s
- 지연시간: 100 ns
- 캐시 라인: 64 bytes

필요한 동시 요청 수:
= (50 × 10^9) × (100 × 10^-9) / 64
= 78개 동시 요청

해결책:
- 비순차 실행으로 다수의 로드 동시 발행
- 프리페치로 미리 데이터 요청
- 메모리 레벨 병렬성 (MLP) 활용

5.4 AMAT (Average Memory Access Time)

공식:
AMAT = Hit Time + (Miss Rate × Miss Penalty)

예시:
- L1 히트 시간: 4 사이클
- L1 미스율: 5%
- L2 히트 시간: 12 사이클
- L2 미스율: 20% (L1 미스 )
- 메모리 접근 시간: 200 사이클

계산:
AMAT = 4 + 0.05 × (12 + 0.20 × 200)
     = 4 + 0.05 × (12 + 40)
     = 4 + 0.05 × 52
     = 4 + 2.6
     = 6.6 사이클

다중 레벨 캐시의 AMAT:
┌──────────────────────────────────────────────────────────┐
 AMAT = T_L1 + MR_L1 × (T_L2 + MR_L2 × (T_L3 + MR_L3 × T_Mem))
└──────────────────────────────────────────────────────────┘

6. 메모리 성능 최적화

6.1 데이터 레이아웃 최적화

Structure of Arrays (SoA) vs Array of Structures (AoS):

AoS (Array of Structures):
struct Particle {
    float x, y, z;      // 12 bytes
    float vx, vy, vz;   // 12 bytes
    float mass;         // 4 bytes
    int   id;           // 4 bytes
};                      //  32 bytes

Particle particles[1000];

메모리 레이아웃:
[x,y,z,vx,vy,vz,mass,id][x,y,z,vx,vy,vz,mass,id][...]

x 좌표만 접근할 : 32바이트마다 4바이트만 사용  낭비


SoA (Structure of Arrays):
struct Particles {
    float x[1000];
    float y[1000];
    float z[1000];
    float vx[1000];
    float vy[1000];
    float vz[1000];
    float mass[1000];
    int   id[1000];
};

메모리 레이아웃:
[x0,x1,x2,...][y0,y1,y2,...][z0,z1,z2,...]...

x 좌표만 접근할 : 연속된 메모리 접근  효율적

성능 차이: SoA가 최대 4-8배 빠를  있음 (SIMD 활용 )

6.2 루프 최적화

루프 타일링 (Loop Tiling / Blocking):

// 원본 코드 - 캐시 효율 낮음
for (i = 0; i < N; i++)
    for (j = 0; j < N; j++)
        for (k = 0; k < N; k++)
            C[i][j] += A[i][k] * B[k][j];

// 타일링 적용 - 캐시 효율 높음
#define BLOCK 64
for (ii = 0; ii < N; ii += BLOCK)
    for (jj = 0; jj < N; jj += BLOCK)
        for (kk = 0; kk < N; kk += BLOCK)
            for (i = ii; i < min(ii+BLOCK, N); i++)
                for (j = jj; j < min(jj+BLOCK, N); j++)
                    for (k = kk; k < min(kk+BLOCK, N); k++)
                        C[i][j] += A[i][k] * B[k][j];

효과:
┌──────────────────────────────────────────────────────────┐
 원본:  행렬 전체를 반복 접근  캐시 스래싱             
 타일링: 작은 블록을 완전히 처리  캐시에 유지           
                                                          
 N=1024, BLOCK=64 :                                  
 - 원본: ~10                                           
 - 타일링: ~2 (5 향상)                               
└──────────────────────────────────────────────────────────┘

6.3 프리페칭

하드웨어 프리페치:
- CPU가 접근 패턴을 감지하여 자동으로 프리페치
- 순차 접근, 스트라이드 접근에 효과적
- 불규칙한 접근에는 비효과적

소프트웨어 프리페치:
// Intel intrinsic 예시
for (i = 0; i < N; i++) {
    _mm_prefetch(&array[i + 16], _MM_HINT_T0);  // L1으로 프리페치
    sum += array[i];
}

프리페치 거리 계산:
거리 = 메모리 지연시간 / 루프 반복당 시간

예시:
- 메모리 지연시간: 100 사이클
- 루프 반복당 시간: 5 사이클
- 프리페치 거리: 100 / 5 = 20 요소 앞서 프리페치

주의사항:
- 너무 빠른 프리페치: 캐시에서 밀려남
- 너무 느린 프리페치: 데이터 도착  
- 불필요한 프리페치: 캐시 오염

6.4 메모리 정렬

정렬(Alignment) 중요성:

정렬된 접근:
주소: 0x1000 (64바이트 정렬)
┌───────────────────────────────────────────────┐
                64바이트 캐시 라인               
  [데이터 64바이트가  라인에 모두 포함]         
└───────────────────────────────────────────────┘
접근 횟수: 1회

비정렬 접근:
주소: 0x1020 (32바이트 오프셋)
┌─────────────────────┬─────────────────────────┐
     캐시 라인 1            캐시 라인 2        
  [...32바이트...]      [...32바이트...]       
└─────────────────────┴─────────────────────────┘
접근 횟수: 2회

정렬 지시어:
// C/C++
struct alignas(64) CacheLine {
    int data[16];
};

// 동적 할당
void* ptr = aligned_alloc(64, size);

7. 연습 문제

기초 문제

  1. 메모리 계층 구조가 필요한 이유를 설명하시오.

  2. 다음 코드에서 시간적 지역성과 공간적 지역성을 찾으시오: c for (i = 0; i < 100; i++) { sum += array[i]; }

  3. SRAM과 DRAM의 주요 차이점 3가지는?

중급 문제

  1. L1 캐시 히트 시간이 4사이클, 미스율이 8%, L2 접근 시간이 12사이클일 때 AMAT는?

  2. 다음 중 공간적 지역성을 해치는 코드는? ```c // (a) for (i = 0; i < N; i++) for (j = 0; j < N; j++) sum += a[i][j];

// (b) for (j = 0; j < N; j++) for (i = 0; i < N; i++) sum += a[i][j]; ```

  1. DDR4-3200 듀얼 채널의 이론적 최대 대역폭은?

심화 문제

  1. Working Set 크기가 캐시 크기보다 클 때 발생하는 문제와 해결책을 설명하시오.

  2. 다음 행렬 곱셈 코드를 루프 타일링을 적용하여 최적화하시오: c for (i = 0; i < N; i++) for (j = 0; j < N; j++) for (k = 0; k < N; k++) C[i][j] += A[i][k] * B[k][j];

  3. 프리페치 거리를 계산하시오:

  4. 메모리 지연시간: 60ns
  5. CPU 클럭: 3GHz
  6. 루프당 명령어: 10개, CPI: 1
정답 1. CPU와 메모리 간 속도 격차를 해소하기 위해. 빠르고 비싼 메모리를 CPU 가까이, 느리고 저렴한 메모리를 멀리 배치하여 비용 대비 성능 최적화. 2. - 시간적 지역성: 변수 `sum`, `i` (100번 반복 접근) - 공간적 지역성: `array[i]` (연속된 메모리 주소 접근) 3. SRAM vs DRAM: - 구조: SRAM 6T, DRAM 1T1C - 리프레시: SRAM 불필요, DRAM 필요 - 속도: SRAM 빠름 (~2ns), DRAM 느림 (~50ns) - 비용/밀도: SRAM 비쌈/낮음, DRAM 저렴/높음 4. AMAT = 4 + 0.08 × 12 = 4 + 0.96 = 4.96 사이클 5. (b) 열 우선 순회 - C/C++에서 배열은 행 우선 저장되므로 6. DDR4-3200: 8바이트 × 3200MT/s × 2채널 = 51.2 GB/s 7. 캐시 스래싱 발생 - 필요한 데이터가 반복적으로 교체됨 해결책: 루프 타일링, 데이터 레이아웃 최적화, 알고리즘 변경 8. 타일링 적용: ```c #define B 64 for (ii = 0; ii < N; ii += B) for (jj = 0; jj < N; jj += B) for (kk = 0; kk < N; kk += B) for (i = ii; i < ii+B && i < N; i++) for (j = jj; j < jj+B && j < N; j++) for (k = kk; k < kk+B && k < N; k++) C[i][j] += A[i][k] * B[k][j]; ``` 9. 프리페치 거리: - 메모리 지연: 60ns × 3GHz = 180 사이클 - 루프 시간: 10 명령어 × 1 CPI = 10 사이클 - 거리: 180 / 10 = 18 요소 앞서 프리페치

다음 단계


참고 자료

to navigate between lessons