从R调用CUDA编译的.dll

时间:2013-07-14 00:47:49

标签: c r cuda

我正在使用Windows 7平台。

我将逐步介绍我执行的所有例程,以获取.dll文件(PASS),dyn。在R(PASS)中加载它并在R(FAIL)中唤起.Call函数。

当唤起.Call我得到:

> out<- .Call("rowAND", as.integer(t(m)), nrow(m), ncol(m))
**Error in .Call("rowAND", as.integer(t(m)), nrow(m), ncol(m)) : 
  C symbol name "rowAND" not in load table**

1)源代码下方:

#include <stdio.h>
#include <math.h>

#include <cuda_runtime.h>
#include <cuda.h>
#include <device_launch_parameters.h>

#include <R.h>
#include <Rdefines.h>

#include "cuPrintf.cuh"
#include "cuPrintf.cu"

#include "cuRow.h"
#include "cuError.h"

extern "C" { 
SEXP rowAND(SEXP x, SEXP r_nrow, SEXP r_ncol) {
    // input: 
    //              x=as.integer(t(m)), vector of integer values from R (t(m) because store values by col)
    //              r_nrow=nrow(m), scalar
    //              r_ncol=ncol(m), scalar

    //x = coerceVector(x, INTSXP); // force coercion to a matrix of real values

    // define deimension
    int nrow = asInteger(r_nrow);
    int ncol = asInteger(r_ncol);
    size_t m_size;
    size_t calc_size;
    m_size = nrow * ncol * sizeof(int); // m (input)
    calc_size = nrow * sizeof(int); // change to nrow/ncol depending on calculation (output)

    // R
    SEXP r;
    PROTECT(r = allocMatrix(INTSXP,nrow,1));

    // cuda error variable
    cudaError_t err;

    // allocate HOST 
    int *h_m = INTEGER(x);
    int *h_calc = INTEGER(r);

    // allocate DEVICE
    int *d_m = NULL, *d_calc = NULL;
    err = cudaMalloc((void **)&d_m, m_size); checkError(err);
    err = cudaMalloc((void **)&d_calc, calc_size); checkError(err);

    // copy host matrix to device
    err = cudaMemcpy(d_m, h_m, m_size, cudaMemcpyHostToDevice); checkError(err);

    // Initialize cuPrintf -- DEBUGGING
    cudaPrintfInit();

    dim3 numBlocks(nrow,1,1); // blocks
    dim3 threadsPerBlock(1,1,1); // 1 thread per block
    rowOR<<<numBlocks, threadsPerBlock,0,0>>>(d_m, d_calc, ncol); // main call

    // Terminate cuPrintf -- DEBUGGING
    cudaPrintfDisplay (stdout, true);
    cudaPrintfEnd ();

    err = cudaGetLastError(); checkError(err);

    // Copy the device result vector in device memory to the host result vector
    err = cudaMemcpy(h_calc, d_calc, calc_size, cudaMemcpyDeviceToHost); checkError(err);

    // Free device global memory
    err = cudaFree(d_m); checkError(err);
    err = cudaFree(d_calc); checkError(err);

    // Reset the device
    err = cudaDeviceReset();

    UNPROTECT(1);
    return r;
}

2)我使用生成对象(.obj)的nvcc编译.cu文件。因此,我链接库(PASS),这里没问题,它生成.dll文件。

3)当我使用R命令加载.dll时:dyn.load IT PASS 。 加载的.dll会显示在getLoadedDLLs()

> getLoadedDLLs()
                                                                                  Filename Dynamic.Lookup
base                                                                                  base          FALSE
methods       C:/Revolution/R-Community-6.2/R-2.15.3/library/methods/libs/i386/methods.dll          FALSE
Revobase    C:/Revolution/R-Community-6.2/R-2.15.3/library/Revobase/libs/i386/Revobase.dll           TRUE
tools             C:/Revolution/R-Community-6.2/R-2.15.3/library/tools/libs/i386/tools.dll          FALSE
grDevices C:/Revolution/R-Community-6.2/R-2.15.3/library/grDevices/libs/i386/grDevices.dll          FALSE
stats             C:/Revolution/R-Community-6.2/R-2.15.3/library/stats/libs/i386/stats.dll          FALSE
cuRow           C:/Users/msn/Documents/Visual Studio 2010/Projects/R_C/R_C/Debug/cuRow.dll           TRUE

