我想知道 NVIDIA 的 cuBLAS 库。有没有人有这方面的经验?例如,如果我使用 BLAS 编写 C 程序,我是否能够用对 cuBLAS 的调用替换对 BLAS 的调用?或者更好地实现一种让用户在运行时选择的机制?
如果我将 Boost 提供的 BLAS 库与 C++ 一起使用会怎样?
janneb 的回答是不正确的,cuBLAS不是CPU BLAS 的直接替代品。它假设数据已经在设备上,并且函数签名有一个额外的参数来跟踪 cuBLAS 上下文。
然而,在 CUDA 6.0 中出现了一个名为 NVBLAS 的新库,它提供了这种“插入式”功能。它拦截 Level3 BLAS 调用(GEMM、TRSV 等)并自动将它们发送到 GPU,从而有效地将 PCIE 传输与 GPU 上的计算平铺。
这里有一些信息:https ://developer.nvidia.com/cublasxt,CUDA 6.0 现已可供 CUDA 注册开发人员使用。
一旦 CUDA 6.0 向公众发布,完整的文档将在线发布。
CUBLAS 不环绕 BLAS。CUBLAS 还以列优先顺序访问矩阵,例如一些 Fortran 代码和 BLAS。
我更习惯用 C 编写代码,即使是 CUDA。使用 CBLAS(BLAS 的 C 封装)编写的代码可以很容易地更改为 CUDA 代码。请注意,使用 BLAS 的 Fortran 代码与使用 CBLAS 的 C/C++ 代码完全不同。Fortran 和 BLAS 通常以列优先顺序存储矩阵或双精度数组,但 C/C++ 通常处理行优先顺序。我通常处理这个问题,将矩阵保存在一维数组中,并使用#define 编写一个宏来访问矩阵的元素 i,j,如下所示:
/* define macro to access Aij in the row-wise array A[M*N] */
#define indrow(ii,jj,N) (ii-1)*N+jj-1 /* does not depend on rows M */
/* define macro to access Aij in the col-wise array A[M*N] */
#define indcol(ii,jj,M) (jj-1)*M+ii-1
CBLAS 库有一个很好的组织参数和约定(常量枚举变量),为每个函数提供矩阵的排序。请注意,矩阵的存储也有所不同,逐行带状矩阵的存储方式与逐列带状矩阵不同。
我认为没有机制允许用户在使用 BLAS 或 CUBLAS 之间进行选择,而无需编写两次代码。CUBLAS 在大多数函数调用中也有一个在 BLAS 上没有出现的“句柄”变量。我虽然使用#define 来更改每个函数调用的名称,但这可能行不通。
我一直在将 BLAS 代码移植到 CUBLAS。我使用的 BLAS 库是 ATLAS,所以我所说的可能只对 BLAS 库的选择是正确的。
ATLAS BLAS 要求您指定您使用的是列主序还是行主序,我选择了列主序,因为我使用的是使用列主序的 CLAPACK。另一方面,LAPACKE 将使用行主要排序。CUBLAS 是列主要排序。您可能需要相应地进行调整。
即使订购不是问题,移植到 CUBLAS 也绝不是替代品的下降。最大的问题是您必须将数据移入和移出 GPU 的内存空间。该内存是使用 cudaMalloc() 设置并使用 cudaFree() 释放的,这正如人们所期望的那样。使用 cudaMemcpy() 将数据移动到 GPU 内存中。执行此操作的时间将是决定是否值得从 CPU 迁移到 GPU 的一个重要因素。
但是,一旦完成,调用就非常相似。CblasNoTrans 变为 CUBLAS_OP_N,CblasTrans 变为 CUBLAS_OP_T。如果您的 BLAS 库(如 ATLAS 那样)允许您按值传递标量,则必须将其转换为按引用传递(对于 FORTRAN 来说是正常的)。
鉴于此,任何允许选择 CPU/GPU 的开关都最容易处于比使用 BLAS 的功能更高的级别。就我而言,我有算法的 CPU 和 GPU 变体,并根据问题的大小在更高级别选择它们。