我一直注意到某些机器上的所有CUDA内核(Fedora 24,GeForce Titan X maxwell)的执行速度超慢,但其他人没有。 编辑:我之前将CUDA vectorAdd sample作为MCVE,但由于每个线程的工作负载较低而对是否真的存在内存瓶颈存有疑问;所以,这是一个手动展开的内核:
enum { serialization_factor = 8 };
__global__ void vectorAdd(
const float* __restrict__ lhs,
const float* __restrict__ rhs,
float* __restrict__ result,
int length)
{
int pos = threadIdx.x + blockIdx.x * blockDim.x * serialization_factor;
if (length - pos >= blockDim.x * serialization_factor) {
#pragma unroll
for(int i = 0; i < serialization_factor; i++) {
result[pos] = lhs[pos] + rhs[pos];
pos += blockDim.x;
}
}
else {
for(; pos < length; pos += blockDim.x) {
result[pos] = lhs[pos] + rhs[pos];
}
}
}
......假设我们为5,000,000个元素运行它;并启动内核两次,忽略第一次运行。
好吧,凭借我的家用GPU,Geforce GTX 650 Ti Boost,我得到527 usec。这有点奇怪 - 通过带宽计算,我期待555 usec之类的东西:3004 MHz时钟* 192位总线= 72096 MB = 72 GB /秒,每个浮点数2 * 4字节* 5M数据。但它非常接近所以让我们忽略差异。分析器告诉我“全局负载吞吐量”为72.355 GB /秒。
现在,在Maxwell Titan X的工作中,我获得了232次使用。这大约快两倍 - 但GPU的带宽是我家GPU的5倍:~336 GB /秒。我应该看到像120 usec这样的东西。并且 - 分析器告诉我“全局负载吞吐量”是343.271 GB /秒(!)
怎么会发生这种情况?
备注:
答案 0 :(得分:3)
您的带宽计算不完全准确。由于specified theoretical peak memory bandwidth of the GTX 650 Ti BOOST传输(在时钟信号的上升沿和下降沿上传输单独的字),double data rate是您计算的两倍(144.2 GB / s)。向量添加示例中实现的带宽比您计算的高50%,因为还需要将结果写回内存。这意味着您的GTX 650 Ti BOOST测量结果达到了理论峰值带宽的79%。
Titan X's specified peak memory bandwidth为336.5 GB / s,因此您的测试达到了理论峰值内存带宽的77%。
这是about as good as it gets。剩余的差异是由于内存刷新,切换传输方向所需的时间等开销造成的。
答案 1 :(得分:1)
在tera的answer中添加一些,你的算法有一个热身和冷静阶段:当飞行中有很多请求时,延迟确实被隐藏了,但代价是温暖 - 向上,以及最后一次迭代的冷却。
如果您的日程安排良好,您将获得2048(每个sm的最大驻留线程数)x 24(GTX Titan X上的sm数)的工作块。每个都将运行8个值。因此,您的工作块是393,216个条目。 对于5,000,000大小的样本,它会产生12.7次迭代(13次,最后一次不完整)。预热/冷却成本是1次迭代。 根据线程的调度(并且这不一定是可预测的),您可以总共运行14次迭代;你可以以相同的成本获得5,111,808个参赛作品(还有一个热身/冷静)。这个尺寸将为您提供我认为的最佳表现。
因此,不完整的迭代加上预热/冷却可能会花费大约10%的性能,如果不是更多的话,实现的带宽接近峰值的85%。
还应该查看内核的最小运行时间,因为它可能也会占用一些微内核。运行各种数据大小应该可以缓解这一点。
最后但并非最不重要的是,内存频率可以使用nvidia-smi进行修改,如here所述。