[다시경량화] cudaGetDeviceProperties

ehghkwl·2026년 1월 20일

Lightweight Challenge

목록 보기
22/22

오늘은 기본적으로 환경설정 하면서, 간단하게 gpu 하드웨어 속성을 확인한다.

#include <iostream>
#include "cuda_runtime.h"

int main()
{
    int count;
    cudaError_t err = cudaGetDeviceCount(&count);
    if (cudaSuccess != err)
    {
        std::printf("cudaGetDeviceCount failed : %s\n", cudaGetErrorString(err));
        return 1;
    }
    std::printf("Device count: %d\n", count);

    for (int i = 0; i < count; i++)
    {
        cudaDeviceProp prop{};
        cudaGetDeviceProperties(&prop, i);

        std::printf("---- Device %d ----\n", i);
        std::printf("Name: %s\n", prop.name);
        std::printf("Compute capability: %d.%d\n", prop.major, prop.minor);
        std::printf("Global memory: %.2f GB\n", prop.totalGlobalMem / (1024.0 * 1024.0 * 1024.0));
        std::printf("SM count: %d\n", prop.multiProcessorCount);
        std::printf("Max threads per block: %d\n", prop.maxThreadsPerBlock);
        std::printf("Max threads per SM: %d\n", prop.maxThreadsPerMultiProcessor);
    }
    return 0;
}

Device count: 1
---- Device 0 ----
Name: NVIDIA GeForce RTX 3060
Compute capability: 8.6
Global memory: 12.00 GB
SM count: 28
Max threads per block: 1024
Max threads per SM: 1536

❓: cudaGetDeviceCount와 cudaGetDeviceProperties

cudaGetDeviceCount: PC에 붙어있는 nvidia gpu 개수
cudaGetDeviceProperties: 각 gpu의 스펙

❓: cudaDeviceProp 가 무슨 자료형인거지?

gpu 속성(이름, 메모리, SM개수, 블록당 스레드 제한 등)을 담는 구조체임. 그냥,, 팩트라서 받아들이면됨ㅋㅋ

❓: cudaDeviceProp prop{}; cudaDeviceProp prop; 차이가 뭐지?

아, 초기화 차이였음... {}를 하면, 값이 전부 0/NULL로 초기화됨..이걸 깜빡하다니,,ㄷㄷ 반성하장.....

❓: prop.major, prop.minor 가 뭐지?

gpu 아키텍처 버전을 의미함.

❓: prop.totalGlobalMem 가 뭐지? 단위는 바이트인가?

gpu 전체 VRAM 용량이지만, 실제로는 드라이버/컨텍스트/런타임이 조금씩 떼어가서 12GB전체를 사용하진 못해.
VRAM은 Video Random Access Memory의 약자로, gpu에서 사용하는 메모리라고 생각하면 된다. cpu에서 사용하는 memory(RAM)과는 독립적인 다른 영역이다.

❓: prop.multiProcessorCount 가 뭐지?

-> 뒤에서 좀더 자세히 설명함.
SM의 개수를 의미하는데, SM은 Streaming Multiprocessor 로, gpu안에 있는 연산 블록 수라고 보면됨. gpu에서는 연산이 각 SM단위로 수행되게 되는데, SM이 많을 수록 병렬 처리가 많아진다고 보면됨.
정확히 말하면, block하나가 하나의 SM에 배정돼서 실행되고, 여러 SM에 여러 데이터가 동시에 처리되어서, SM이 많을 수록 병렬 처리 능력이 좋아지는 경향이 있음. 그냥 단편적으로 생각하면, 16개의 block이 있을때, 수용 가능한 SM이 2개가있으면 8번 반복하고, 4개가 있으면 4번 반복하면 되기 때문에 시간은 절반으로 줄어듬.

❓: prop.maxThreadsPerBlock 는 왜 1024??

maxThreadsPerBlock = Block 최대 스레드
: 병렬처리 가능한 집합의 크기 제한
maxThreadsPerMultiProcessor은 = SM 최대 스레드
: 여러 block을 동시에 올려서 메모리 지연을 숨기고 처리량을 뽑는 실행 단위로, 한 SM에서 동시에 상주 가능한 thread의 최대치(occupancy 상한)
thread수가 최대 1024라면, 블럭이 2d일때 32 x 32를 초과할 수 없다는것이다. (이때 block은 행,열 크기가 달라도 상관없다)

❓: SM, Core, Kernel, Grid, Block, thread, Wrap 이게 무슨 의미고 어떤 관계인거지?

  • Kernel: gpu에서 실행할 코드
  • Grid: 커널을 실행할 때 생성되는 Block들의 전체 집합
  • Block: 함께 묶여 실행되는 thread들의 그룹. 하나의 Block은 하나의 SM에만 올라가며, 실행 도중 다른 SM으로 이동하거나, Block이 나뉘어서 다른 SM에 올라가지 않는다.)
  • thread: 커널의 "논리적 실행 인스턴스"로 각각 threadIdx, blockIdx를 갖는다.
  • Warp: 하드웨어가 스케줄링하는 최소 단위로, 32 threads 묶음이다.
  • SM:Streaming Multiprocessor로, block들이 올라가서 실행되는 "실행 리소스 묶음"이다. 이 묶음에는 스케줄러, 레지스터, shared memory, 실행 파이프 들이 포함된다.
  • Core: SM 내부에 있는 연산 파이프로, core-thread 1:1매칭이 아니고, warp가 발행한 명령을 처리하는 실행 유닛에 가깝다.
  • 커널 실행 시퀀스
  1. CPU가 kernel 호출
  2. GPU는 grid안의 block들을 작업 큐에 넣음
  3. 각 SM은 각자의 리소스(레지스터/shared mem/warp slot 등)가 허용하는 만큼의 block을 꺼내서 SM에 올림
  4. SM 내부에서 block은 warp단위로 쪼개짐
  5. SM의 warp scheduler가 준비된 warp들 중 하나를 골라서 1사이클마다 명령을 발행함. 스케줄러는 메모리로드를 기다리지 않고, 바로 실행가능한 wrap을 실행하는 구조임 (latency hiding)

❓: Block크기를 1로 하면 제일 유연하게 병렬처리할 수 있는거 아닌가?

warp는 32-lane SIMD처럼 동작하므로, block이 1 thread면 한 warp가 생성되더라도 31 lane이 비활성화되어 연산/메모리 처리량이 크게 낭비된다. 그래서 보통 blockDim은 최소 32의 배수로 잡는다.
block 크기는 보통 128/256/512부터 시작한다. 이유는 warp 단위(32)의 배수라 낭비가 적고, occupancy(활성 warp 수) 확보에 유리하고, 메모리 coalescing에도 유리한 패턴이 많기 때문이다.

❓: SM에서 내부적으로는 어떤식으로 처리되는거지?

SM 내부에서는 warp단위로 스케줄링되면, 매 사이클(gpu 클럭이라 생각하면 됨)마다 실행가능한 warp에 명령을 발행한다. warp scheduler는 여러개 존재해서, 그 스케줄러가 병렬처리 되는 것이다. 여튼, 스케줄러를 통해 계속 switching되어 gpu가 쉴새없이 동작하도록 스케줄링되어 있고, 1536개의 thread를 한번에 처리하는 것이 아니라, 엄청나게 빠른 교대 실행인 것이다!

profile
안녕하세요.

0개의 댓글