CUDAExample-0-cppOverload

官方提供的例程中有GPU和CPU两部分程序,这两部分程序完成相同的工作,其中,GPU部分是用共享内存完成,且提供了三种不同的方法,CPU部分同样提供了三种不同的计算方法,完成与GPU程序相同的运算,用于做对比。overload指的是一个块内sharememory超出了max shared memory per block的size。但是在cuda7.0,gtx980显卡下max shared memory per block为48k,当把一块内的共享内存提升到48k以上时,就会报错,提示share memory溢出。但是当没有超过share memory时,程序运行正确且对比结果为真。换句话说,overload问题已经通过自身软件进行了限制,不允许程序中出现overload问题,否则直接报错。

测试程序

GPU部分

/*
 *share memory为THREAD—N*sizeofint)的大小。
*/
__global__ void simple_kernel(const int *pIn, int *pOut, int a)
{
    __shared__ int sData[THREAD_N];
    int tid = threadIdx.x + blockDim.x*blockIdx.x;

    sData[threadIdx.x] = pIn[tid];
    __syncthreads();

    pOut[tid] = sData[threadIdx.x]*a + tid;;
}

/*
 *share memory为THREAD—N*sizeof(int2)的大小。
 *int2结构体类型,包含xy两维度
*/
__global__ void simple_kernel(const int2 *pIn, int *pOut, int a)
{
    __shared__ int sData6[3];

    int tid = threadIdx.x + blockDim.x*blockIdx.x;
    sData[threadIdx.x] = pIn[tid];
    __syncthreads();

    pOut[tid] = (sData[threadIdx.x].x + sData[threadIdx.x].y)*a + tid;;
}

/*
 *share memory为THREAD—N*sizeofint)* 2的大小。
*/
__global__ void simple_kernel(const int *pIn1, const int *pIn2, int *pOut, int a)
{
    __shared__ int sData1[THREAD_N];
    __shared__ int sData2[THREAD_N];
    int tid = threadIdx.x + blockDim.x*blockIdx.x;

    sData1[threadIdx.x] = pIn1[tid];
    sData2[threadIdx.x] = pIn2[tid];
    __syncthreads();

    pOut[tid] = (sData1[threadIdx.x] + sData2[threadIdx.x])*a + tid;
}

CPU部分

bool check_func1(int *hInput, int *hOutput, int a)
{
    for (int i = 0; i < N; ++i)
    {
        int cpuRes = hInput[i]*a + i;

        if (hOutput[i] != cpuRes)
        {
            return false;
        }
    }

    return true;
}

bool check_func2(int2 *hInput, int *hOutput, int a)
{
    for (int i = 0; i < N; i++)
    {
        int cpuRes = (hInput[i].x + hInput[i].y)*a + i;

        //printf("hInput[i].x %d - hInput[i].y %d = %d\n", hInput[i].x , hInput[i].y, hInput[i].x - hInput[i].y);

        if (hOutput[i] != cpuRes)
        {
            return false;
        }
    }

    return true;
}

bool check_func3(int *hInput1, int *hInput2, int *hOutput, int a)
{
    for (int i = 0; i < N; i++)
    {
        if (hOutput[i] != (hInput1[i] + hInput2[i])*a + i)
        {
            return false;
        }
    }

    return true;
}

GPU状态提取部分


    struct cudaFuncAttributes attr;

    // overload function 1
    func1 = simple_kernel;
    memset(&attr, 0, sizeof(attr));
    checkCudaErrors(cudaFuncSetCacheConfig(*func1, cudaFuncCachePreferShared));
    checkCudaErrors(cudaFuncGetAttributes(&attr, *func1));
    OUTPUT_ATTR(attr);

以上程序在每一部分都相同,且在kernel函数运行之前就进行显示,而且simple—kernel函数是复用的,区分复用哪一个kernel函数用

    void (*func1)(const int *, int *, int);
    void (*func2)(const int2 *, int *, int);
    void (*func3)(const int *, const int *, int *, int);

分辨。
其中,cudaFuncSetCacheConfig和cudaFuncGetAttributes的代码未给出,但是通过传入传出参数和运行代码可以知道,此段代码是用于设置和返回当前正在使用的kernel函数的状态,如shared size 、constant size、max threads per block、number of register等等,其中shared size是根据程序中设置的值来确定的,是个变量,在文档中有提及

Note that some function attributes such as
ref ::cudaFuncAttributes::maxThreadsPerBlock “maxThreadsPerBlock”
may vary based on the device that is currently being used

可以看出此部分代码虽然放到kernel函数之前,但是却能返回kernel中设置的信息。

测试程序

由于GTX980每一块中的共享内存较多,线程只有1024,所以通过在每一块中额外定义和使用Shared memory来验证程序是否会返回false,但是当块中使用的shared memory超出限制时,就会在编译时报错。

总结

通过以上程序以及测试程序可以分析得知overload问题已经在在此版本中通过编译前检查是否溢出来解决。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章