我有两个3D数组,即信号S(Q,C,M)
和过滤器F(Q,C,K)
。 Q
包含转换(FFT / DHT),C
是通道号。每个Q*C
都是一个过滤器。 M
K
是信号和过滤器的数量。
现在我需要执行以下操作:为每个信号应用每个滤波器,使用2D数组Q*C
的元素乘法。有MK
个QC
个,S
和F
的每一对都要相乘。在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。现在这是合理的。
答案 0 :(得分:-1)
首先。 CUDA内核的性能与设备的ccc及其硬件密切相关,据说:
第1点解释了你所说的话:
如果数据维度足够大,则可以达到约600 GFLOPS /秒。
增加允许内核运行更多块的数据大小,这意味着设备能够通过上下文切换隐藏长延迟操作。
我的建议是(通过增加复杂性来排序:
如果您发布最小功能代码,我可以告诉您更多!