来自cuda内核的函数调用无法正常工作

时间:2016-02-18 19:01:06

标签: c++ cuda

我有以下cuda Kernel:

template <class T,typename Func>
__global__
void for_each_kernel (T* d_v,int N,Func f)
{
    int idx = blockIdx.x*blockDim.x + threadIdx.x;
    int num_threads = gridDim.x * blockDim.x;

    __shared__ T s_x[1024];

    for(int i = idx; i < N; i += num_threads)
    {

        s_x[threadIdx.x] = d_v[i];
        f(&s_x[threadIdx.x]); // This Does Not Work Correctly
        //s_x[threadIdx.x] *=  10; // This Works Correctly
        d_v[i] = s_x[threadIdx.x];
    }
}

当我拨打function f时,它会输出错误的值。但是当我直接进行乘法运算时,它就可以了。

两个部分都在评论中突出显示。

这是传递的函数:

__device__
void func(int *x) 
{
    *x = (*x) * 10;

}

以下是内核调用的发生方式:

template <typename Func>
void for_each (int start,int end,Func f)
{   
    for_each_kernel<<<26,1024>>> (d_v,end-start+1,f);   
}   

a [i]中的每一个都被初始化为i。

我正在打印的值为a[10],应打印100。 但它是打印32767,这是2 ^ 15 - 1。

显示问题的完整示例代码如下:

#include <cstdio>
using namespace std;


__device__
void func(int *x)
{
    *x = (*x) * 10;

}

template <class T,typename Func>
__global__
void for_each_kernel (T* d_v,int N,Func f)
{
    int idx = blockIdx.x*blockDim.x + threadIdx.x;
    int num_threads = gridDim.x * blockDim.x;

    __shared__ T s_x[1024];

    for(int i = idx; i < N; i += num_threads)
    {

        s_x[threadIdx.x] = d_v[i];
        f(&s_x[threadIdx.x]);
        //s_x[threadIdx.x] *=  10;
        d_v[i] = s_x[threadIdx.x];
    }
}

template <class T>
class device_vector
{
    T *d_v;
    int numEle;

    public :

    device_vector (T *h_v,int N)
    {
        cudaMalloc  ((T**)&d_v,N*sizeof(T));
        cudaMemcpy(d_v, h_v, N * sizeof(T), cudaMemcpyHostToDevice);
        numEle = N;


    }

    void set (T data,int index)
    {
        cudaMemcpy (&d_v[index],&data,sizeof(T),cudaMemcpyHostToDevice);
    }


    T get (int index)
    {
        T temp;
        cudaMemcpy (&temp,&d_v[index],sizeof(T),cudaMemcpyDeviceToHost);
        return temp;
    }

    void getRange (T *dest,T *start,int N)
    {
        cudaMemcpy (dest,start,sizeof(T)*N,cudaMemcpyDeviceToHost);
    }


    // Only Provide Start And End Vertices Fot Which you Want To Do Some Operation
    template <typename Func>
        void for_each (int start,int end,Func f)
        {  
            for_each_kernel<<<26,1024>>> (d_v,end-start+1,f);  
        }  

};


int a[1<<28];
int main ()
{
    int N = 1<<28;

    for (int i=0;i<N;i++)
        a[i] = i;

    device_vector<int> d (a,N);

    d.for_each (0,N-1,func);

    printf ("Getting Element At Index %d : %d \n",100,d.get(10));

    return 0;
}

1 个答案:

答案 0 :(得分:3)

问题是您正在将__device__函数指针从主机传递到内核。直接从主机获取设备符号的地址是非法的。您必须使用cudaMemcpyFromSymbol来获取主机端设备符号的地址。 在当前代码中,您必须创建一个指向__device__函数的主机端函数指针并将其传递给内核。它可以按如下方式完成:

//Declare function pointer
typedef void(*pFunc)(int*);

//Function pointer on device
__device__ pFunc f_device = func;

int main()
{
    int N = 1 << 28;

    for (int i = 0; i<N; i++)
        a[i] = i;

    device_vector<int> d(a, N);

    //Function pointer on host
    pFunc f_host;

    //Copy address of device function to host
    cudaMemcpyFromSymbol(&f_host, f_device, sizeof(pFunc));

    d.for_each(0, N - 1, f_host);

    printf("Getting Element At Index %d : %d \n", 100, d.get(100));

    return 0;
}