Cuda测量循环

时间:2013-08-29 22:44:00

标签: cuda measurement

我启动了一个非常简单的内核<<<<< 1,512>>>在CUDA Fermi GPU上。

__global__ void kernel(){
int x1,x2;

x1=5;
x2=1;

for (int k=0;k<=1000000;k++)
  {
   x1+=x2;

  }
}

内核非常简单,它可以添加10 ^ 6个并且不会将任何内容传回全局内存。结果是正确的,即在循环x1(在其所有512个线程实例中)包含10 ^ 6 + 5

之后

我正在尝试测量内核的执行时间。同时使用visual studio parallel nsight和nvvp。 Nsight测量2.5微秒,nvvp测量4微秒。

问题如下:我可能会大大增加循环的大小,例如10 ^ 8,时间保持不变。如果我减少循环大小相同。为什么会这样?

请注意,如果我在循环中使用共享内存或全局内存,则测量结果会反映正在执行的工作(即存在相称性)。

2 个答案:

答案 0 :(得分:3)

如上所述,CUDA编译器优化在删除死代码方面非常积极。因为x2不参与写入内存的值,所以可以删除它和循环。编译器还会预先计算在编译时可以推导出的任何结果,因此如果编译器知道循环中的所有常量,它可以计算最终结果并用常量替换它。

要解决这两个问题,请重写您的代码:

__global__ 
void kernel(int *out, int x0, bool flag)
{
    int x1 = x0, x2 = 1;

    for (int k=0; k<=1000000; k++) {
       x1+=x2;
    }

    if (flag) out[threadIdx.x + blockIdx.x*blockDim.x] = x1;
}

然后像这样运行:

kernel<<<1,512>>>((int *)0, 5, false);

通过将x1的初始值作为参数传递给内核,可以确保循环结果不可用于编译器。该标志使内存存储有条件,然后内存存储使整个计算不安全删除。只要在运行时将标志设置为false,就不会执行存储,因此不会影响循环的时间。

答案 1 :(得分:2)

因为编译器消除了死路径。你的代码实际上并没有做任何事情。看看装配。

如果你实际上看到了这个值,那么编译器可能刚刚优化了循环,因为它可以在编译期间知道该值。

当您将寄存器内容写出到共享内存时,编译器无法保证不会使用该结果,因此实际将计算该值。换句话说,您计算的值必须最终在某处使用或写入内存,否则其计算将被丢弃。