gpt4 book ai didi

memory - 为什么全局内存版本比我的 CUDA 代码中的常量内存更快?

转载 作者:行者123 更新时间:2023-12-05 03:15:30 25 4
gpt4 key购买 nike

我正在开发一些 CUDA 程序,我想使用常量内存加快计算速度,但事实证明,使用常量内存会使我的代码慢约 30%。

我知道常量内存擅长将读取广播到整个 warp,我认为我的程序可以利用它。

这里是常量内存代码:

__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();在读取常量内存之前,但它没有改变任何东西。

怎么了?提前致谢!

系统:

  • CUDA 驱动程序版本:5.0
  • CUDA 能力:2.0

参数:

  • 顶点数:~250 万
  • 飞机数量:1024架

结果:

  • 恒定内存版本:46 毫秒
  • 全局内存版本:35 毫秒

编辑:

所以我尝试了很多方法来使常量内存更快,例如:

1)注释掉两次全局内存读取,看看有没有影响,有没有。全局内存仍然更快。

2) 每个线程处理更多的顶点(从 8 个到 64 个)以利用 CM 缓存。这比每个线程一个顶点还要慢。

2b) 使用共享内存存储位移和顶点——一开始就加载它们,处理并保存所有位移。同样,比显示的 CM 示例慢。

在这次经历之后,我真的不明白 CM 读取广播是如何工作的,以及如何在我的代码中正确地“使用”。此代码可能无法使用 CM 进行优化。

编辑2:

又是一天的调整,我试过了:

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%) 所以 ifs 并不像我想象的那么邪恶。

编辑3:

我正在总结这个问题,这个问题可能无法通过使用常量内存来改善,这些是我的结果*:

Graph of global and constant memory performance

*时间报告为 15 次独立测量的中值。当常量内存不足以保存所有平面(4096 和 8192)时,多次调用内核。

最佳答案

虽然计算能力 2.0 芯片有 64k 的常量内存,但每个多处理器只有 8k 的常量内存缓存。您的代码的每个线程都需要访问所有 16k 的常量内存,因此您会因缓存未命中而失去性能。要有效地为平面数据使用常量内存,您需要重构您的实现。

关于memory - 为什么全局内存版本比我的 CUDA 代码中的常量内存更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15241032/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com