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 的实现中使用频率非常高的几条指令.
   10   11   12   13   14   15   16   17   18   19   20