指令并行与矩阵分块:填平最后三十倍差距
前言
上回把三重循环换了下顺序,矩阵乘法从9秒干到1.5秒,当时对照的OpenBLAS成绩是0.05秒,中间还隔着三十倍,这三十倍总不能全赖人家多线程吧。翻了一堆资料把这笔账算明白了,大头其实藏在两个地方:CPU的指令级并行,和矩阵的分解策略。
CPU早就不是一次算一个数了
写代码的人很容易有个惯性思维:一行 a[i]*b[i] 就是做了一次乘法,CPU老老实实算完一个再算下一个。这是指令串行的想象,真实情况是现代CPU一条SIMD指令一次就能算一批:AVX2的寄存器256位宽,塞得下4个double,一条乘加指令(FMA)出发就是4乘4加;再加上主流CPU有两个FMA运算端口,一个时钟周期理论吞吐是16个浮点操作。标量代码再怎么优化,每个周期也就吃掉这一小口,理论峰值的大餐一口没动。