CUDA多卡运行设置

1. cuda设置GPU硬件设备

cuda指定运行设备有两种方式,分别是运行时设置和设置上下文

1.1 运行时设置

cudaError_t cudaSetDevice(int device)

参数说明:

  • device:表示要设置为当前设备的设备索引号。

返回值说明:

  • 如果函数调用成功,返回值为cudaSuccess;否则返回相应的错误码。

1.2 设置cuda上下文

CUdevice cuda_device;
CUcontext context;
cuDeviceGet(&cuda_device, device);
cuCtxCreate(&context, CU_CTX_SCHED_BLOCKING_SYNC, cuda_device);
cudaError_t cuDeviceGet (CUdevice* device, int ordinal)

参数说明:

  • device:指向CUdevice类型的指针,用于存储获取到的CUDA设备句柄。
  • ordinal:表示要获取的CUDA设备的索引号,从0开始。

返回值说明:

  • 如果函数调用成功,返回值为CUDA_SUCCESS;否则返回相应的错误码。
CUresult cuCtxCreate (CUcontext *pctx, unsigned int flags, CUdevice dev)

参数说明:

  • pctx:指向CUcontext类型的指针,用于存储创建的CUDA上下文句柄。
  • flags:表示上下文的创建标志,可以是以下值的按位或组合:
    • CU_CTX_SCHED_AUTO:自动选择上下文调度模式。
    • CU_CTX_SCHED_SPIN:上下文在无任务可执行时将自旋等待。
    • CU_CTX_SCHED_YIELD:上下文在无任务可执行时将主动让出CPU。
    • CU_CTX_SCHED_BLOCKING_SYNC:上下文在无任务可执行时将阻塞等待。
  • dev:表示要与上下文关联的CUDA设备句柄。

返回值说明:

  • 如果函数调用成功,返回值为CUDA_SUCCESS;否则返回相应的错误码。

1.3 两种方式的区别

cudaSetDevice和cuCtxCreate是用于设置CUDA设备的两个不同的函数,它们在功能和使用方式上有一些区别。

  1. cudaSetDevice是CUDA Runtime API中的函数,而cuCtxCreate是CUDA Driver API中的函数。这意味着cudaSetDevice是在运行时使用的,而cuCtxCreate是在驱动程序级别使用的。

  2. cudaSetDevice函数用于将当前线程的活动设备设置为指定的设备。它接受一个设备索引号作为参数,该索引号表示要设置为活动设备的CUDA设备的索引。例如,cudaSetDevice(0)将将设备索引号为0的设备设置为活动设备。

  3. cuCtxCreate函数用于创建一个CUDA上下文。CUDA上下文是一个管理CUDA资源(如设备内存、流、事件等)的对象。它接受一个指向CUcontext类型的指针作为参数,该指针将在函数调用成功时被设置为新创建的CUDA上下文的句柄。

  4. cudaSetDevice函数只设置当前线程的活动设备,而cuCtxCreate函数创建一个新的CUDA上下文,并将其设置为当前线程的活动上下文。这意味着cuCtxCreate函数不仅可以设置活动设备,还可以创建一个新的上下文来管理CUDA资源。

总结起来,cudaSetDevice函数用于设置当前线程的活动设备,而cuCtxCreate函数用于创建一个新的CUDA上下文,并将其设置为当前线程的活动上下文。它们在功能和使用方式上有所不同,具体使用哪个函数取决于你的需求和上下文。

那什么时候使用cuda上下文呢?
在使用CUDA进行编程时,管理CUDA上下文是非常重要的。下面是一些需要管理CUDA上下文的情况:

  1. 多线程环境:如果你的应用程序涉及多个线程同时使用CUDA,每个线程都应该有自己的CUDA上下文。这是因为CUDA上下文是线程特定的,不同的线程需要独立的上下文来管理其CUDA资源。

  2. 多设备环境:如果你的系统中有多个CUDA设备,每个设备都有自己的内存和计算资源。在这种情况下,你需要为每个设备创建一个独立的CUDA上下文,以便在不同的设备上执行并管理CUDA操作。

  3. 内存管理:CUDA上下文还负责管理设备内存的分配和释放。你需要在正确的上下文中分配和释放设备内存,以确保内存的正确使用和释放。

  4. 资源管理:CUDA上下文还负责管理其他CUDA资源,如流、事件和纹理等。你需要在正确的上下文中创建、使用和销毁这些资源,以确保它们与正确的设备和上下文关联。

总之,管理CUDA上下文是为了确保正确的设备和上下文关联,以及正确的资源和内存管理。这对于多线程环境、多设备环境和正确的CUDA编程至关重要。

如果我在一个类的构造函数中调用cuCtxCreate创建了cuda上下文,那么在各成员函数中还需要调用cudaSetDevice吗?
如果在一个类的构造函数中调用了cuCtxCreate函数创建了CUDA上下文,并且该上下文成为了当前线程的活动上下文,那么在类的其他成员函数中通常不需要再调用cudaSetDevice函数来设置设备。

当CUDA上下文被创建并成为当前线程的活动上下文时,后续的CUDA函数调用将默认在该上下文中执行。这意味着在类的其他成员函数中,CUDA函数将自动在之前创建的上下文中执行,而无需再次指定设备。

然而,需要注意的是,如果在类的构造函数中创建了多个CUDA上下文,并且在不同的成员函数中需要在不同的上下文中执行CUDA操作,那么在每个成员函数中可能需要调用cudaSetDevice函数来设置正确的设备。

此外,如果在类的构造函数中创建了CUDA上下文,并且在其他成员函数中需要与OpenGL或其他图形库进行互操作,可能需要使用相应的图形库函数来将CUDA上下文与图形库上下文关联起来,以实现正确的互操作性。

总结起来,如果在一个类的构造函数中调用了cuCtxCreate函数创建了CUDA上下文,并且该上下文成为了当前线程的活动上下文,那么在类的其他成员函数中通常不需要再调用cudaSetDevice函数来设置设备。但在特定情况下,可能需要在成员函数中调用cudaSetDevice函数来设置正确的设备或与其他图形库进行互操作。

2. ffmpeg硬编码指定GPU硬件设备

在使用FFmpeg的C API进行硬编码时,你可以通过设置编码器上下文的hw_device_ctx字段来指定使用哪个GPU设备。

首先,你需要使用av_hwdevice_ctx_create函数创建一个硬件设备上下文,并指定设备类型和设备索引。然后,你可以将这个硬件设备上下文设置到编码器上下文的hw_device_ctx字段。
例如:

AVBufferRef* hw_device_ctx = NULL;
int device_id = 0;  // 设备索引号
char device[128] = {
    
    0};

// 创建硬件设备上下文
sprintf(device, "%d", device_id);
int ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, device, NULL, 0);
if (ret < 0) {
    
    
    // 错误处理
}

// 创建编码器上下文
AVCodecContext* enc_ctx = avcodec_alloc_context3(encoder);
if (!enc_ctx) {
    
    
    // 错误处理
}

// 设置硬件设备上下文
enc_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);

// 其他编码器设置和编码操作...

有一个奇怪的现象就是,明明类的构造函数中创建了cuda上下文,结果某些成员函数却不生效,还需要调用cudaSetDevice在设置一次,原因不明。

猜你喜欢

转载自blog.csdn.net/wyw0000/article/details/132868271
今日推荐