CUDA C编程(二十八)CUDA 6.0中函数库的介绍

Drop-In 库
  Drop-In库可以使某些GPU加速库无缝地替换已有的CPU库。只要GPU加速库与原主机库使用相同的API,就可以直接把一个应用程序链接到一个Drop-In库中。Drop-In库的设计目的是提高传统应用程序的可移植性。事实上,有了Drop-In库,甚至不需要重新编译应用程序代码。
  在已有的应用程序中,目前只支持两个CUDA库。NVBLAS是cuBLAS库的一个子函数库,它可以替换任意的三层BLAS函数。cyFFTW可以替换FFTW库的调用。有两种方法可以强制应用程序用一个Drop-In库来替换BLAS或FFTW。第一种是可以重新编译应用程序以链接到CUDA库而不是标准库。举例来说,如果有一个使用BLAS库的应用程序,该应用程序是由源文件app.c创建的,通常使用以下编译命令:$ gcc app.c -lblas -o app,如果我们想用与cuBLAS等价的函数库来替换应用程序中所有的BLAS 3调用,那么需要重建应用程序来使用cuBLAS库,如下所示:$ gcc app.c -lnvblas -o app
  第二种是强制在主机库之前加载CUDA库,这种方法是在Linux环境下使用CUDA Drop-In的。它可以通过使用LD_PRELOAD环境变量来实现,它引导操作系统在检查默认设置之前查找指定库的函数定义。这是在我们运行完应用程序的命令之后,接着使用envshell实现的。例如,如果前面示例中的应用程序没有使用命令行参数,而且我们也不想重新编译此程序,那么就可以使用等价的CUDA命令替换BLAS 3例程来执行此程序,命令行如下所示:$ env LD_PRELOAD=libnvblas.so ./app
  接下来的核心代码段主要使用了sgemm BLAS例程并且完全用C语言进行编写:

  srand(9384);
  generate_random_dense_matrix(M, N, &A);
  generate_random_dense_matrix(N, M, &B);
  generate_random_dense_matrix(M, N, &C);

  sgemm_("N", "N", &M, &M, &N, &alpha, A, &M, B, &N, &beta, C, &M);

  通过以下编译指令可以再主机上运行drop-in.c,前提是已经安装了C BALS库并设置好了库路径。$ gcc drop-in.c -lblas -lm -o drop-in,如果要在GPU上运行sgemn调用,只需使用如下命令重新进行编译:$ env LD_PRELOAD=libnvlas -o drop-in,或使用如下编译:$ env LD_PRELOAD=libnvlas.so ./drop-in。Drop-In库帮助解决了函数移植的障碍,利用高性能的CUDA库进一步提高了工作效率。通过简单地重新连接或添加一个环境变量,我们可以用大规模并行GPU加速来有效的加强现有应用程序的执行。

多 GPU 库
  多GPU库(也被称为XT库接口)是在CUDA 6.0中被引入的。它们能使单一的函数库调用在多个GPU上自动地执行。由于在多个GPU上执行需要在设备上划分任务,与GPU全局内存相比,一个多GPU库可以对更大规模的数据集进行操作。因此,即使我们的系统只有一个GPU,也可以通过交换GPU内外的数据分区,来对超出可用全局内存大小的输入数据进行操作。
  在CUDA 6.0中,cuFFT中的一些函数和所有的Level 3 cuBLAS函数都支持多GPU上的程序执行。在性能优化上,cuBLAS Level 3多GPU库调用利用内核计算自动覆盖了内存传输。
  使用多GPU库需要进行一些额外的工作。接下来要学习下面cufft-multi.cu中的代码段,cufft-multi.cu运行的例子与cufft.cu相同,但是用cuFFTXT API把所有任务分派给了系统中的所有GPU。

    nGPUs = nGPUs > 2 ? 2 : nGPUs;
    workSize = (size_t *)malloc(sizeof(size_t) * nGPUs);

    // Setup the cuFFT Multi-GPU plan
    cufftCreate(&plan);
    // cufftPlan1d(&plan, N, CUFFT_C2C, 1);
    cufftXtSetGPUs(plan, 2, gpus);
    cufftMakePlan1d(plan, N, CUFFT_C2C, 1, workSize);

    // Generate inputs
    generate_fake_samples(N, &samples);
    real_to_complex(samples, &complexSamples, N);
    cufftComplex *complexFreq = (cufftComplex *)malloc(sizeof(cufftComplex) * N);

    // Allocate memory across multiple GPUs and transfer the inputs into it
    cufftXtMalloc(plan, &dComplexSamples, CUFFT_XT_FORMAT_INPLACE);
    cufftXtMemcpy(plan, dComplexSamples, complexSamples,CUFFT_COPY_HOST_TO_DEVICE);

    // Execute a complex-to-complex 1D FFT across multiple GPUs
    cufftXtExecDescriptorC2C(plan, dComplexSamples, dComplexSamples,CUFFT_FORWARD);

    // Retrieve the results from multiple GPUs into host memory
    cufftXtMemcpy(plan, complexSamples, dComplexSamples,CUFFT_COPY_DEVICE_TO_HOST);

  cufft.cu与cufft-multi.cu之间的主要区别是:
  1.需要列出当前系统中所有的GPU(使用getAllGpus函数),并配置cuFFT plan来使用这些GPU(cufftXtSetGPU);
  2.使用cufftXtMalloc而不是cudaMalloc在多个GPU上分配设备内存,并将其与相同的CUFFT plan进行关联。需要注意的是,分配信息结果存储在cudaLibXtDesc对象中而没有将其传给一个指针;
  3.使用cufftXtMemcpy而不是cudaMemcpy实现主机内存与多个GPU之间的数据传输。注意,cufftXtMemcpy支持主机端数组和cudaLibXtDesc对象之间的数据拷贝,类似,需要指定数据传输方向,如CUFFT_COPY_HOST_TO_DEVICE、CUFFT_COPY_DEVICE_TO_HOST、CUFFT_COPY_DEVICE_TO_DEVICE。使用cuFFTXTT的多GPU执行的任何设备位置必须表示为cudaLibXtDesc对象。
  4.使用cufftExecDescriptor* 库调用而不是cufftExec*来执行实际的FFT变换,使用如下命令进行编译:$ nvcc -lcufft cufft-multi.cu -o cufft-multi。cuFFTXT库使用FFT函数之前的知识来分配GPU之间的数据,这样做没有破坏FFT结果的有效性(并且在多GPU上对cuBLAS有类似的操作)。在程序移植过程中,添加多GPU支持需要特别注意。如果我们的应用程序有很好的并行性,那么使用多GPU CUDA XT接口比自定义多GPU实现更简单。cuBLAS和cuFFT库的XT接口是CUDA库的一个强大的附加功能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值