0. 큰 그림

  • 목표: 여러 프로세서/컴퓨터를 연결더 높은 성능을 얻는 것(클라이언트~클라우드 전 범위)

  • 키워드

    • Multiprocessor / Multicore
    • Scalability(확장성), Availability(가용성), Power efficiency(전력 효율)
    • Task-level parallelism(서로 독립적인 작업을 많이 처리해서 처리량↑) vs Parallel program(단일 프로그램을 여러 프로세서에서 동시 실행)

1. 하드웨어/소프트웨어 관점 정리

1.1. 하드웨어

  • Serial 예: Pentium 4
  • Parallel 예: quad-core Xeon e5345

1.2. 소프트웨어

  • Sequential 예: 행렬 곱
  • Concurrent 예: 운영체제

1.3. 핵심 난점

  • 병렬 HW를 효과적으로 쓰게 만드는 SW/프로그래밍이 어렵다.

2. 병렬 프로그래밍이 어려운 이유 (§6.2)

병렬 SW가 본질적인 문제. 유의미한 성능 향상이 없으면 그냥 더 빠른 단일 코어 쓰는 게 낫다.

2.1. 3대 난점

  1. Partitioning(분할): 일을 어떻게 쪼개서 프로세서에 배치할지
  2. Coordination(조정/동기화): 결과 합치기, 순서/의존성 관리
  3. Communication overhead(통신 오버헤드): 코어 간/노드 간 데이터 이동 비용

3. Amdahl’s Law(암달의 법칙)와 한계

3.1. 기본 메시지

  • 순차(Serial) 부분이 전체 속도를 제한한다.
  • 예시: 프로세서 100개로 90× 가속하려면?
    • 속도향상식:
    • 이를 만족하려면 (순차는 0.1% 수준)

3.2. 해석 포인트

  • 코어 수가 늘수록, 남는 순차 구간/동기화/통신이 병목으로 크게 부각된다.

4. 스케일링(Scaling) 예제로 보는 직관

4.1. 강한 스케일링(Strong scaling): 문제 크기 고정

  • 작업: 10개 스칼라 합 + 10×10 행렬 합(총 110 add)
  • 10프로세서: 시간 , 속도 5.5×(잠재치의 55%)
  • 100프로세서: 시간 , 속도 10×(잠재치의 10%) → 문제 크기가 작으면 코어 늘려도 효율 급락

4.2. 문제 크기를 키우면 효율이 좋아진다

  • 행렬 100×100(총 10010 add)
    • 10프로세서: 9.9×(99% 잠재치)
    • 100프로세서: 91×(91% 잠재치)

4.3. 약한 스케일링(Weak scaling): 프로세서 수에 비례해 문제 크기 확대

  • 10프로세서 + 10×10 →
  • 100프로세서 + 32×32(≈1000) → 로 성능 유지(예시에서)

5. 병렬 컴퓨터 분류: Instruction/Data stream 관점

5.1. Flynn 분류

  • SISD: 단일 명령/단일 데이터 (전통적 단일 코어) 예: Pentium4
  • SIMD: 단일 명령/다중 데이터 (벡터/미디어 확장) 예: SSE
  • MISD: 다중 명령/단일 데이터 (현대 예 거의 없음)
  • MIMD: 다중 명령/다중 데이터 (멀티코어/멀티프로세서) 예: Xeon e5345

5.2. SPMD

  • Single Program Multiple Data: MIMD 머신에서 같은 프로그램을 여러 프로세서가 실행하되, 조건문으로 역할을 나눔

6. 벡터 프로세서(Vector Processor) 핵심

6.1. 개념

  • 고도로 파이프라인화된 기능 유닛에 대해 벡터 레지스터로 데이터 스트리밍
  • 메모리→레지스터로 모아서 처리하고 결과를 다시 저장

6.2. RISC-V 벡터 예

  • v0~v31: 32개 레지스터, 각 레지스터는 64개 원소(64-bit)

  • 대표 명령

    • fld.v / fsd.v (벡터 load/store)
    • fadd.d.v (벡터-벡터)
    • fadd.d.vs (벡터-스칼라)
  • 장점: 루프를 벡터 명령으로 바꾸면 instruction fetch bandwidth 부담 감소

6.3. 예제: DAXPY (Y = aX + Y)

  • 스칼라 코드: 루프에서 load/mul/load/add/store 반복
  • 벡터 코드: 벡터 load → 벡터-스칼라 mul → 벡터 add → 벡터 store 로 루프 오버헤드 제거

6.4. Vector vs Scalar 요점

  • 컴파일러가 데이터 병렬을 표현하기 쉽고, loop-carried dependence가 없음을 명시 가능 → HW 체크 감소
  • 규칙적 메모리 접근은 interleaved/burst 메모리에 유리
  • 루프 회피로 control hazard 감소
  • MMX/SSE 같은 ad-hoc 확장보다 더 일반적이며 컴파일러 친화적

7. SIMD 개념 정리

  • 벡터 데이터에 elementwise 연산
  • x86 MMX/SSE: 128-bit 레지스터에 여러 데이터 원소를 패킹
  • 모든 lane/프로세서가 같은 명령을 같은 시점에 실행(데이터 주소만 다름) → 동기화 단순
  • 데이터 병렬이 높은 애플리케이션에 특히 적합

