CUDA编程接口详解
本文将详细介绍NVIDIA CUDA编程指南第3章(编程接口)中的核心概念,例如NVCC编译器、CUDA运行时、版本管理和兼容性、计算模式、模式切换以及Windows下的Tesla计算集群模式。以下是本文的大纲:
文章目录
- CUDA编程接口详解
- 1. Compilation with NVCC
- 1.1. NVCC编译器简介
- 1.2. 常用编译选项
- 1.3. 示例:编译一个简单的CUDA程序
- 1.4. 示例:使用Makefile编译CUDA程序
- 2. CUDA Runtime
- 2.1. 设备管理API
- 2.2. 内存管理API
- 2.3. 执行管理API
- 3. Versioning and Compatibility
- 3.1. CUDA版本号
- 3.2. API兼容性
- 3.3. ABI兼容性
- 3.4. 示例:检查CUDA版本
- 4. Compute Modes
- 4.1. 计算模式简介
- 4.2. 示例:设置计算模式
- 4.3. 示例:查询计算模式
- 5. Mode Switches
- 6. Tesla Compute Cluster Mode for Windows
1. Compilation with NVCC
NVCC(NVIDIA CUDA Compiler,NVIDIA CUDA编译器)是用于编译CUDA C/C++代码的编译器。要使用NVCC编译CUDA代码,我们需要将CUDA源文件的扩展名设置为.cu
,并使用以下命令进行编译:
nvcc -o my_program my_program.cu
在本节中,我们将详细介绍NVCC编译器的用法和选项。以下是本节的内容概述:
- NVCC编译器简介
- 常用编译选项
- 示例:编译一个简单的CUDA程序
- 示例:使用Makefile编译CUDA程序
1.1. NVCC编译器简介
NVCC是CUDA平台的核心组件之一,它将CUDA C/C++代码转换为GPU可执行的二进制代码。NVCC的运行过程分为两个阶段:首先,它将CUDA代码中的设备代码(device code)和主机代码(host code)分离;然后,它将设备代码交给PTX编译器(NVIDIA的GPU汇编编译器)进行编译,将主机代码交给C/C++编译器(例如GCC或者Clang)进行编译。
1.2. 常用编译选项
NVCC支持许多编译选项,例如:
-arch=sm_XX
:设置目标架构,例如-arch=sm_35
用于编译支持计算能力3.5的程序;-c
:仅编译,不进行链接;-o
:设置输出文件名;-I
:设置头文件搜索路径;-L
:设置库文件搜索路径;-l
:链接库文件。
1.3. 示例:编译一个简单的CUDA程序
假设我们有一个简单的CUDA程序vector_add.cu
,其内容如下:
#include <iostream>
#include <cuda_runtime.h>
__global__ void vector_add(const float *A, const float *B, float *C, int N) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < N) {
C[i] = A[i] + B[i];
}
}
int main() {
// ...省略主机代码...
}
要使用NVCC编译这个程序,我们可以执行以下命令:
nvcc -o vector_add vector_add.cu
编译成功后,我们可以运行生成的可执行文件vector_add
。
1.4. 示例:使用Makefile编译CUDA程序
在实际项目中,我们通常需要编译多个源文件,并链接多个库文件。为了简化编译过程,我们可以使用Makefile来管理编译选项和依赖关系。以下是一个简单的Makefile示例:
# 设置NVCC编译器和编译选项
NVCC = nvcc
CFLAGS = -arch=sm_35 -I/usr/local/cuda/include
# 设置目标文件和源文件
TARGET = vector_add
SOURCES = vector_add.cu
# 编译规则
all: $(TARGET)
$(TARGET): $(SOURCES)
$(NVCC) $(CFLAGS) -o $@ $^
clean:
rm -f $(TARGET)
使用这个Makefile,我们可以直接运行make
命令来编译CUDA程序。
2. CUDA Runtime
CUDA运行时(CUDA Runtime)是一个用于管理设备、内存和执行的高级API。它包括以下几个部分:
- 设备管理:包括设备查询、设备选择、设备属性获取等功能;
- 内存管理:包括设备内存分配、释放、数据传输等功能;
- 执行管理:包括核函数调用、同步、流管理等功能。
在本节中,我们将详细介绍CUDA运行时API的使用方法和注意事项。以下是本节的内容概述:
- 设备管理API
- 内存管理API
- 执行管理API
2.1. 设备管理API
设备管理API主要用于查询和设置CUDA设备。以下是一些常用的设备管理API:
cudaGetDeviceCount(int *count)
:获取可用CUDA设备的数量;cudaGetDeviceProperties(cudaDeviceProp *prop, int device)
:获取指定设备的属性;cudaSetDevice(int device)
:选择当前线程使用的设备;cudaGetDevice(int *device)
:获取当前线程使用的设备。
2.2. 内存管理API
内存管理API主要用于分配、释放和传输设备内存。以下是一些常用的内存管理API:
cudaMalloc(void **devPtr, size_t size)
:分配设备内存;cudaFree(void *devPtr)
:释放设备内存;cudaMemcpy(void *dst, const void *src, size_t count, cudaMemcpyKind kind)
:传输内存数据。
2.3. 执行管理API
执行管理API主要用于调用核函数、同步和管理流。以下是一些常用的执行管理API:
__global__
:定义核函数;<<<...>>>()
:调用核函数;cudaStreamCreate(cudaStream_t *pStream)
:创建流;cudaStreamDestroy(cudaStream_t stream)
:销毁流;cudaStreamSynchronize(cudaStream_t stream)
:同步流;cudaDeviceSynchronize()
:同步设备。
3. Versioning and Compatibility
CUDA使用版本号表示其API和ABI(Application Binary Interface,应用程序二进制接口)的兼容性。CUDA的版本号由三部分组成:主版本号、次版本号和修订版本号,例如CUDA 10.2.89。
主版本号和次版本号用于表示API的兼容性。如果应用程序使用的CUDA版本与系统安装的CUDA版本在主版本号和次版本号上一致,则应用程序可以正常运行。修订版本号用于表示ABI的兼容性。如果应用程序使用的CUDA版本与系统安装的CUDA版本在修订版本号上一致或更低,则应用程序可以正常运行。
在本节中,我们将详细介绍CUDA版本管理和兼容性的概念和实践。以下是本节的内容概述:
- CUDA版本号
- API兼容性
- ABI兼容性
- 示例:检查CUDA版本
3.1. CUDA版本号
CUDA版本号由三部分组成:
- 主版本号(Major version):表示CUDA平台的主要功能和架构变化;
- 次版本号(Minor version):表示CUDA平台的次要功能和性能改进;
- 修订版本号(Revision version):表示CUDA平台的细节修复和优化。
例如,CUDA 10.2.89表示主版本号为10,次版本号为2,修订版本号为89。
3.2. API兼容性
API兼容性是指一个CUDA程序可以在不同版本的CUDA平台上正常运行。API兼容性主要由主版本号和次版本号决定:
- 如果一个CUDA程序使用的CUDA版本与系统安装的CUDA版本在主版本号和次版本号上一致,则该程序可以正常运行;
- 如果一个CUDA程序使用的CUDA版本的主版本号高于系统安装的CUDA版本的主版本号,则该程序可能无法正常运行;
- 如果一个CUDA程序使用的CUDA版本的主版本号低于系统安装的CUDA版本的主版本号,但次版本号高于或等于系统安装的CUDA版本的次版本号,则该程序可以正常运行;
- 如果一个CUDA程序使用的CUDA版本的主版本号低于系统安装的CUDA版本的主版本号,且次版本号低于系统安装的CUDA版本的次版本号,则该程序可能无法正常运行。
3.3. ABI兼容性
ABI兼容性是指一个CUDA程序的二进制文件可以在不同版本的CUDA平台上正常运行。ABI兼容性主要由修订版本号决定:
- 如果一个CUDA程序使用的CUDA版本与系统安装的CUDA版本在修订版本号上一致或更低,则该程序可以正常运行;
- 如果一个CUDA程序使用的CUDA版本的修订版本号高于系统安装的CUDA版本的修订版本号,则该程序可能无法正常运行。
3.4. 示例:检查CUDA版本
要检查CUDA版本,我们可以使用以下方法:
- 查看CUDA运行时库的版本:
cat /usr/local/cuda/version.txt
; - 查看CUDA编译器的版本:
nvcc --version
; - 查看CUDA驱动的版本:
nvidia-smi
; - 在CUDA程序中获取版本信息:
#include <iostream>
#include <cuda_runtime.h>
int main() {
int runtime_version = 0;
int driver_version = 0;
cudaRuntimeGetVersion(&runtime_version);
cudaDriverGetVersion(&driver_version);
std::cout << "CUDA Runtime Version: " << runtime_version << std::endl;
std::cout << "CUDA Driver Version: " << driver_version << std::endl;
return 0;
}
4. Compute Modes
CUDA支持多种计算模式,用于控制设备的访问权限。计算模式分为以下几种:
- Default(默认):设备可以被多个线程和多个上下文(Context)同时访问;
- Exclusive Process(独占进程):设备只能被一个进程访问,但可以被多个线程和多个上下文同时访问;
- Prohibited(禁止):设备不能被任何线程或上下文访问。
在本节中,我们将详细介绍CUDA计算模式的概念和实践。以下是本节的内容概述:
- 计算模式简介
- 示例:设置计算模式
- 示例:查询计算模式
4.1. 计算模式简介
计算模式是一种用于控制CUDA设备访问权限的机制。通过设置计算模式,我们可以控制设备在多个线程和多个上下文之间的共享行为。以下是计算模式的详细介绍:
- Default(默认):设备可以被多个线程和多个上下文同时访问。这种模式适用于大多数情况,因为它允许多个CUDA程序并行运行;
- Exclusive Process(独占进程):设备只能被一个进程访问,但可以被多个线程和多个上下文同时访问。这种模式适用于需要独占设备资源的高性能计算场景;
- Prohibited(禁止):设备不能被任何线程或上下文访问。这种模式适用于需要禁用CUDA设备的安全或节能场景。
4.2. 示例:设置计算模式
要设置计算模式,我们可以使用以下方法:
- 在CUDA程序中设置计算模式:
#include <iostream>
#include <cuda_runtime.h>
int main() {
int device = 0;
cudaSetDevice(device);
// 设置计算模式为独占进程
cudaError_t err = cudaDeviceSetSharedMemConfig(cudaComputeModeExclusiveProcess);
if (err != cudaSuccess) {
std::cerr << "Failed to set compute mode: " << cudaGetErrorString(err) << std::endl;
return 1;
}
// ...执行其他CUDA操作...
return 0;
}
- 使用
nvidia-smi
命令行工具设置计算模式:
# 设置设备0的计算模式为独占进程
nvidia-smi -i 0 -c EXCLUSIVE_PROCESS
4.3. 示例:查询计算模式
要查询计算模式,我们可以使用以下方法:
- 在CUDA程序中查询计算模式:
#include <iostream>
#include <cuda_runtime.h>
int main() {
int device = 0;
cudaSetDevice(device);
// 获取计算模式
cudaComputeMode compute_mode;
cudaDeviceProp device_prop;
cudaGetDeviceProperties(&device_prop, device);
compute_mode = device_prop.computeMode;
// 打印计算模式
switch (compute_mode) {
case cudaComputeModeDefault:
std::cout << "Compute mode: Default" << std::endl;
break;
case cudaComputeModeExclusiveProcess:
std::cout << "Compute mode: Exclusive Process" << std::endl;
break;
case cudaComputeModeProhibited:
std::cout << "Compute mode: Prohibited" << std::endl;
break;
default:
std::cerr << "Unknown compute mode" << std::endl;
return 1;
}
return 0;
}
- 使用
nvidia-smi
命令行工具查询计算模式:
# 查询设备0的计算模式
nvidia-smi -i 0 --query-gpu=compute_mode --format=csv
5. Mode Switches
CUDA的模式切换功能允许用户在系统运行时切换计算模式。模式切换通过nvidia-smi
命令行工具实现,用户可以根据需要随时切换计算模式。
以下是一个模式切换的示例:
- 查看当前计算模式:
nvidia-smi -i 0 --query-gpu=compute_mode --format=csv
- 将计算模式切换为独占进程:
nvidia-smi -i 0 -c EXCLUSIVE_PROCESS
- 验证计算模式已更改:
nvidia-smi -i 0 --query-gpu=compute_mode --format=csv
需要注意的是,模式切换可能会影响正在运行的CUDA程序。在切换计算模式之前,请确保所有相关程序已关闭。
6. Tesla Compute Cluster Mode for Windows
Tesla计算集群模式(Tesla Compute Cluster Mode,简称TCC模式)是NVIDIA为Windows平台提供的一种高性能计算模式。TCC模式旨在提高Tesla GPU在高性能计算场景中的性能和稳定性,包括以下特性:
- 优化的内存传输性能;
- 支持大内存分页;
- 支持Peer-to-Peer内存传输;
- 更低的内核启动延迟;
- 系统管理中断(SMI)隔离。
要启用TCC模式,用户需要使用NVIDIA控制面板或nvidia-smi
命令行工具。启用TCC模式后,Tesla GPU将作为专用计算设备运行,无法用于图形显示。
需要注意的是,TCC模式仅适用于Windows平台上的Tesla GPU。其他平台和GPU系列不受影响。