【发布时间】:2013-04-19 21:33:43
【问题描述】:
我正在尝试将 featWidth * featHeight * 31 立方体与另一个 modelWidth * modelHeight * 31 立方体“卷积”。问题是这个内核非常慢(嗯,我设法比顺序 CPU 代码快,但与 OpenMP 版本一样慢)。我正在使用 Quadro FX 1800(是的,64 个 CUDA 核心......)。
__constant__ float d_model[31*22*22];
#define IMUL(a,b) ( __mul24((a), (b)) )
#define IMAD(a,b,c) ( __mul24((a), (b)) + (c) )
__global__ void dMatch(float *score, const int featWidth, const int featHeight, const int modelWidth, const int modelHeight, const int scoreWidth, const int scoreHeight)
{
const int x = IMAD(blockIdx.x, blockDim.x, threadIdx.x);
const int y = IMAD(blockIdx.y, blockDim.y, threadIdx.y);
if(x < scoreWidth && y < scoreHeight)
{
const int scoreIdx = IMAD(x, scoreHeight, y);
score[scoreIdx] = 0.f;
const int baseFeatIdx = IMUL(x,scoreHeight) + IMAD(modelHeight-1, x, y);
for(int z = 0; z < 31; ++z)
{
// Index positionning
int featIdx = IMAD(z, IMUL(featWidth,featHeight), baseFeatIdx);
int modelIdx = IMUL(z, IMUL(modelWidth,modelHeight));
float value = 0.f;
// filter
for(int xx=0; xx<modelWidth; xx++)
{
const int xxmodelIdx = IMAD(xx, modelHeight, modelIdx);
const int xxfeatIdx = IMAD(xx, featHeight, featIdx);
for(int yy=0; yy<modelHeight; yy++)
{
value += d_model[xxmodelIdx+yy] * tex1Dfetch(texFeatures,xxfeatIdx+yy);
}
}
score[scoreIdx] += value;
}
}
}
无论如何,我使用块中的8*8 线程和(scoreWidth/8)*(scoreHeight/8) 的网格大小启动这个内核(scoreWidth 和 scoreHeight 是生成的矩阵大小)。
我想知道你是否知道我的代码出了什么问题或者什么地方比较慢。
编辑:
一个更快的版本(480 毫秒的进程下降了 150 毫秒!)感谢 tera:
__global__ void dMatch(float *score, const int featWidth, const int featHeight, const int modelWidth, const int modelHeight, const int scoreWidth, const int scoreHeight)
{
const int y = IMUL(4,IMAD(blockIdx.x, blockDim.x, threadIdx.x));
const int x = IMAD(blockIdx.y, blockDim.y, threadIdx.y);
if(x < scoreWidth && y < scoreHeight)
{
const int scoreIdx = IMAD(x, scoreHeight, y);
const int baseFeatIdx = IMUL(x,scoreHeight) + IMAD(modelHeight-1, x, y);
float value=0.f, value1 = 0.f, value2 = 0.f, value3 = 0.f;
float feat,feat1,feat2,feat3;
// Index positionning
int featIdx = 0;
int modelIdx = 0;
int xxmodelIdx;
int xxfeatIdx;
float val;
for(int z = 0; z < 31; ++z)
{
featIdx = IMAD(z,IMUL(featWidth,featHeight),baseFeatIdx);
modelIdx = IMUL(z,IMUL(modelWidth,modelHeight));
// filter
for(int xx=0; xx<modelWidth; xx++)
{
xxmodelIdx = IMAD(xx, modelHeight, modelIdx);
xxfeatIdx = IMAD(xx, featHeight, featIdx);
feat=tex1Dfetch(texFeatures,xxfeatIdx+0);
feat1=tex1Dfetch(texFeatures,xxfeatIdx+1);
feat2=tex1Dfetch(texFeatures,xxfeatIdx+2);
feat3=tex1Dfetch(texFeatures,xxfeatIdx+3);
for(int yy=0; yy<modelHeight; yy++)
{
val = d_model[xxmodelIdx+yy];
value += val * feat;
value1 += val * feat1;
value2 += val * feat2;
value3 += val * feat3;
feat = feat1;
feat1 = feat2;
feat2 = feat3;
feat3 = tex1Dfetch(texFeatures,xxfeatIdx+yy+4);
}
}
}
score[scoreIdx] = value;
if(y+1 < scoreHeight)
score[scoreIdx+1] = value1;
if(y+2 < scoreHeight)
score[scoreIdx+2] = value2;
if(y+3 < scoreHeight)
score[scoreIdx+3] = value3;
}
用这个dim3 threads(16,16); dim3 grid(divup(scoreHeight,64), divup(scoreWidth,16));启动。
【问题讨论】:
-
一些快速思考:使用绑定到 3D 数组的纹理来利用 3D 局部性。一次性计算附近偏移量的多个结果,以摊销获取数据的成本。获得一个像样的 GPU,因为无论如何你的 GPU 并不比任何最近的 CPU 快多少。
-
谢谢!是的,我会尝试 3D 阵列,但我对此期望不高。当然,我的 GPU 不是很好……而且我有 Intel Xeon W3520 @ 2.67GHz。嗯...我正在等待我的新显卡(GTX 680),我想我不会有任何优化问题:)
-
我最希望产生多个输出。因为额外的输出基本上是免费的。
-
@tera 我不明白。您想计算不同 (x,y) 位置的分值吗?
-
是的。由于相邻像素的得分值只需要获取立方体的一个表面,因此立方体体积中的所有其他值都已加载用于原始像素的得分。
标签: cuda