【问题标题】:Returning a pointer to a device allocated matrix from C to Fortran将指向设备分配矩阵的指针从 C 返回到 Fortran
【发布时间】:2014-03-13 21:00:36
【问题描述】:

首先,我是 Fortran/C/CUDA 的新手。其次,我正在开发一个 Fortran/C 程序,该程序使用 cuBLAS 在 GPU 上执行矩阵向量乘法。在需要更新矩阵内容之前,我需要将多个(最多 1000 个)向量与一个矩阵相乘。但是,当前版本每次将新向量发送到 GPU 时,我都必须重新分配矩阵(由于矩阵没有改变,这非常浪费和缓慢)。

我希望能够将矩阵与向量相乘,而不必为每个向量重新分配矩阵。我的一个想法是调用一个单独的 C 函数,它将矩阵分配给 GPU,返回一个指向 Fortran 主程序的指针,然后调用另一个执行矩阵向量乘法的 C 函数。

使用 ISO_C_BINDING,我将一个指向浮点数的指针返回到变量中:

type(C_PTR) :: ptr

当我尝试将其传递给矩阵向量 C 函数时:

在 Fortran 中

call cudaFunction(ptr,vector, N)

在 C 中

extern "C" void cudaFunction_(float *mat, float *vector, int *N)

一切都编译并运行,但 cublasSgemv 执行失败。关于为什么会发生这种情况的任何想法?我看过一些相关的帖子,但他们从未尝试将返回的指针发送回 C,这就是(我相信)我遇到问题的地方。

提前致谢!

