Gemm优化

为使您的问题得到快速解决,建议选择对应标签。
按照博客中矩阵的拆分方式
https://blog.csdn.net/weixin_39920397/article/details/111686882

假设L1D=32K,L2=512K,A,B,C矩阵大小都为480X480,即M=N=K=480
mr=nr=4
Kr=L1D/(mr+nr)=32K/4/(4+4)=1K
Nr=(L2-L1D)/Kr= (512K-32K)/4/1K=120

那也就是先拆分B矩阵的N,新的B矩阵为480X120=225K,A矩阵不拆分480X480=900K,
实现后效率不太高,总感觉M也要拆分

另外A矩阵如果都在L3上的时候,可以在最内层循环里面添加预取指令,这样可以减少cache miss

因为目前深度学习的M对应的是OC,输出通道一般不太大,一般为几百左右,所以就没有进行拆,基本上都能够在L3 cache里面,要拆的话,可能根据L3的大小拆。
另外这里的mr=mr=4是不是太小了,我们在arm64上这个mr=8,nr=12,arnv7上mr=6,nr=8

关于这个mr和nr的大小我也很奇怪呀,说是根据寄存器的数量。armv7 有 16 个 32-bit 通用寄存器,但能用的就13个R0~R12?armv7有 31 个 64-bit 通用寄存器,能用的是X9-X15和X19-X29?X0-X7 用于参数传递,其他都有特殊用途?

这里可能没有说清楚,这里的寄存器是指neon寄存器,因为matmul一般都用neon来进行优化。armV7中有16个neon寄存器,每一个是128位宽,对应是4个float。因此可以存放16*4=64个数据。mr=6,nr=8时候,6*8<64,剩下的寄存器可以用于读取/暂存A矩阵和B矩阵的数据。Arm64同样类推。

原来指的是NEON寄存器呀 :rofl:,我再试下,感谢

我今天试了下矩阵的6种分块模式,即M,N,K的两两组合,测试发现先后顺序影响不是很大,结果如下(第一列是矩阵的大小,第二列是gflops,第三列是diff,拆分Mr,Nr和Kr都是256):
(1)拆分M和K
200 1.662842 0.000000
240 1.628944 0.000000
280 1.436267 0.000046
320 1.171243 0.000084
360 1.470043 0.000099
400 1.483051 0.000130
440 1.494625 0.000137
480 1.363565 0.000168
520 1.408083 0.000229
560 1.416394 0.000275
600 1.416062 0.000275
(2)拆分M和N
200 1.654367 0.000000
240 1.566466 0.000000
280 1.456671 0.000000
320 1.057965 0.000000
360 1.169191 0.000000
400 1.224053 0.000000
440 1.068431 0.000000
480 0.894021 0.000000
520 0.776579 0.000000
560 0.832413 0.000000
600 0.740747 0.000000
(3)拆分N和K
200 1.662892 0.000000
240 1.580492 0.000000
280 1.429176 0.000046
320 1.065536 0.000084
360 1.271640 0.000099
400 1.241547 0.000130
440 1.106468 0.000137
480 0.908971 0.000168
520 0.898072 0.000229
560 0.918584 0.000275
600 0.854196 0.000275
以上可以得到两个结果:
A.从拆分模式来看,还是拆分K和M效果更佳。
B.以拆分N和K来看,矩阵为480的时候衰减明显,拆分后新的A矩阵为2564804=480K,与L2的512K很接近。这么来看主要是看拆分后A矩阵的大小是否小于L2缓存,这样拆分K和M为什么效果更好就好理解了?
以上是我的理解,还请大佬指教

你这里的至于拆分的信息,信息太少,最内层kernel的计算顺序需要和拆分配合起来,外围的拆分顺序变了,内部的kernel计算顺序也要相应的变化,这个变化主要是你如何分配cache来存放你的数据来决定。所以根本原因不是拆分引起的,是计算访存比。这里的计算访存比需要考虑到cache的miss引入潜在的访存。

1.拆分信息:CPU是A53,L1=32K,L2=512K,L3好像没有。A,B矩阵大小都为480X480。32个128位NEON寄存器。
2.外围的拆分顺序会影响kernel的计算顺序?有没有具体的例子呀,有点不太明白。
3.实际测试发现效率影响的因素:a.于拆分后的A和B是否都能放入L2 b.当不能同时放入L2时,A能否放入L2。当不满足a的时候效率有一定下降,当连b都不满足的时候,再次下降。
4.关于访存比,感觉好像无法比对6种拆分模式的优劣,比如
拆分M和N:
A矩阵的访存=(M/mr)(N/nr)Kmr=原始访存的1/nr
B矩阵的访存=(M/mr)
(N/nr)Knr=原始访存的1/mr
拆分M和K:
A矩阵的访存=(M/mr)(N)krmr=MNkr
B矩阵的访存=(M/mr)
(N)krN=
5.关于kernel的计算,假设最后拆分的A矩阵为a,最后拆分的B矩阵为b,文章里面好像是用a的一列(4行)乘以b的一行(4列),然后将这个得到的扇面累加起来。但实际测试的时候发现用a的一行(4列)乘以b的一列(4行)效率更高。这个是有什么说法么?