7.1. Vector vs Multimedia Extensions

  • Vector: 가변 벡터 폭, stride 접근 지원
  • Multimedia 확장(SSE 등): 고정 폭, stride 지원 제한
  • (도식) 벡터 유닛은 파이프라인+배열 형태 기능 유닛 조합 가능

8. 하드웨어 멀티스레딩

8.1. Multithreading 기본

  • 여러 스레드의 실행을 병렬로 수행
  • 레지스터/PC 등 컨텍스트를 복제, 스레드 간 빠른 스위칭

8.2. Fine-grain vs Coarse-grain

  • Fine-grain MT: 매 사이클 스레드 전환(명령 인터리빙) → 한 스레드 스톨 시 다른 스레드 실행
  • Coarse-grain MT: 긴 스톨(L2 miss 등)에서만 전환 → HW 단순, 그러나 짧은 스톨(데이터 해저드 등) 은 숨기기 어려움

8.3. SMT(Simultaneous Multithreading)

  • 다중 발행/동적 스케줄링 프로세서에서 여러 스레드의 명령을 같은 사이클에 혼합 발행
  • 스레드 간 독립 명령이 유닛이 비면 실행, 스레드 내부 의존성은 스케줄링+레지스터 리네이밍으로 해결
  • 예: Pentium-4 HT(레지스터는 복제, 기능 유닛과 캐시는 공유)

8.4. 미래 전망

  • 전력 제약 → 단순한 마이크로아키텍처로 회귀 가능
  • 캐시 미스 지연 숨김에 스레드 전환이 효과적일 수 있음
  • 여러 단순 코어가 자원을 더 효율적으로 공유할 수도

9. 공유 메모리 멀티프로세서(SMP)

9.1. 개념

  • 모든 프로세서가 하나의 물리 주소 공간 공유

  • 공유 변수 동기화는 lock으로 수행

  • 메모리 접근 시간

    • UMA(uniform) vs NUMA(nonuniform)

9.2. 예제: Sum Reduction(UMA)

  • 64,000개 수를 64프로세서에서 합산
  1. 각 프로세서가 1000개씩 부분합 계산
  2. 부분합들을 reduction(분할정복)으로 합침: 절반이 쌍으로 더하고, 그 다음 1/4…
  • 단계 간 synch() 필요
  • 홀수 개 남을 때 Processor0가 빠진 원소 처리하는 조건 분기 포함

10. GPU 입문 - 그래픽에서 범용으로

10.1. 역사

  • 초기: 프레임버퍼와 비디오 출력 주소 생성
  • 이후: 3D 그래픽(버텍스/픽셀 처리, 셰이딩, 텍스처 매핑, 래스터화)
  • 무어의 법칙 → 저비용/고집적 → PC/콘솔용 3D 카드 확산 → GPU 등장

10.2. 시스템 내 위치(도식)

  • CPU–칩셋–PCIe로 GPU 연결, GPU 메모리 별도

10.3. GPU 아키텍처 특성

  • 처리 자체가 고도 데이터 병렬
  • 고도 멀티스레딩, 스레드 스위칭으로 메모리 지연 숨김
  • 멀티레벨 캐시 의존 낮음, 대신 그래픽 메모리는 폭이 넓고 BW 큼
  • 추세: GPGPU, CPU/GPU 이기종(Sequential은 CPU, Parallel은 GPU)
  • 프로그래밍: DirectX/OpenGL, Cg/HLSL, CUDA

10.4. 예: NVIDIA Tesla(구성)

  • 여러 SIMD 프로세서로 구성

  • 한 SIMD 프로세서

    • 16 SIMD lane
    • SIMD 명령이 32-element wide threads(워프)에서 동작
    • 16-wide 프로세서 위에 2사이클에 걸쳐 동적 스케줄
    • 32K×32-bit 레지스터가 lane에 분산, 스레드 컨텍스트당 64레지스터

10.5. GPU 메모리 구조(개념도)

  • CUDA thread private memory
  • thread block local memory
  • grid 단위 실행과 grid 간 동기화, 글로벌 GPU 메모리

10.6. GPU 분류의 애매함

  • SIMD/MIMD로 깔끔히 안 들어맞음
  • 조건 실행으로 MIMD 환상은 가능하지만 성능 저하 → 일반 목적 코드는 주의해서 작성
  • 표 관점: ILP(정적=VLIW, 동적=Superscalar) × DLP(SIMD/Vector, Tesla MP)

10.7. CPU 멀티코어(SIMD 포함) vs GPU 비교

  • SIMD 프로세서 수: 824 vs 1580
  • lane/processor: 24 vs 816
  • SIMD 스레드용 MT 지원: 24 vs 1632
  • 최대 캐시: 48MB vs 6MB
  • 메인 메모리: 641024GB vs 416GB
  • 캐시 일관성: CPU Yes / GPU No
  • Demand paging: CPU Yes / GPU No → GPU는 캐시/가상메모리 기능보다 스루풋과 BW 중심 설계라는 뉘앙스

10.8. GPU 용어 가이드(표)

  • Vectorizable loop ↔ grid
  • Thread block, CUDA thread, warp 등 대응