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問題已經在在此版本中通過編譯前檢查是否溢出來解決。

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