4)这里有问题:当我检查函数rowAND是否已加载时,我得 FALSE

> is.loaded("rowAND")
[1] FALSE
> 

因此,显然,当我运行.Call(因为它没有加载)时它会失败:

> path.dll<-'C:/Users/msn/Documents/Visual Studio 2010/Projects/R_C/R_C/Debug'
> dyn.load(file.path(path.dll,paste0("cuRow", .Platform$dynlib.ext)))
> nrow<-10
> ncol<-3
> m<-matrix(sample(c(0,1),nrow*ncol,replace=TRUE),nrow,ncol)
> out<- .Call("rowAND", as.integer(t(m)), nrow(m), ncol(m))
Error in .Call("rowAND", as.integer(t(m)), nrow(m), ncol(m)) : 
  C symbol name "rowAND" not in load table

我看到该函数似乎在源代码中已正确定义,但在加载的库中无法“看到”。

我在这里缺少什么?提前谢谢!

修改

基于@Dirk部分答案,将尝试编写一个将由C调用的CUDA dll项目。因此,我可以使用标准R CMD SHLIB编译目标C源。

喜欢:C(dll),部署到R里面调用CUDA dll。

完成后会更新!

编辑2:

我在下面回答了我自己的问题。我终于可以在CUDAR

中实现WINDOWS platform

3 个答案:

答案 0 :(得分:4)

对于那些遇到同样困难的人,我决定回答我自己的问题。我可以将答案分类为解决问题的方法。

一天结束,我的问题是使用CUDA平台在GPU中实施R WINDOWS并行度。

我发现实现CRAN的大多数CUDA包(并非全部)都没有WINDOWS平台的二进制文件。换句话说,如果您尝试从WINDOWS中的源代码构建,则会失败。我猜他们还没有为WINDOWS构建,因为使用WINDOWSMinGW编译器在nvcc编译和链接.cu文件是一种技巧。

NVidia将VS2010作为WINDOWS开发的主要平台,eclipse插件仅支持Linux。虽然,nvcc编译器支持-ccbin选项,可以调用它gcc,但配置“工具链”真是绝招。

我的解决方法是在VS2010中开发DLL项目,并使用VS2010本机编译器/链接器cl来编译和链接DLL。

这个dll是内部调用CUDA GPU并行性的部分。

VS2010中编译后,我使用dyn.load()加载了dll,并使用.C中的R调用了其函数。

它终于奏效了,一天结束时我可以在CUDA平台中将GPU R并行功能部署到WINDOWS

我可以使用NAMESPACE在包中部署相同的.dll,并在CRAN tar ball中提供dll源代码,旨在不侵犯开源策略。无论如何,这是一种解决方法。

两个重要因素:

1)使用extern "C"在本机C中部署所有导出的函数。

2)将函数的所有输入变量视为指针,因为在使用'.C'调用时它是必需的。

答案 1 :(得分:2)

在您的情况下,我要做的是在现有的CUDA R包中非常密切地,它们在CRAN上公开提供,因为它们提供了可行的实现。我相信至少其中一些也建立在Windows上。

使用CUDA的CRAN包中有

等等。有关详情,请参阅CRAN Task View on High-Performance Computing

我最熟悉的是第一个(也是最老的)。我使用一层代码从R调用C到C,然后用另一层代码调用C到使用NVidia编译器前端编译的CUDA代码。最后一个使用Rcpp从R到C / C ++。我怀疑你的错误是由于试图跳过一步。

答案 2 :(得分:1)

在Windows上通过Visual Studio使用CUDA编译R时,有几件重要的事情。

  1. 使用 __ declspec(dllexport)关键字声明C函数(安装 extern&#34; C&#34;

    extern “C” __declspec(dllexport)
    
  2. 使用R(32位或64位)构建相同版本;否则,在R中加载DLL将失败:

  3.   

    加载库失败:%1不是有效的Win32应用程序。

    1. 正确包含Visual Studio中的CUDA库。一般来说,它将添加到:
    2.   

      Solution Explorer→项目名称

        

      属性→链接器→输入→附加依赖性

      其他详细步骤,您可以参考 NVIDIA blogParallelR