测量关于块数的cuda执行时间

时间:2014-03-23 14:59:06

标签: c performance cuda

我写了我的第一个cuda脚本,并想知道它是如何并行化的。 我有一些变量r0_devf_dev,每个变量长度为(*fnum_dev) * 3。在每个块上,它们按顺序读取。然后是我读过的r_dev和我要并行写的v_dev,两者都是长度为gnum * 3的数组。

该程序产生我希望它产生的结果,但复杂性(时间与数据大小的关系)并不是我所期望的。

我的期望是,当数组v_dev的大小增加时,执行时间保持不变,因为gnum的值小于某个维度中允许的块数。

现实是不同的。使用以下代码,测量时间。观察到线性复杂性,我将在顺序代码中执行该操作。

dim3 blockGrid(gnum);

cudaEvent_t start, stop;
float time;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);

// the actual calculation
stokeslets<<<blockGrid, 1>>>(fnum_dev, r0_dev, f_dev, r_dev, v_dev);

// time measurement
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);

问题:

如上所述,我的期望是错的吗? 还有哪些其他考虑因素很重要?

详情

以下显示stokeslet的实施。也许我在做那些不好的事情?

__device__ void gridPoint(int offset, float* r0, float* f, float* r, float* v) {
    int flatInd = 3 * offset;

    float dr[3];
    float len = 0;
    float drf = 0;

    for (int i = 0; i < 3; i++) {
        dr[i] = r[i] - r0[i + flatInd];
        len += dr[i] * dr[i];
        drf += dr[i] * f[i + flatInd];
    }

    len = sqrt(len);
    float fak = 1 / (8 * 3.1416 * 0.7);
    v[0] +=  (fak / len) * (f[0 + flatInd] + (dr[0]) * drf / (len * len));
    v[1] +=  (fak / len) * (f[1 + flatInd] + (dr[1]) * drf / (len * len));
    v[2] +=  (fak / len) * (f[2 + flatInd] + (dr[2]) * drf / (len * len));
}


__global__ void stokeslets(int* fnum, float* r0, float* f, float* r, float* v) {
    // where are we (which block, which is equivalent to the grid point)?
    int idx = blockIdx.x;

    // we want to add all force contributions
    float rh[3] = {r[3 * idx + 0], r[3 * idx + 1], r[3 * idx + 2]};

    float vh[3] = {0, 0, 0};
    for (int i=0; i < *fnum; i++) {
        gridPoint(i, r0, f, rh, vh);
    }
    // sum intermediate velocity vh
    int flatInd = 3 * idx;
    v[0 + flatInd] += vh[0];
    v[1 + flatInd] += vh[1];
    v[2 + flatInd] += vh[2];
}

1 个答案:

答案 0 :(得分:3)

代码的主要问题是您运行的多个块只包含一个线程

引用CUDA C编程指南

  

NVIDIA GPU架构围绕可扩展的多线程阵列构建   流式多处理器(SM)。当主机CPU上的CUDA程序调用a时   在内核网格中,网格的块被枚举并分发给多处理器   具有可用的执行能力。线程块的线程并发执行   在一个多处理器上,多个线程块可以在一个上同时执行   多处理器。当线程块终止时,空出的新块将被启动   多处理器。

     

多处理器旨在同时执行数百个线程。

引用帖子How CUDA Blocks/Warps/Threads map onto CUDA Cores?

的回答
  

程序员将工作划分为线程,将线程划分为线程块,将线程块划分为网格。计算工作分配器将线程块分配给流式多处理器(SM)。一旦将线程块分配给SM,就会分配线程块的资源(warp和共享内存),并将线程划分为32个线程的组,称为warps。一旦分配了warp,它就被称为主动warp。 两个warp调度程序每个周期选择两个活动warp并将warp调度到执行单元

从两个带有粗体标记的句子开始,每个流多处理器每个时钟周期只运行2个线程。这是您观察与连续情况基本相同的计算复杂度的主要原因。

建议重写代码/内核以承载每个块运行多个线程的可能性。

进一步阅读:The Fermi architecture whitepaper