我正在研究一些CUDA程序,我想使用常量内存来加速计算,但是转向使用常量内存会使我的代码慢30%。
我知道恒定的记忆能很好地将读取广播到整个经线中,我认为我的程序可以利用它。
这是常量内存代码:
__constant__ float4 constPlanes[MAX_PLANES_COUNT];
__global__ void faultsKernelConstantMem(const float3* vertices, unsigned int vertsCount, int* displacements, unsigned int planesCount) {
unsigned int blockId = __mul24(blockIdx.y, gridDim.x) + blockIdx.x;
unsigned int vertexIndex = __mul24(blockId, blockDim.x) + threadIdx.x;
if (vertexIndex >= vertsCount) {
return;
}
float3 v = vertices[vertexIndex];
int displacementSteps = displacements[vertexIndex];
//__syncthreads();
for (unsigned int planeIndex = 0; planeIndex < planesCount; ++planeIndex) {
float4 plane = constPlanes[planeIndex];
if (v.x * plane.x + v.y * plane.y + v.z * plane.z + plane.w > 0) {
++displacementSteps;
}
else {
--displacementSteps;
}
}
displacements[vertexIndex] = displacementSteps;
}
全局内存代码是相同的,但它有一个参数(使用指向平面数组的指针)并使用它而不是全局数组。
我认为那些第一个全局内存读取
float3 v = vertices[vertexIndex];
int displacementSteps = displacements[vertexIndex];
可能导致线程“失步”,然后它们不会利用常量内存读取的广播,所以我试图调用__syncthreads();在阅读常量记忆之前,它没有改变任何东西。
有什么问题?提前谢谢!
系统:
参数:
结果:
编辑:
所以我尝试了很多方法来更快地使常量内存,例如:
1)注释掉两个全局内存读取以查看它们是否有任何影响而它们没有。全球记忆仍然更快。
2)每个线程处理更多顶点(从8到64)以利用CM缓存。这比每个线程的一个顶点更慢。
2b)使用共享内存来存储位移和顶点 - 在开始时加载所有位移,处理并保存所有位移。再次,比显示的CM示例慢。
在此经历之后,我真的不明白CM读取广播是如何工作的,以及如何在我的代码中正确“使用”。此代码可能无法使用CM进行优化。
EDIT2:
另一天的调整,我试过了:
3)每个线程处理更多顶点(8到64),内存合并(每个线程的增量等于系统中线程的总数) - 这比增量等于1但仍然没有加速的结果更好
4)替换此if语句
if (v.x * plane.x + v.y * plane.y + v.z * plane.z + plane.w > 0) {
++displacementSteps;
}
else {
--displacementSteps;
}
这给出了“不可预测的”结果,只需要一些数学运算来避免使用此代码进行分支:
float dist = v.x * plane.x + v.y * plane.y + v.z * plane.z + plane.w;
int distInt = (int)(dist * (1 << 29)); // distance is in range (0 - 2), stretch it to int range
int sign = 1 | (distInt >> (sizeof(int) * CHAR_BIT - 1)); // compute sign without using ifs
displacementSteps += sign;
不幸的是,这比使用if更慢(~30%)if ifs并不像我想的那么大。
EDIT3:
我结束这个问题,这个问题可能无法通过使用常量内存来改善,这些是我的结果*:
*时报报告为15次独立测量的中位数。当常量内存不足以保存所有平面(4096和8192)时,内核被多次调用。
答案 0 :(得分:2)
虽然计算能力2.0芯片具有64k的常量内存,但每个多处理器只有8k的常量内存缓存。您的代码让每个线程都需要访问所有16k的常量内存,因此您会因缓存未命中而丢失性能。要有效地为平面数据使用常量内存,您需要重新构建实现。