Cuda输出随计算能力而变化

时间:2018-02-11 20:37:55

标签: cuda

我正在尝试运行以下内核,类似于稀疏矩阵向量乘法(SpMV)内核。

__global__ void cost_spmv(const int *population,const int *row,const int *col,int *out){
    /*Calculate the cost vector for multiplication of the matrices*/
    //int tid=threadIdx.x+blockDim.x*blockIdx.x;
    int lane=threadIdx.x;
    extern __shared__ int val[];
    int r=blockIdx.x;
    int rowStart=row[r];
    int rowEnd=row[r+1];
    val[threadIdx.x]=0;
    for(int i=rowStart+lane;i<rowEnd;i+=32)
        val[threadIdx.x]+=  population[col[i]];
    __syncthreads();
    if(lane<16)
        val[threadIdx.x]+=val[threadIdx.x+16];
    if(lane<8)
        val[threadIdx.x]+=val[threadIdx.x+8];
    if(lane<4)
        val[threadIdx.x]+=val[threadIdx.x+4];
    if(lane<2)
        val[threadIdx.x]+=val[threadIdx.x+2];
    if(lane<1)
        val[threadIdx.x]+=val[threadIdx.x+1];
    if(lane==0)
        out[r]=val[threadIdx.x];
}

使用

调用内核
cost_spmv<<<numRows,32,32*sizeof(int)>>>(population,rowArray,colArray, out)

其中numRows是数组的大小,out和rowArray(numRows+1 actually)rowArray[i]包含属于第i行的元素的起始索引.colArray的大小为rowArray[numRows]colArray[i]包含使用rowArray描述的行的非零值的列号。

然而,在针对计算能力 3.5在Tesla P4上 进行编译时,与我获得的计算能力6.1相比,我获得了不同的答案。我在特斯拉P4上使用计算 功能6.1 的答案与我在920m上使用计算 功能3.5 <得到的答案相同/ strong>即可。可能是什么原因?

1 个答案:

答案 0 :(得分:0)

请记住,CUDA编译器具有世界的单线程视图。它不知道用于执行代码的运行时配置,这在编译时是不可用的。

val[]的加载和先前写入val[]之间的代码中没有表达依赖关系。因此,编译器可以根据需要自由移动负载。在某些情况下,它可能选择提前发出一些或所有负载以增加代码的负载延迟容限,例如,通过转换代码如下:

int __temp0 = val[threadIdx.x+16];
int __temp1 = val[threadIdx.x+ 8];
int __temp2 = val[threadIdx.x+ 4];
int __temp3 = val[threadIdx.x+ 2];
int __temp4 = val[threadIdx.x+ 1];

if(lane<16)
    val[threadIdx.x]+=__temp0;
if(lane<8)
    val[threadIdx.x]+=__temp1;
if(lane<4)
    val[threadIdx.x]+=__temp2;
if(lane<2)
    val[threadIdx.x]+=__temp3;
if(lane<1)
    val[threadIdx.x]+=__temp4;

根据编译器选择放置负载的位置,缩减序列的结果会有所不同。 CUDA编译器中的代码生成和特别是指令调度因GPU架构而异,因此在编译不同的GPU架构时可能会观察到不同的结果。

为了在加载和存储之间强制实现所需的依赖关系,CUDA编程模型认可的方法是在每个缩减步骤之后使用__syncthreads()来创建障碍。实现期望结果的可能更快但更糟糕的方法是通过使用val修饰符来声明代码范围之外的代理可以更改volatile。这可以防止编译器移动val[]的负载。