使用CUDA进行数组元素明智的乘积和操作时,Gflops非常低

时间:2014-10-09 18:17:53

标签: arrays cuda

我有两个3D数组,即信号S(Q,C,M)和过滤器F(Q,C,K)Q包含转换(FFT / DHT),C是通道号。每个Q*C都是一个过滤器。 M K是信号和过滤器的数量。

现在我需要执行以下操作:为每个信号应用每个滤波器,使用2D数组Q*C的元素乘法。有MKQC个,SF的每一对都要相乘。在Matlab表格中,它将是Z(:,:,i,j) = S(:,:,i) .* F(:,:,j)

Z的维度为Q*C*K*M。它看起来像是最后一个维度上的外部产品。之后,我需要对所有通道求和,得到一个Q*K*M数组。无需保存中间结果Z

我编写了以下CUDA内核,但它只显示< 20 GFlops / s。 Lunching参数:Q=1024, threadPerBlock = Q, blockPerGrid = (K, M).

#define C 50
#define M 100
#define K 500

__global__ void corr5Ker(float *X, float *W, float *Z, int nChan) {

// Block index
int bk = blockIdx.x;
int bm = blockIdx.y;

// Thread index
int tx = threadIdx.x;

// Calc offsets
int xBegin = 1024 * nChan * bm;
int xStep = 1024;
int xEnd = 1024 * nChan * (bm + 1);

int wBegin = 1024 * nChan * bk;
int wStep = 1024;

float rC = 0;
// Conv
for (int ix = xBegin, iw = wBegin; ix < xEnd; ix += xStep, iw += wStep) {
    rC += X[ix + tx] * W[iw + tx];
}   
__syncthreads();

int threadId = (bk + bm * gridDim.x) * 1024 + tx;
Z[threadId] = rC;

}

我使用Q*C*M*K来计算Flops,时间只包含内核时间。我还测试了矩阵元素加法和线性内核的乘法,如果数据维度足够大,它可以达到大约600 Gflops / s。上述操作稍微复杂一点,但不应该低至20 Gflops / s。我错了什么时候?

修改1

我在计算矩阵加法时更正了我的代码,代码只有6 Gflops / s。我试图使用saxpy,它也提供了相同的结果。现在很清楚重要的是内存带宽。

我还用更多的寄存器纠正了上面的内核,这给出了大约50 Gflops / s。现在这是合理的。

1 个答案:

答案 0 :(得分:-1)

首先。 CUDA内核的性能与设备的ccc及其硬件密切相关,据说:

  1. 每个块使用1024个线程可能只能在SM上容纳少量块。这是由于每个线程需要的寄存器数量。共享内存在这种情况下不是限制,所以你没有使用任何限制。
  2. 使用共享内存,您会看到性能提升。
  3. 第1点解释了你所说的话:

      

    如果数据维度足够大,则可以达到约600   GFLOPS /秒​​。

    增加允许内核运行更多块的数据大小,这意味着设备能够通过上下文切换隐藏长延迟操作。

    我的建议是(通过增加复杂性来排序:

    • 了解您的应用程序,了解正在发生的事情。
    • 减少每个块的线程数。这应该会增加每个SM的块数,并且应该提高你获得的性能。
    • 使用共享内存。

    如果您发布最小功能代码,我可以告诉您更多!