Hi, chenjie13,
根据你的文字和代码来看, 这不是一个常规的点乘的过程, 我们常说的点乘是向量的多个分量进行乘法, 并累加得到一个标量. 而根据你的文字和代码看, 这更像是对于你的3D矩阵A的任何一个1024 * 1024 = 1M个元素的面As, 其中的每个元素As(i,j) * C(i,j)的过程, 其中C是一个同样的1024 * 1024的系数矩阵.
如果是基于这种理解, 而不是你的原始描述的话, 根据你的代码:
无论是200层的这个矩阵的任何一个面, 还是系数矩阵的那个面, 大小均为8MB(1024 * 1024 * 2 * sizeof(float)). 这将远远的超过现在的GPU的任何L2 cache的大小. 因此实际上每次乘法, 3D矩阵的每个面和系数的这个平面, 均将反复被从global memory载入. 最终的运行起来将是反复载入8MB * 200 + 8MB * 200 + 8MB * 200 = 约4.8GB每次"你的点乘". 实际上的SM中的SP将基本空载, 而显存将很忙碌. Profiler将验证我的说法.
考虑到计算能力的不同, 这些写法不一定能充分满载显存. 我建议你分别进入如下步骤:
(1) 使用profiler看一下device memory的utilization程度, 如果不能接近满载. 你应当考虑1个线程计算多组数据(你的这里的2个元素的乘法, 分别得到实部和虚部的过程). 在特定的计算能力的卡上, 这样做是必须的.
(2)如果你的卡目前这个写法能够卡在显存访存的基本峰值. 则你应当考虑优化重复数据. 你有一个巨大的重复系数面(8MB), 每次和200个面的大矩阵中的每个面运算, 你的默认代码将每次都将重新载入一次这个系数面, 这是一种浪费. 你应当考虑通过shared memory之类的手段分批次的缓冲这个面(的一部分), 这样能理论上说最多减少50%的访存. 有大约200%的最多性能提升.
无论是采用了(1)(2)的哪种, 目前这个算法均将卡访存的. (运算量非常少, 基本都在访存上).
一个能实际大约达到300GB/s的卡, 你的这个代码理论说最佳能跑到约8MB * 401 =3.2GB, 3.2GB / 300GB/s = 大约10.x ms (例如1080), 实际能优化到跑到20ms以下就挺好.
Regards,
屠戮人神.