Home CUDA Architecture
Post
Cancel

CUDA Architecture

CUDA hardware의 구조(Tesla GP100 예시)

  • 1GPU에 6GPC(graphics processing cluster)
  • 1GPC에 10Pascal SM -> 1GPU에 60SM
  • 1SM(unit) = 32SP + 16DP + 8SFU + 2Tex
    • SP(streaming processor) : FP32 core, 메인 CUDA core, ALU for a single CUDA thread
    • DP(double precision) : FP64 core
    • SFU(sepcial function unit) : sin, cos, square root 등 특별한 연산 1클락에 해결 가능
    • Tex(texture processor) : for graphics purpose, CUDA로 사용시 사용하지 않기도 하고 메모리로 쓰기도 함


CUDA 의 확장성

  • CUDA dedvice는 1~4개의 SM의 저가 모바일 기기부터 1000+의 고가 워크스테이션까지 매우 다양
  • thread block 개념을 도입하여 해결(SM 1개가 thread block 1개 처리)
  • so, grid - block - thread의 계층 구조 필요
  • thread block 들이 SM에 자유롭게 assign 되어서 처리되는 구조
  • Each block can execute in any order relative to other blocks


SM에서 CU(control Unit, SM당 1개)의 실행 구조

  • 1개의 CU의 제어를 받아 32 core(SP) 가 물리적으로 동시에 실행
  • 1개의 warp scheduler
  • 32 thread가 같은 instruction을 동시 실행
  • SM 1개는 2048+ thread를 동시 관리 -> memory의 느린 반응 속도 해결


Thread와 Warp

  • Thread는 독립적 실행 단위(실)
  • Warp 평행하게 관리되는 여러개의 실(Warp를 만드는 것처럼 여러 실을 평행하게 관리)
  • CUDA에서의 Warp는 32개의 thread(SM이 32개의 SP를 가지므로)
  • lane: Warp 내에서의 thread의 index(0~31)
  • block 에는 1024개의 thread가 있지만, 32개씩 끊어서 warp로 관리
  • 20개 이상의 warp가 대기 상태로 있는 것이 효율적
    • memory access 시간을 고려
    • warp 전환간 거의 zero-overhead. 충분히 많은 register를 확보하고 있기 때문
    • warp scheduler는 HW로 구현되어 오버헤드 거의 없음


2레벨 병렬 처리

  • grid는 thread blocks로 이루어져 있으므로 SM에 병렬 처리
  • thread block은 여러 warp로 갈라져서 병렬 처리
  • warp / block 종료 시 다음 warp / block을 처리
  • 자원 제약에 대한 고려가 필요하지만, thread수를 1024정도로 잡으면 문제없음
  • block의 실행 순서가 정해져 있지 않음


warp id, lane id

  • GPU assembly instruction으로 체크 가능
  • warp id : SM 내에서, 특정 warp의 ID number
    1
    2
    3
    4
    5
    6
    
      __device__ unsigned warp_id(void) {
          // this is not equal to threadIdx.x / 32
          unsigned ret;
          asm volatile ("mov.u32 %0, %warpid;" : "=r"(ret));
          return ret;
      }
    
  • lane id : warp 내에서, 자신의 lane id
    1
    2
    3
    4
    5
    
      __device__ unsigned lane_id(void) {
          unsigned ret;
          asm volatile ("mov.u32 %0, %laneid;" : "=r"(ret));
          return ret;
      }
    


This post is licensed under CC BY 4.0 by the author.