Page 15 - 《软件学报》2021年第8期
P. 15
蔡雨 等:异构 HPL 算法中 CPU 端高性能 BLAS 库优化 2297
在最内层的核心汇编代码中,PREFETCHn 指令的使用主要考虑两点:
(1) 何处插入 PREFETCHn 指令.
(2) 预取的地址跨度设置.
X86 CPU 的 cache line 大小为 64B,一个缓存行可以存放 8 个双精度浮点数据.如图 6 所示的汇编代码第 1
行的软件预取操作,表示把 A c 的第 9 个双精度数据开始的一个缓存行预取到 L1 缓存中.此处的预取操作是为第
22 行的 load 指令准备数据.第 5 行的 load 操作会在 L1 缓存发生 cache miss,但是因为对 A 进行了 packing 操作,
理论上能够在 L2 cache 命中.同理,第 9 行、第 14 行和第 18 行处的 load 操作会在 L1 中命中,第 11 行预取操作
将 A c 的第 17 个数据预取到内存.
……
1 prefetcht0 64(%%rax)
……
2 vmovapd 0 * 8(%%rbx),%%xmm1
3 vmovapd 2 * 8(%%rbx),%%xmm2
4 vmovapd 4 * 8(%%rbx),%%xmm3
5 vmovddup 0 * 8(%%rax),%%xmm0
6 vfmadd231pd %%xmm1,%%xmm0,%%xmm4
7 vfmadd231pd %%xmm2,%%xmm0,%%xmm5
8 vfmadd231pd %%xmm3,%%xmm0,%%xmm6
9 vmovddup 1 * 8(%%rax),%%xmm0
10 vfmadd231pd %%xmm1,%%xmm0,%%xmm7
11 prefetcht0 128(%%rax)
12 vfmadd231pd %%xmm2,%*%xmm0,%%xmm8
13 vfmadd231pd %%xmm3,%%xmm0,%%xmm9
14 vmovddup 2 * 8(%%rax),%%xmm0
15 vfmadd231pd %%xmm1,%%xmm0,%%xmm10
16 vfmadd231pd %%xmm2,%%xmm0,%%xmm11
17 vfmadd231pd %%xmm3,%%xmm0,%%xmm12
18 vmovddup 3 * 8(%%rax),%%xmm0
19 vfmadd231pd %%xmm1,%%xmm0,%%xmm13
20 vfmadd231pd %%xmm2,%%xmm0,%%xmm14
21 vfmadd231pd %%xmm3,%%xmm0,%%xmm15
……
22 vmovddup 8 * 8(%%rax),%%xmm0
Fig.6 Code segment of inner-most DGEMM kernel
图 6 DGEMM 核心汇编代码片段
软件预取指令的插入位置需要综合考虑体系结构特点,合理安排汇编指令.X86 CPU 的 L2 load-to-use 的
latency 至少是 12 个 core cycles,而每时钟周期只可以执行一条 FMA 指令,在 CPU 流水线能够连续 retire FMA
指令的理想状态下,预取指令和后续 load 指令之间至少插入 12 条 FMA 指令.
3 指令集优化
高效 BLAS kernel 的实现方法具有通用性,不同于其他数学库大部分代码通过汇编实现优化,BLIS 只在最
内层的 kernel 核心代码处使用了汇编代码,框架内的其他代码使用 C 实现.这给可移植性带来了极大的便利,在
适配不同架构的 CPU 时,开发者可以将主要精力集中在最内层 kernel 的汇编代码的优化上.
3.1 X86向量指令
不同架构的 CPU 大多会提供高效的 SIMD(single instruction multiple data)指令,X86 CPU 支持 AVX2 指令
集,可以使用 128 位的 XMM 寄存器和 256 位的 YMM 寄存器,但由于浮点运算部件的数据路径宽度是 128 位,
每个时钟周期最多可以同时处理 2 个双精度浮点数,单核理论双精度浮点性能是(128/64)×2=4 DP-FLOPs/cycle,
实际测试结果表明,使用 XMM 寄存器的效率要优于 YMM 寄存器.AVX2 指令集中主要有两类指令:数据传输
类指令和数据操作类指令.其中,VMOVDDUP、VMOVAPD、VMOVUPD、VMULPD 和 VFMADD231PD 是在
X86 架构 CPU 平台上高效 BLAS kernels 的实现中使用频率非常高的几条指令.