CUDA 생태계의 구성요소, 계층 구조, 버전 체계와 호환성 규칙을 체계적으로 설명하고, 혼동되기 쉬운 용어들을 엄밀하게 정의한다.
CUDA의 용어 체계에는 상당한 수준의 중의성과 과적재가 존재한다. “CUDA”라는 단어 자체가 최소 다섯 가지 개념을 가리키고, “driver(드라이버)”는 문맥마다 다른 의미로 쓰이며, 여러 도구가 출력하는 버전 번호는 서로 다른 하위 시스템을 가리킨다. 이 글은 CUDA 구성요소에 대한 엄밀한 온톨로지(ontology)를 제시한다. 즉, CUDA 생태계에 무엇이 존재하는지, 각 구성요소가 서로 어떻게 연결되는지, 어떤 버전 의미론(semantics)과 호환성 규칙, 실패 양상을 가지는지를 체계적으로 설명한다. 각 용어는 모호함이 없도록 정확하게 정의된다. 이 구조를 이해하는 것은 버전 비호환 문제를 진단하고 CUDA 시스템 동작을 논리적으로 이해하는 데 필수적이다.
CUDA라는 단어는 최소 다섯 가지 서로 다른 의미로 과적재(overloaded)되어 있다.
compute_8.0, compute_9.0 등)로 버전이 매겨진다.__global__, __device__ 등).nvcc, 라이브러리, 헤더, 개발 도구들을 포함한 개발용 패키지.libcudart).누군가 “CUDA 버전”이라고 말할 때, 그것이 툴킷 버전, 런타임 버전, Driver API 버전, 혹은 Compute Capability를 뜻하는 것일 수 있다. 정확성을 위해서는 무엇을 의미하는지 명시적으로 구분해야 한다.
kernel은 GPU 컴퓨팅 문맥에서 서로 완전히 다른 두 가지 의미를 가진다.
6.6.87), Windows NT 커널, macOS XNU 커널.__global__로 표시된 C++ 함수로, GPU에서 실행된다. 호스트 코드에서 호출되면 CUDA 커널은 스레드 블록의 그리드로 런치된다.이 글 전체에서 OS kernel은 항상 리눅스, 윈도우와 같은 운영체제 커널을 의미하고, CUDA kernel은 항상 GPU 함수(디바이스에서 실행되는 함수)를 의미한다.
일반적인 컴퓨팅에서 “드라이버”는 운영체제가 하드웨어 장치와 통신할 수 있도록 해 주는 소프트웨어를 뜻한다. CUDA 문맥에서의 driver는 다음과 같이 과적재되어 있다.
NVIDIA GPU 드라이버 (또는 “NVIDIA 디스플레이 드라이버”): GPU 하드웨어를 관리하는 OS 커널 공간 드라이버(리눅스에서는 커널 모듈, 윈도우에서는 커널 드라이버). 역사적인 명칭은 “디스플레이 드라이버”이지만, 이 통합 드라이버는 모든 GPU 작업을 처리한다: 그래픽 렌더링, 연산(컴퓨트) 워크로드, 메모리 관리, 스케줄링. 이름은 NVIDIA GPU가 그래픽 중심에서 범용 연산 가속기로 진화해 온 역사를 반영한다.
nvidia.ko, nvidia-modeset.ko, nvidia-uvm.ko; 윈도우에서는 커널 드라이버.535.104.05, 550.54.15 등.CUDA Driver API: GPU 기능에 직접 접근할 수 있는 저수준 C API(libcuda.so(리눅스), nvcuda.dll(윈도우)). 이는 NVIDIA GPU 드라이버 패키지가 제공하는 유저 공간 라이브러리다.
/usr/lib/x86_64-linux-gnu/libcuda.so.NVIDIA GPU 드라이버 패키지는 OS 커널 구성요소(커널 모듈/드라이버)와 유저 공간 라이브러리(libcuda)를 모두 포함한다.
CUDA 생태계는 여러 계층으로 이루어져 있으며, 각 계층은 상이한 책임을 갖는다. 이 계층 구조를 이해하는 것은 버전 호환성과 시스템 동작을 논리적으로 파악하는 데 기본이 된다.
CUDA 스택은 OS 커널 공간과 유저 공간 전반에 걸쳐 있다.
mermaidgraph TB A["<b>Application</b> (PyTorch, TensorFlow, custom)"] B["<b>libcudart.so</b> (Runtime API, user-space)"] C["<b>libcuda.so</b> (Driver API, user-space)"] D["<b>nvidia.ko</b> (GPU Driver, <sup>OS</sup>kernel-space)"] E["<b>GPU Hardware</b>"] A -->|calls| B B -->|calls| C C -->|ioctl syscalls| D D -->|commands| E style A fill:#1a1a1a,stroke:#86efac,stroke-width:2px,color:#86efac,text-align:left style B fill:#1e2a3a,stroke:#60a5fa,stroke-width:2px,color:#60a5fa,text-align:left style C fill:#1e2a3a,stroke:#60a5fa,stroke-width:2px,color:#60a5fa,text-align:left style D fill:#3a2a1e,stroke:#fbbf24,stroke-width:3px,color:#fbbf24,text-align:left style E fill:#1a1a1a,stroke:#86efac,stroke-width:2px,color:#86efac,text-align:left classDef default font-family:Source Code Pro
libcuda.so / nvcuda.dll (Driver API, 백엔드):
NVIDIA GPU 드라이버 패키지가 제공한다.
시스템 전역에 설치된다.
/usr/lib/x86_64-linux-gnu/libcuda.so (또는 /usr/lib64/libcuda.so)C:\Windows\System32\nvcuda.dll저수준 프리미티브 제공: cuInit, cuMemAlloc, cuLaunchKernel 등.
OS 커널 드라이버와의 통신 방식:
ioctl 시스템 콜(OS 커널 디바이스와의 I/O 제어용 시스템 콜)DeviceIoControl 호출GPU 드라이버 버전으로 버전이 정해진다(예: 드라이버 535.x가 CUDA Driver API 12.2를 제공하는 libcuda.so/nvcuda.dll을 포함).
libcudart.so / cudart64_*.dll (Runtime API, 프런트엔드):
CUDA Toolkit(또는 PyTorch 같은 애플리케이션 패키지)에서 제공한다.
파일 위치 예:
libcudart.so(공유 라이브러리), libcudart_static.a(정적 라이브러리)cudart64_<version>.dll(공유), cudart_static.lib(정적)상위 수준 API 제공: cudaMalloc, cudaMemcpy, cudaLaunchKernel 등.
내부적으로 libcuda.so/nvcuda.dll(Driver API)을 호출해 실제 동작을 수행한다.
정적 링크 또는 동적 링크 모두 가능하다.
애플리케이션 코드는 일반적으로 Driver API가 아니라 Runtime API를 사용한다.
CUDA Toolkit:
다음을 포함하는 개발용 패키지:
nvcc: CUDA 커널 코드를 위한 컴파일러libcudart/cudart64_*.dll: 런타임 라이브러리cuda.h, cuda_runtime.h)cuBLAS, cuDNN, cuFFT 등nvprof, nsight, cuda-gdbGPU 드라이버와는 별도로 버전이 관리된다: 툴킷 12.1, 12.4 등.
CUDA 커널 코드를 컴파일하기 위한 빌드 타임에 필요하다.
런타임 라이브러리(libcudart)는 실행 시 필요하지만, nvcc와 헤더는 필요 없다.
설치 경로 예:
/usr/local/cuda/C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.x\NVIDIA GPU 드라이버:
nvidia.ko, 리눅스) 또는 커널 드라이버(윈도우)와, 유저 공간 라이브러리(libcuda.so(리눅스/macOS), nvcuda.dll(윈도우))를 제공한다.CUDA 스택은 애플리케이션을 향한 계층과 시스템을 향한 계층을 분리한다.
libcudart.so + 애플리케이션 코드. 상위 수준 Runtime API(cudaMalloc, cudaMemcpy 등)를 제공한다. 애플리케이션에 번들되거나 링크된다.libcuda.so + GPU 드라이버(nvidia.ko). 저수준 Driver API와 하드웨어 관리를 제공한다. 시스템 전역에 설치되며, 실행 시 반드시 존재해야 한다.이 분리는 애플리케이션이 일관된 상위 수준 API를 사용할 수 있게 해 주며, 백엔드는 하드웨어 별 세부 사항을 처리한다. libcudart는 Runtime API 호출을 Driver API 호출로 변환하고, libcuda는 이를 OS 커널 드라이버를 통해 실제 하드웨어에 전달한다.
용어 주의: 여기서 “실행 시간(execution-time)”은 애플리케이션이 실제로 실행되는 시점을 뜻한다. 이는 특정 CUDA 라이브러리인 Runtime API(libcudart)와는 별개의 개념이다. 다만 Runtime API 라이브러리는 실행 시간에 필요하다.
| 구성요소 | 빌드 타임(컴파일 시) | 실행 타임(런타임) |
|---|---|---|
nvcc | CUDA 커널 코드를 컴파일하는 데 필요 | 필요 없음 |
CUDA 헤더(cuda.h 등) | 필요 | 필요 없음 |
libcudart(Runtime API) | 애플리케이션 링크에 필요 | 애플리케이션 실행에 필요 |
libcuda(Driver API) | 직접 사용되지는 않음 | 시스템 전역에 필요 |
GPU 드라이버(nvidia.ko) | 필요 없음 | 필요 |
예: PyTorch 컴파일:
12.1을 기준으로 컴파일되었다(빌드 과정에서 툴킷 12.1의 헤더와 라이브러리를 사용하여 링크했다는 뜻).12.1의 nvcc, 헤더, libcudart가 사용된다.libcudart.so를 정적 링크하거나 패키징하여 함께 제공하며, 시스템에 설치된 GPU 드라이버가 제공하는 libcuda.so를 호출한다.>= 12.1)의 CUDA Driver API 버전을 지원하는 GPU 드라이버가 존재해야 한다.CUDA 생태계에는 서로 독립된 여러 버전 체계가 있다. 각각의 버전 번호는 시스템의 서로 다른 측면을 나타낸다. 이들을 혼동하는 것이 혼란의 주요 원인이다.
Compute Capability(CC)는 GPU의 명령어 집합과 하드웨어 기능을 정의한다. 이는 소프트웨어가 아니라 GPU 하드웨어 자체의 속성이다.
X.Y (예: 8.0, 9.0)에서 X는 메이저 버전, Y는 마이너 버전.8.9, H100은 CC 9.0.nvidia-smi 또는 cudaGetDeviceProperties()를 통해 조회할 수 있다.GPU 코드는 두 가지 형식으로 컴파일될 수 있다.
바이너리 호환성 규칙:
SASS(컴파일된 머신 코드)는 매우 엄격한 호환성 제약을 갖는다.
8.0용 SASS는 일반적으로 CC 8.6 하드웨어에서 실행되지 않는다. 둘 다 메이저 버전 8.x이지만 각 CC는 서로 다른 명령어 인코딩을 가질 수 있다.8.0용 SASS는 CC 7.5 하드웨어에서 실행되지 않는다(오래된 하드웨어에는 필요한 명령어가 없다).8.0용 SASS는 CC 9.0 하드웨어에서 실행되지 않는다(메이저 버전이 다르면 ISA도 다르기 때문).PTX(중간 표현)는 전방 호환성을 제공한다.
8.0을 대상으로 컴파일된 PTX는 드라이버가 실행 시점에 CC 8.6, 8.9, 9.0 등의 아키텍처용 SASS로 JIT 컴파일할 수 있다.리눅스 형식: R.M.P (예: 535.104.05, 550.54.15).
윈도우 형식: 디스플레이 드라이버는 다른 버전 형식(예: 31.0.15.3623)을 사용하지만, CUDA 구성요소는 R.M과 유사한 버전 관계를 갖는다.
각 드라이버 버전은 지원 가능한 최대 CUDA Driver API 버전을 갖는다. 예:
535.x는 CUDA Driver API 12.2를 지원550.x는 CUDA Driver API 12.4를 지원중요: 드라이버 버전은 최대 CUDA Driver API 버전을 결정하며, 이 값은 애플리케이션이 사용하는 Runtime API 버전 이상이어야 한다.
nvidia-smi를 통해 드라이버 버전과 지원되는 최대 CUDA Driver API 버전을 조회할 수 있다.
형식: X.Y.Z (예: 12.1.0, 12.4.1).
nvcc 버전, libcudart 버전, 사용 가능한 API 기능들을 결정한다.nvcc --version으로 조회할 수 있다(툴킷이 설치되어 있어야 함).libcudart가 지원하는 API 버전.12.1은 Runtime API 12.1을 가진 libcudart를 제공).libcudart를 번들하거나 링크할 수 있다.cudaRuntimeGetVersion()으로 조회할 수 있다.libcuda.so가 제공하는 API 버전.cudaDriverGetVersion()으로 조회하거나, nvidia-smi에서 “CUDA Version”으로 확인할 수 있다.PyTorch가 CUDA 버전을 보고할 때, 다음을 의미한다.
torch.version.cuda로 조회(예: "12.1").torch.cuda.is_available() 수행 시 드라이버를 검사해 사용 가능 여부를 확인한다.예를 들어, PyTorch가 툴킷 12.1로 컴파일되었더라도, CUDA Driver API 12.4를 지원하는 드라이버가 설치된 시스템에서 실행될 수 있다. Driver API 버전이 툴킷 CUDA 버전 이상(12.4 ≥ 12.1)인 한 문제 없다.
CUDA의 버전 호환성은 특정 규칙을 따른다. 이 규칙을 이해하는 것은 애플리케이션이 다양한 시스템에서 정상적으로 실행되도록 하는 데 매우 중요하다.
용어 노트: 여기서 호환성은 백엔드(드라이버 + GPU 하드웨어)의 관점에서 설명된다. “전방 호환(forward compatible)”은 백엔드가 더 오래된 툴킷 버전으로 빌드된 프런트엔드와 동작할 수 있음을 의미한다(예: 드라이버 12.4 버전이 툴킷 12.1에서 온 libcudart를 지원). “역방향 호환(backward compatible)”은 백엔드가 더 새로운 툴킷 버전으로 빌드된 프런트엔드와도 동작할 수 있음을 의미한다(예: 드라이버 12.1이 툴킷 12.4에서 온 libcudart를 지원). CUDA 드라이버는 전방 호환(낡은 프런트엔드를 지원)되지만 역방향 호환(새로운 프런트엔드를 지원)은 되지 않는다.
CUDA는 특정 차원에서 전방 호환성을 제공한다.
Driver API는 Runtime API에 대해 전방 호환이다:
12.4를 지원하는 드라이버는 Runtime API 12.1, 12.2, 12.3, 12.4로 빌드된 애플리케이션을 실행할 수 있다.PTX는 Compute Capability를 넘나드는 전방 호환성을 제공한다:
8.0을 대상으로 컴파일된 PTX는 드라이버가 JIT 컴파일을 통해 CC 8.6, 8.9, 9.0 등의 하드웨어에서 실행할 수 있다(메이저 버전 경계를 넘어도 가능).CUDA에서는 역방향 호환성이 지원되지 않는다.
Driver API는 더 새로운 Runtime API를 지원할 수 없다:
12.1만 지원하는 드라이버는 Runtime API 12.4를 요구하는 애플리케이션을 실행할 수 없다.SASS는 더 오래된 하드웨어에서 실행될 수 없다:
8.0용으로 컴파일된 SASS는 CC 7.5 하드웨어에서 실행되지 않는다(오래된 GPU에 필요한 명령어가 없다).SASS는 Compute Capability 간에 이식 가능하지 않다:
8.0용으로 컴파일된 SASS는 일반적으로 CC 8.6이나 9.0 하드웨어에서 실행되지 않는다.CUDA 애플리케이션이 성공적으로 실행되려면 서로 독립적인 두 가지 조건이 충족되어야 한다.
조건 1: API 버전 호환성
textDriver API version ≥ Runtime API version
libcuda.so가 제공하는 Driver API 버전(GPU 드라이버에 의해 결정)이, 애플리케이션이 사용하는 Runtime API 버전(libcudart가 제공, 애플리케이션에 번들되거나 링크됨) 이상이어야 한다.
조건 2: GPU 코드 가용성
다음 둘 중 하나 이상이 참이어야 한다.
text바이너리에 GPU의 Compute Capability에 맞는 SASS가 포함되어 있거나 또는 바이너리에 PTX가 포함되어 있고, 드라이버가 해당 GPU 아키텍처에 대한 JIT 컴파일을 지원한다
즉, 애플리케이션 바이너리에는 실행 가능한 GPU 코드가 포함되어 있어야 한다.
대표적인 실패 모드:
cudaErrorInsufficientDriver: 조건 1 위반(Driver API 버전 < Runtime API 버전)cudaErrorNoKernelImageForDevice: 조건 2 위반(GPU용 SASS나 PTX가 없음)각 도구는 서로 다른 버전 번호를 보고한다. 어떤 도구가 무엇을 측정하는지를 이해하는 것은 호환성 문제를 진단하는 데 중요하다.
nvidia-sminvidia-smi(NVIDIA System Management Interface)는 GPU 드라이버를 질의해 드라이버 관련 정보를 보고한다.
보고하는 것:
535.104.05)12.2)nvidia-smi --query-gpu=compute_cap --format=csv로 조회 가능)보고하지 않는 것:
nvcc 컴파일러 버전예시 출력:
textDriver Version: 535.104.05 CUDA Version: 12.2
535.104.05: 시스템에 설치된 GPU 드라이버 버전12.2: 이 드라이버가 지원하는 최대 CUDA Driver API 버전(해당 버전 이하를 요구하는 애플리케이션은 실행 가능)nvcc --version보고하는 것:
12.1.0).nvcc 컴파일러 버전(툴킷과 동일).보고하지 않는 것:
사용 불가능할 수 있는 경우:
libcudart만 번들하는 경우.torch.version.cuda보고하는 것:
"12.1").보고하지 않는 것:
torch.cuda.is_available()의미:
CUDA 사용 가능 여부를 나타내는 불리언 값을 반환한다. 실패 시 버전 불일치 또는 드라이버 누락을 의미한다.
cudaRuntimeGetVersion()과 cudaDriverGetVersion()애플리케이션 코드에서 프로그래밍적으로 질의할 수 있다.
cudaRuntimeGetVersion(): Runtime API 버전(libcudart 기준).cudaDriverGetVersion(): Driver API 버전(libcuda 기준).예:
cint runtimeVersion, driverVersion; cudaRuntimeGetVersion(&runtimeVersion); // 예: 12010 (12.1) cudaDriverGetVersion(&driverVersion); // 예: 12040 (12.4)
CUDA 코드를 컴파일할 때의 흐름은 다음과 같다.
소스 코드(.cu 파일): CUDA 커널 정의(__global__ 함수)와 호스트 코드가 포함된다.
nvcc 컴파일:
g++, 윈도우의 cl.exe)로 컴파일된다.링킹:
libcudart(Runtime API)와 링크한다.Compute Capability 타깃 설정: nvcc는 -arch와 -code 플래그를 사용한다.
-arch=compute_XY: 가상 아키텍처(PTX 기능 레벨)를 설정한다. 컴파일 시 사용 가능한 CUDA 기능을 결정한다.-code=sm_XY: 특정 GPU 아키텍처(CC X.Y)에 대한 SASS(네이티브 머신 코드)를 생성한다.-code=compute_XY: CC X.Y용 PTX를 바이너리에 포함시켜 전방 호환성을 제공한다.-code 타깃을 콤마로 구분해 지정할 수 있다.기본 동작: -code 없이 -arch=compute_XY만 지정하면, nvcc는 암묵적으로 해당 아키텍처에 대한 sm_XY SASS와 compute_XY PTX를 모두 생성한다.
모범 사례: 항상 -arch(가상 아키텍처)와 -code(실제 아키텍처)를 모두 명시하라. -code만 사용해도 nvcc가 PTX 레벨을 추론하지만, 그 동작이 의도와 다를 수 있다.
예:
bashnvcc -arch=compute_80 -code=sm_80,sm_86,sm_89,compute_80 kernel.cu -o app
이 명령은 네 가지 출력을 생성한다.
8.0(A100), 8.6(RTX 3090/3080), 8.9(RTX 4090/4080)용 SASS8.0 PTX실행 시 동작은 다음과 같다.
애플리케이션이 실행될 때의 흐름은 다음과 같다.
cudaMalloc, cudaMemcpy, cudaLaunchKernel 등)를 호출한다.libcudart가 이를 Driver API 호출(cuMemAlloc, cuMemcpyHtoD, cuLaunchKernel)로 변환한다.libcuda.so가 ioctl 시스템 콜을 통해 OS 커널 드라이버와 통신한다.실제로 전송되는 것: CUDA 커널 코드가 “런치”될 때, 호스트는 C++ 소스 코드를 GPU로 전송하지 않는다. 대신 다음과 같이 동작한다.
미리 컴파일된 GPU 머신 코드(SASS) 또는 PTX가 애플리케이션 바이너리에 포함되어 있다(nvcc가 컴파일 타임에 생성함).
애플리케이션 시작 시, 드라이버는 적절한 코드를 GPU 메모리에 로드한다.
CUDA 커널을 런치할 때, 호스트는 다음을 지정한다.
GPU 하드웨어 스케줄러가 스레드 블록 전반에 걸쳐 SASS 코드를 실행한다.
이 실행 모델은 네트워크 기반의 RPC(Remote Procedure Call)는 아니지만, 개념적으로 유사한 점이 있다.
cudaDeviceSynchronize() 등을 통해 동기화하거나 계속 진행할 수 있다.프로그래밍 모델은 별도의 프로세서(GPU)에 자신만의 메모리 공간과 명령어 집합을 가진 코드를 원격 실행시키는 형태라는 점에서, 넓은 의미의 “원격 실행”과 닮아 있다.
설정:
12.1만 지원.12.4로 빌드됨.결과:
12.4를 가진 libcudart를 호출한다.libcudart는 Driver API 버전 12.1을 가진 libcuda.so(GPU 드라이버가 제공)를 호출한다.libcuda.so는 Runtime API 12.4가 요구하는 더 새로운 Driver API 기능들을 지원하지 못한다.cudaErrorInsufficientDriver를 반환한다.해결 방법: 필요한 CUDA Driver API 버전(여기서는 ≥ 12.4)을 지원하는 GPU 드라이버로 업그레이드한다.
설정:
8.0(예: A100)용으로만 컴파일됨.7.5 하드웨어(예: RTX 2080 Ti)에서 실행.결과:
8.0용 CUDA 커널 코드를 로드하려 한다.8.0 명령어를 지원하지 않는다.cudaErrorNoKernelImageForDevice 또는 이와 유사한 에러.해결 방법:
7.5(-arch=compute_75)용으로 코드를 재컴파일한다.-arch=compute_75만 지정하고 sm_ 코드는 생략하는 방식 등).설정:
-code=sm_80(CC 8.0 SASS만, PTX 없음)으로 컴파일된 코드.9.0(예: H100)과 같은 더 새로운 GPU에서 실행.결과:
8.0용 SASS만 존재한다.8.0용 SASS는 메이저 버전이 다른 CC 9.0과 호환되지 않는다(ISA가 다름).cudaErrorNoKernelImageForDevice – 바이너리에 호환 가능한 CUDA 커널 이미지가 없음.해결 방법:
-arch=compute_80 -code=sm_80,compute_80.-code의 compute_80 옵션이 PTX를 바이너리에 포함시킨다.9.0 하드웨어에서 실행 시, 드라이버는 이 PTX를 CC 9.0용 SASS로 JIT 컴파일해 사용한다.설정:
12.1을 기준으로 컴파일됨.12.4를 지원.결과:
12.1의 libcudart를 번들하거나 링크한다.12.4의 libcuda.so를 제공한다.12.4 ≥ 12.1: 성공. 문제 없음.반대 설정:
12.4를 기준으로 컴파일됨.12.1만 지원.결과:
12.4 기능을 요구한다.12.1을 가진 libcuda.so는 이를 지원하지 못한다.cudaErrorInsufficientDriver 또는 런타임 에러.해결 방법: 필요한 CUDA Driver API 버전(≥ 12.4)을 지원하는 GPU 드라이버로 업그레이드한다.
설정:
12.1이 /usr/local/cuda-12.1에 설치됨.12.4가 /usr/local/cuda-12.4에 설치됨.PATH가 /usr/local/cuda-12.1/bin을 가리킴.12.4로 컴파일됨.결과:
nvcc --version은 12.1을 보고한다(PATH 상의 nvcc).12.4의 libcudart를 사용한다.nvcc가 보고하는 버전은 실제 애플리케이션이 사용하는 런타임 버전과 일치하지 않을 수 있다.주의: nvcc --version은 PATH에 잡힌 툴킷 버전을 보고할 뿐, 애플리케이션이 링크한 툴킷 버전을 나타내지 않는다. 애플리케이션은 다른 버전의 툴킷에 링크되었거나 자체적으로 라이브러리를 번들할 수 있다.
해결 방법: ldd ./app 등으로 애플리케이션이 실제로 링크하고 있는 라이브러리(특히 libcudart)를 확인해 버전을 추론한다.
설정:
nvidia/cuda:12.1-runtime 기반 컨테이너 이미지.nvcc를 필요로 함.결과:
libcudart 등 실행에 필요한 라이브러리는 있지만, nvcc나 헤더는 없다.nvcc를 찾을 수 없음.해결 방법:
nvidia/cuda:12.1-devel 이미지를 사용한다.주의: 런타임 vs 개발(devel) 이미지
-runtime) 이미지: CUDA 애플리케이션 실행에 필요한 libcudart와 라이브러리들을 포함한다. nvcc나 헤더는 포함되지 않는다.-devel) 이미지: 전체 CUDA Toolkit(nvcc, 헤더, 라이브러리)을 포함하며, CUDA 코드를 컴파일해야 할 때 필요하다.libcudart 정적 링크 vs 동적 링크설정:
12.1의 libcudart_static.a를 정적으로 링크한다.12.4를 지원.결과:
libcudart 코드(버전 12.1)가 내장되어 있다.libcudart는 Driver API 버전 12.4의 libcuda.so를 호출한다.12.4 ≥ 12.1: 성공.반대로:
12.4의 libcudart_static.a를 정적으로 링크한다.12.1만 지원.결과:
libcudart(버전 12.4)가 Driver API 버전 12.1의 libcuda.so를 호출한다.12.1 < 12.4: 실패.주의: 정적 링크는 libcudart를 애플리케이션 바이너리에 함께 묶는다. 이 경우 사용되는 버전은 빌드 타임에 결정되며, 실행 환경에 따라 바뀌지 않는다. 동적 링크는 라이브러리 검색 경로(리눅스의 LD_LIBRARY_PATH, 윈도우의 PATH)나 시스템 라이브러리에 따라 실행 시 버전을 선택할 수 있다.
| 구성요소 | 제공 주체 | 위치 (리눅스 / 윈도우) | 목적 | 버전 기준 |
|---|---|---|---|---|
| OS 커널 드라이버 | NVIDIA GPU 드라이버 | OS 커널 공간: nvidia.ko / nvlddmkm.sys | GPU 하드웨어 관리 | 드라이버 |
| Driver API 라이브러리 | NVIDIA GPU 드라이버 | /usr/lib/libcuda.so / System32\\nvcuda.dll | 저수준 Driver API | 드라이버 |
| Runtime 라이브러리 | CUDA Toolkit | /usr/local/cuda/lib64 / CUDA\\v12.x\\bin | 상위 수준 Runtime API | 툴킷 |
nvcc | CUDA Toolkit | /usr/local/cuda/bin / CUDA\\v12.x\\bin | CUDA 커널 컴파일 | 툴킷 |
| 헤더 | CUDA Toolkit | /usr/local/cuda/include / CUDA\\v12.x\\include | 빌드 타임 API 정의 | 툴킷 |
| 수학 라이브러리 | CUDA Toolkit | /usr/local/cuda/lib64 / CUDA\\v12.x\\lib | 최적화된 GPU 연산 | 툴킷 |
libcudart를 정적으로 링크한다면, 그 버전이 실행 환경 드라이버와 호환되는지 확인하라. 동적 링크 시에는 요구되는 libcudart 버전을 문서화하라.-arch와 -code 플래그를 사용하라. PTX를 포함해 전방 호환성을 확보하라.cudaDriverGetVersion()과 cudaRuntimeGetVersion()을 사용해 호환성을 검증하라.nvcc 포함)을 요구하지 않는다. 실행에는 libcudart와 GPU 드라이버만 있으면 된다.nvidia-smi를 실행해 GPU 드라이버 버전과 지원 CUDA Driver API 버전을 확인하라.torch.version.cuda): PyTorch가 컴파일될 때 사용된 CUDA Toolkit 버전이다. 시스템에 설치된 툴킷 버전과 일치할 필요는 없다.12.1로 빌드된 경우: 시스템 GPU 드라이버는 CUDA Driver API ≥ 12.1을 지원해야 한다.12.4를 지원하는 경우: PyTorch는 툴킷 12.1, 12.2, 12.3, 12.4 중 어느 버전으로 빌드되었든 실행 가능하다.주의: TensorFlow도 동일한 호환성 모델을 따른다. 릴리스 노트에서 빌드에 사용된 툴킷 버전을 확인하라.
-runtime): libcudart와 실행에 필요한 라이브러리를 포함한다. 미리 컴파일된 CUDA 애플리케이션 실행에 적합하며, nvcc는 포함하지 않는다.-devel): 전체 CUDA Toolkit(nvcc, 헤더, 라이브러리)을 포함한다. 컨테이너 내부에서 CUDA 코드를 컴파일해야 할 때 필요하다.CUDA 아키텍처는 빌드 타임과 실행 타임에 서로 다른 역할을 수행하는 명확히 분리된 구성요소들로 이루어진 계층적 시스템이다. 이를 엄밀하게 이해하려면 다음을 구분해야 한다.
용어 구분: “CUDA”는 아키텍처, ISA, 언어, 툴킷, 런타임을 가리킬 수 있다. “드라이버”는 OS 커널 공간 드라이버(nvidia.ko) 또는 유저 공간 Driver API 라이브러리(libcuda.so)를 뜻할 수 있다. “커널”은 운영체제 커널(OS kernel) 또는 GPU 함수(CUDA kernel)를 의미할 수 있다.
계층 구조: libcudart(프런트엔드, Runtime API, 애플리케이션 지향)는 libcuda(백엔드, Driver API, 시스템 지향)를 호출하고, 이는 다시 OS 커널 드라이버(nvidia.ko)를 호출하며, 최종적으로 GPU 하드웨어를 제어한다.
버전 관계: Driver API 버전은 Runtime API 버전 이상이어야 한다. GPU는 자신의 Compute Capability에 해당하는 SASS를 갖고 있거나, 드라이버가 JIT 컴파일할 수 있는 PTX가 바이너리에 포함되어 있어야 한다.
빌드 vs 실행: 빌드 타임에는 툴킷(nvcc 포함)이 필요하다. 실행에는 애플리케이션이 번들하거나 링크한 libcudart와 시스템 GPU 드라이버만 있으면 된다.
버전 불일치는 특정한 실패 모드로 드러난다. 예를 들어 드라이버 부족(cudaErrorInsufficientDriver), CUDA 커널 이미지 누락(cudaErrorNoKernelImageForDevice), 지원되지 않는 API 호출 등이 있다. 이 체계적인 이해를 바탕으로 왜 nvidia-smi, nvcc --version, torch.version.cuda가 서로 다른 숫자를 보고하는지, 각각의 숫자가 무엇을 의미하는지, 그리고 버전 비호환 문제를 어떻게 진단해야 하는지를 명확히 설명할 수 있다.