说我想将两个矩阵相乘,50乘以50.我有2种方法来排列线程和块。
a)计算结果矩阵的每个元素的一个线程。所以我在线程中有一个循环乘以一行和一列。
b)每个乘法的一个线程。结果矩阵的每个元素需要50个线程。在完成乘法之后,我可以使用二进制缩减来对结果求和。
我不知道采取哪种方式,所以我拿了b。这不太理想。事实上它很慢。知道为什么吗?我的猜测是,有太多的线程,他们大部分时间都在等待资源,这是真的吗?
答案 0 :(得分:4)
与高性能计算中的许多事情一样,理解性能的关键在于理解内存的使用。
如果你使用一个线程做一次乘法,那么对于那个线程,你必须从内存中提取两个数据,乘以它们,然后做一些logarthmic数量的加法。这是针对mult和add和bit的三次内存访问 - 算术强度非常低。好消息是,这种方式有许多线程值得完成,每个线程只需要一点点内存/寄存器,这对于占用很有用;但内存访问工作的比例很差。
执行一个点乘积方法的简单一个线程具有相同类型的问题 - 每个乘法需要两次内存访问才能加载。好消息是整个点产品只有一个存储到全局存储器中,并且你避免了二进制缩减,它不能扩展并且需要大量同步;不利的是,现在的线程越来越少了,至少你的(b)方法对你有效。
现在你知道每个内存访问应该有一些方法比这更多;对于平方NxN矩阵,有N ^ 3工作来进行乘法,但只有3xN ^ 2个元素 - 所以你应该能够找到一种方法,每2个内存访问进行多于1次计算。
CUDA SDK中采用的方法是最好的方法 - 将矩阵分解为切片,并使用(b)方法 - 每个输出元素一个线程。但关键在于线程的排列方式。通过从缓慢的全局存储器中拉入整个小子矩阵到共享存储器,并从那里进行计算,可以进行多次乘法并添加从内存中读取的每个数字。这种方法在许多应用中是最成功的方法,因为获取数据 - 无论是通过网络,还是来自CPU的主存储器,还是GPU的片外访问 - 通常需要比处理数据更长的时间。
NVidia的CUDA页面中的文档(特别是http://developer.nvidia.com/object/cuda_training.html)非常好地描述了他们的SDK示例。
答案 1 :(得分:3)
您是否查看了CUDA文档:Cuda Programming Model
此外,示例源代码:Matrix Multiplication
答案 2 :(得分:1)
你看了吗
$SDK/nvidia-gpu-sdk-3.1/C/src/matrixMul
即。 SDK中的矩阵乘法示例?
答案 3 :(得分:0)
如果您不需要自己实现,只需使用库 - CUBLAS,MAGMA等,提供调整矩阵乘法实现。