【问题讨论】:

    标签: c cuda fortran intel-fortran


    【解决方案1】:

    我建议您不要重新发明轮子,而是使用为此目的提供的cublas fortran bindings

    “thunking”包装不是您想要的。每当您在 fortran 中使用 cublas 调用时,它都会根据需要执行隐式复制操作。

    您需要“非重复”包装器,因此您可以明确控制正在进行的复制。您可以使用 Get/SetMatrixGet/SetVector 的 fortran 等效项来来回复制数据。

    有一个示例代码(示例 B.2)显示了如何使用 cublas 文档中包含的非 thunking 包装器。

    即使您确实想重新发明轮子,包装器也会向您展示如何使必要的语法在 C 和 Fortran 之间移动。

    在标准的 linux CUDA 安装中,包装器位于 /usr/local/cuda/src 非thunking 包装器是/usr/local/cuda/src/fortran.c

    这是一个完整的例子:

    cublasf.f:

          program cublas_fortran_example
          implicit none
          integer i, j
    
    c     helper functions
          integer cublas_init
          integer cublas_shutdown
          integer cublas_alloc
          integer cublas_free
          integer cublas_set_vector
          integer cublas_get_vector
    c     selected blas functions
          double precision cublas_ddot
          external cublas_daxpy
          external cublas_dscal
          external cublas_dcopy
          double precision cublas_dnrm2
    c     cublas variables
          integer cublas_status
          real*8 x(30), y(30)
          double precision alpha, beta
          double precision nrm
          integer*8 d_x, d_y, d_alpha, d_beta, d_nrm
          integer*8 dsize1, dlength1, dlength2
          double precision dresult
    
    
    
          write(*,*) "testing cublas fortran example"
    
    c     initialize cublas library
    c     CUBLAS_STATUS_SUCCESS=0
          cublas_status = cublas_init()
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS Library initialization failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
    c     initialize data
          do j=1,30
            x(j) = 1.0
            y(j) = 2.0
          enddo
          dsize1 = 8
          dlength1 = 30
          dlength2 = 1
          alpha = 2.0
          beta = 3.0
    c     allocate device storage
          cublas_status = cublas_alloc(dlength1, dsize1, d_x)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS device malloc failed"
             stop
          endif
          cublas_status = cublas_alloc(dlength1, dsize1, d_y)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS device malloc failed"
             stop
          endif
          cublas_status = cublas_alloc(dlength2, dsize1, d_alpha)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS device malloc failed"
             stop
          endif
          cublas_status = cublas_alloc(dlength2, dsize1, d_beta)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS device malloc failed"
             stop
          endif
          cublas_status = cublas_alloc(dlength2, dsize1, d_nrm)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS device malloc failed"
             stop
          endif
    
    c     copy data from host to device
    
          cublas_status = cublas_set_vector(dlength1, dsize1, x, dlength2,
         >     d_x, dlength2)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS copy to device failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
          cublas_status = cublas_set_vector(dlength1, dsize1, y, dlength2,
         >     d_y, dlength2)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS copy to device failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
    
          dresult = cublas_ddot(dlength1, d_x, dlength2, d_y, dlength2)
          write(*,*) "dot product result=",dresult
    
          dresult = cublas_dnrm2(dlength1, d_x, dlength2)
          write(*,*) "nrm2 of x result=",dresult
    
          dresult = cublas_dnrm2(dlength1, d_y, dlength2)
          write(*,*) "nrm2 of y result=",dresult
    
          call cublas_daxpy(dlength1, alpha, d_x, dlength2, d_y, dlength2)
          cublas_status = cublas_get_vector(dlength1, dsize1, d_y, dlength2,
         >     y, dlength2)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS copy to host failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
          write(*,*) "daxpy y(1)  =", y(1)
          write(*,*) "daxpy y(30) =", y(30)
    
    
          call cublas_dscal(dlength1, beta, d_x, dlength2)
          cublas_status = cublas_get_vector(dlength1, dsize1, d_x, dlength2,
         >     x, dlength2)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS copy to host failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
          write(*,*) "dscal x(1)  =", x(1)
          write(*,*) "dscal x(30) =", x(30)
    
    
          call cublas_dcopy(dlength1, d_x, dlength2, d_y, dlength2)
          cublas_status = cublas_get_vector(dlength1, dsize1, d_y, dlength2,
         >     y, dlength2)
          if (cublas_status /= 0) then
             write(*,*) "CUBLAS copy to host failed"
             write(*,*) "cublas_status=",cublas_status
             stop
          endif
          write(*,*) "dcopy y(1)  =", y(1)
          write(*,*) "dcopy y(30) =", y(30)
    
    c     deallocate GPU memory and exit
          cublas_status = cublas_free(d_x)
          cublas_status = cublas_free(d_y)
          cublas_status = cublas_free(d_alpha)
          cublas_status = cublas_free(d_beta)
          cublas_status = cublas_free(d_nrm)
          cublas_status = cublas_shutdown()
          stop
          end
    

    编译/运行:

    $ gfortran -c -o cublasf.o cublasf.f
    $ gcc -c -DCUBLAS_GFORTRAN -I/usr/local/cuda/include -I/usr/local/cuda/src -o fortran.o /usr/local/cuda/src/fortran.c
    $ gfortran -L/usr/local/cuda/lib64 -lcublas -o cublasf cublasf.o fortran.o
    $ ./cublasf
     testing cublas fortran example
     dot product result=   60.0000000000000
     nrm2 of x result=   5.47722557505166
     nrm2 of y result=   10.9544511501033
     daxpy y(1)  =   4.00000000000000
     daxpy y(30) =   4.00000000000000
     dscal x(1)  =   3.00000000000000
     dscal x(30) =   3.00000000000000
     dcopy y(1)  =   3.00000000000000
     dcopy y(30) =   3.00000000000000
    $ 
    

    CUDA 5.0、RHEL 5.5

    【讨论】:

    • 感谢您非常快速且非常有帮助的回复。我只有几个后续问题。 1) 我正在运行 Ubuntu 13.10,需要使用 Intel Fortran (ifort) 编译器。当我使用 gcc 和 gfortran 运行上面的代码时,出现各种错误:fortran.o: In function 'cublas_init_': fortran.c:(.text+0x5): undefined reference to 'cublasInit' 这些在哪里源于(我从上面复制并粘贴了您的示例)?另外,有没有办法将它与 ifort 一起使用?我不断收到来自 fortran_common.h 的未定义编译器错误。
    • 您使用的是哪个版本的 CUDA?你的 cuda 库安装在哪里?听起来您的链接操作没有找到 cublas 库。对于ifort,将-DCUBLAS_GFORTRAN 更改为-DCUBLAS_INTEL_FORTRAN 可能还需要其他更改。它应该可以与ifort 一起使用,但可能需要进行一些语法更改。
    • 我使用的是 Cuda 5.5,它们安装在 /usr/local/cuda-5.5/ 中,我在上面的示例中进行了相应的更改。我会试试 -DCUBLAS_INTEL_FORTRAN。再次感谢!
    • 在 CUDA 5.5/RHEL 5.5 上准确编译我在此答案中显示的内容没有任何问题据我所知,Ubuntu 13.10 不是任何版本的 CUDA 的官方支持发行版。
    • 抱歉回复晚了(我正在放假过春假)。我试图从上面重新运行您的示例代码(逐字逐句),我收到的输出是:fortran.o: In function cublas_init_':fortran.c:(.text+0x5): undefined reference to cublasInit' fortran.o: In function cublas_shutdown_':fortran. c:(.text+0x10): 未定义引用cublasShutdown' fortran.o: In function cublas_alloc_': fortran.c:(.text+0x3f): 未定义引用cublasAlloc' fortran.o: In function cublas_free_': fortran.c:(.text+0x78): 未定义参考cublasFree' ,但适用于所有功能
    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2011-12-02
    相关资源
    最近更新 更多