说明:
1.转载请联系本人
2.代码在最后
问题描述
SpMV在许多科学计算程序中都有广泛的应用。
数据矩阵A是稀疏的,输入向量x和输出向量y是稠密的。公式: y = Ax
实验要求
- 根据内存大小测不同规模矩阵的处理速度(GFLOPS/秒),并给出计算公式。
- 请计算系统的理论峰值,如果没有达到理论峰值,尝试给出原因。
方法
CUDA稀疏矩阵上没有通用的方法,一般来说对于SpMV问题有两个可以着手的点:
一个是存储方式,另一个是矩阵相乘的方式。 矩阵相乘部分可以参考上一个实验中一些常用的方法,而在稀疏矩阵的问题中,尤为突出的是存储方式的选取。通常来说有COO,CSR,DIA,ELL,HYB等方法,较常采用的是COO与CSR。实验
1.实验环境
本机: CPU:i5-4210U
内存:8G OS: Windows10 1607实验室:CPU: i7-7700K GPU:GTX 1080
内存:8G DDR4 OS:Ubuntu 16.042.结果及分析
假设稀疏矩阵中不为0的个数为k
处理速度公式 = 2*k/1000000000/time 带宽计算公式 = (sizeof(int)*dim + sizeof(int)*k + sizeof(float)*k + sizeof(float)*dim*2)/1000000000/time系统理论峰值(即浮点数理论峰值)
集群理论浮点峰值 = CPU主频(GHz)× CPU每时钟周期执行浮点运算次数 × 节点数 × 8(每节点双路四核)=4.2*4*8=134.4GFLOPS/s峰值带宽: B=F×D/8=2133MHz*64bit/8=17.064GHz
没有达到理论峰值的原因是:
程序并不只是在做浮点数运算或只是在访问内存; 存储格式的问题; 可能内存带宽利用效果不好; 细颗粒度不够高;缓存设置不够; 以及操作系统的线程调度,和服务器本身的不稳定性等等。优化尝试
2.1尝试ELL存储格式
在采用该格式之后,性能提升非常显著,在老师提供的源码基础上,GFlops/s从1左右直接提升至18。
代码存放在路径 但ELL存储格式受到最大列数的制约,虽然在这次实验中体现不明显,但理论上如果原矩阵存在着一行全是数,而其余行只有几个数的情况下,存储空间会非常浪费,性能可能会比CSR要差。2.2尝试采用for循环展开
在spmv函数中的for循环之前,使用#pragma unroll,GFLOPS/s不升反降,不清楚原因。所以for展开的效果不是很显著。
2.3 尝试使用texture cache,行对齐等
在CSDN 上参考了一份代码,其中涉及到多个性能的优化策略,其代码中采用的是CSR的存储格式,报告显示对于非零元素较大的稀疏矩阵有着很好的加速效果。
在本次实验中,由于矩阵初始化时数据分配也不很符合该代码的要求,所以加速效果不够明显。 对应代码放在文末链接。结论
- 普通矩阵和稀疏矩阵的优化思路相差很大,而稀疏矩阵在实际生活中运用最为广泛。
- shared memory的正确使用能够非常显著地提升矩阵乘法的性能
- 选取一个好的存储格式,对性能的提示非常的关键
- CUDA中存在一个cusparse库可以直接调用来计算SpMV,但是运行时必须考虑到CUDA存矩阵的方式(按列存取)
参考
[1]
[2] 注:这是采用了CSR存储及texture方式优化的代码 [3]代码地址
个人GitHub: