目的
作为分析指标和/或基于性能指标评测目的,浮点运算 (FLOP) 速度广泛运用于高性能计算 (HPC) 社区。 许多 HPC 贡献者(比如戈登·贝尔)要求提交应用时注明 FLOP 速度。
本文所述的方法不依赖于性能监控单元 (PMU) 事件/计数器。 它是一种使用英特尔® SDE 评估 FLOP 的替代性软件方法。
方法
- 我们将 FLOP (浮点运算)划分为两类:
- 非屏蔽 FLOP: 针对不支持屏蔽功能的英特尔® 架构
- 非屏蔽 + 屏蔽 FLOP: 针对支持屏蔽功能的英特尔® 架构
不支持屏蔽功能的英特尔® 架构示例 处理器名称 代号名称 第二代英特尔® 酷睿™ 处理器系列 Sandy Bridge 第三代英特尔® 酷睿™ 处理器系列 Ivy Bridge 第四代英特尔® 酷睿™ 处理器系列 Haswell 支持屏蔽功能的英特尔® 架构示例 处理器名称 代号名称 英特尔® 至强融核™ 协处理器 Knights Landing
- 浮点指令/运算所涵盖的范围尚存在争议。
- 下面列举出该方法所使用的常用浮点指令: ADD、SUB、MUL、DIV、SQRT、RCP、FMA、FMS、DPP、 MAX、MIN(均包含多个分类)
- 我们推荐:
- 解码每个浮点指令来确定下列参数:
- 矢量(封包)或标量
- 数据类型(单精度或双精度)
- 所使用的寄存器类型(xmm – 128 位,ymm – 256 位,zmm – 512 位)
- 是否屏蔽 — 屏蔽或非屏蔽指令
- 使用上述带有“动态执行”数的信息评估该指令的 FLOP 数。
例如: vfmadd231pd zmm0, zmm30, zmm1 执行 500 次- p– 封包指令(矢量),非屏蔽
- d– 双精度数据类型(64 位)
- zmm– 运行于 512 位寄存器
- fma– 融合乘加(2 次浮点运算)
上述指令的 FLOP 数 = 8 * 2 (fma) * 500(执行数)= 8000 FLOP。
- 解码每个浮点指令来确定下列参数:
- 评估应用的 FLOP 数时,不必为每个浮点指令进行上述解析/解码。
- 英特尔 SDE 的指令混合直方图与动态掩码配置文件可提供一套预评估的计数器(使用上述或更多方法),可帮助您评估应用的 FLOP 数。
下面将对此进行详细介绍。
用于计算非屏蔽 FLOP 的指令
- 这类指令适用于所有英特尔架构(Sandy Bridge、Ivy Bridge、Haswell,Knights Landing 等)
- 点击此处获取最新版英特尔® SDE。
- 使用英特尔 SDE 生成针对应用的指令混合直方图,如下所示:
- sde -<arch> -iform 1 -omix myapp_mix.out -top_blocks 5000 -- ./myapp.exe
- < arch >表示您希望基于此运行的架构(比如 ivb、hsw、knl)
- 为基于此运行的架构准确编译二进制。
- 支持多线程运行
例如:
sde -knl -iform 1 -omix myapp_knl_mix.out -top_blocks 5000 -- ./myapp.knl.exe
- sde -<arch> -iform 1 -omix myapp_mix.out -top_blocks 5000 -- ./myapp.exe
- 在指令混合输出(比如 myapp_mix.out)中 “EMIT_GLOBAL_DYNAMIC_STATS” 的下方,检查下列预评估计数器:
- *elements_fp_(single/double)_(1/2/4/8/16)
- *elements_fp_(single/double)_(8/16) _masked
- 不同计数器的含义各不相同:
elements_fp_single_1 – floating point instructions with single precision and one element (probably scalar) and no mask elements_fp_double_4 – floating point instructions with double precision and four elements and no mask (ymm) elements_fp_double_8 – floating point instructions with double precision and eight elements and no mask (zmm) …...... elements_fp_single_16_masked – similar as above but now with masks (Note: you will see the mask counts only on architectures + ISA that support masking)
- 由于上述计数器将混合乘加指令 (FMA) 算作 1 FLOP,所以上述计算本身不够充分。
- “EMIT_GLOBAL_DYNAMIC_STATS” 部分还可打印应用中执行的每种 FMA 的动态计数。 请看下面:
VFMADD213SD_XMMdq_XMMdq_XMMdq scalar, double precision, on xmm (128 bit) = 1 element VFMADD231PD_YMMdq_YMMdq_YMMdq packed, double precision, on ymm (256 bit) = 4 elements VFMADD132PS_ZMMdq_ZMMdq_ZMMdq packed, single precision, on zmm (512 bit) = 16 elements
......
也可显示其他相类似的 FMA ,比如 VFNMSUB132PD_YMMqq_YMMqq_MEMqq、VFNMADD231SD_XMMdq_XMMq_XMM 等。 - 计算 FLOP
步骤 1- 对于不同数据类型(单精度/双精度),用与上述计数器相对应的“动态”指令数乘以“元素 (1/2/4/8/16)”,得出 FLOP 数。
示例:
Sandia Mantevo 套件中分子动力学代码的英特尔 SDE (Haswell) 指令混合输出(快照)(请查看 EMIT_GLOBAL_DYNAMIC_STATS 下方的内容)。
非屏蔽 FLOP(双精度) =
(23513724690 * 1 + 274320019 * 2 + 37317021308 * 4) = ~173.3304 GFLOP - 注意事项/警告:
- 由于上述计数器将混合乘加指令 (FMA) 算作 1 FLOP,所以上述计算本身不够充分(请查看“步骤 2”-如何将其计算在内)。
- 您也可以查看 “*elements_fp*_masked” 计数器,了解英特尔® AVX-512 (KNL) 指令混合输出。 下一部分将介绍如何计算屏蔽 FLOP。
- 同样,由于“屏蔽”计数器未指定实际掩码值,所以无法将其计算在内。
- 对于不同数据类型(单精度/双精度),用与上述计数器相对应的“动态”指令数乘以“元素 (1/2/4/8/16)”,得出 FLOP 数。
- 步骤 2
- 将 FMA 及其分类计算在内
- 关于 FMA 分类,可根据上述数据类型(单精度或双精度)、封包或标量和寄存器类型,以及与各 FMA 对应的“动态”指令数,将步骤 1 中计算的 FLOP 数加上“多 1 次” FLOP。
示例:
Sandia Mantevo 套件中分子动力学代码的英特尔 SDE (Haswell) 指令混合输出(快照)(请查看 EMIT_GLOBAL_DYNAMIC_STATS 下方 VFM* 部分)。
VFMADD213PD_XMMdq_XMMdq_XMMdq 1728000 VFMADD213PD_YMMqq_YMMqq_YMMqq 47496488 VFMADD213SD_XMMdq_XMMq_MEMq 825422220 VFMADD213SD_XMMdq_XMMq_XMMq 5733116808 VFMADD231PD_XMMdq_XMMdq_XMMdq 432000 VFMADD231PD_YMMqq_YMMqq_YMMqq 3189961568 VFMADD231SD_XMMdq_XMMq_MEMq 4 VFMADD231SD_XMMdq_XMMq_XMMq 475482133 VFMSUB213PD_YMMqq_YMMqq_YMMqq 1594141168 VFMSUB231PD_YMMqq_YMMqq_YMMqq 47064488 VFMSUB231SD_XMMdq_XMMq_XMMq 1656723
非屏蔽 FMA FLOP(双精度) =
(1728000 * 2 + 47496488 * 4 + 825422220 * 1 + 5733116808 * 1 + 432000 * 2 + 3189961568 * 4 + 4 * 1 + 475482133 * 1 + 1594141168 * 4 + 47064488 * 4 + 1656723 * 1) = ~26.5546 GFLOP
注意事项/警告:- 之前使用的乘数(1,2,4..)根据 FMA 指令的类型(PD - 基于 XMM/YMM 的封装双精度;SD – 基于 XMM 的标量双精度…)来确定。
- 对于英特尔 AVX-512 (KNL/SKL) 指令混合输出,所有 FMA (及其分类)指令(屏蔽或全部矢量)都将标记为屏蔽指令(比如 VFMADD132PD_ZMMf64_MASKmskw_ZMMf64_MEMf64_AVX512)。
- 下一部分“用于计算屏蔽 FLOP 的指令”将对此予以介绍。
- 将步骤 1 和步骤 2 所计算的 FLOP 数相加。
示例(advection 例程):
非屏蔽 FLOP(双精度)总和 = 173.3304 + 26.5546 = 199.885 GFLOP - 如果基于不支持屏蔽的架构运行,可直接计算 FLOP 总数(跳过下一部分)。
- 计算每秒浮点运算时 (FLOPS) ,用适当的硬件测量出的应用运行时间除以采用上述方法计算的 FLOP 数即可。
- 换言之,应用的 FLOP 数最有可能保持不变,因为它与基于运行的架构没有任何关系(除非编译器生成了完全不同的代码,影响了两种不同二进制的 FLOP 数 — 这种情况很少见)。 因此,如需了解应用的 FLOP 数,按上述针对不具备硬件屏蔽功能的 Ivy Bridge(或 Haswell)的方法计算,并使用与其他架构(比如 Knights Landing 等)相同的数即可。 因此评估 FLOP 数时,根本无需在意是否屏蔽。
- 不过,如果您仍需评估支持屏蔽功能的架构中的 FLOP 数,请参考下一部分,了解如何采用英特尔 SDE 的动态掩码配置文件特性计算屏蔽 FLOP。
用于计算屏蔽 FLOP 的指令
- 英特尔 SDE 具备动态掩码配置文件特性,可评估和打印带掩码的指令所执行的运算次数。
- 使用英特尔 SDE 生成应用的动态掩码配置文件,如下所示:
- sde -<arch> -iform 1 -odyn_mask_profile myapp_msk.out -top_blocks 5000 -- ./myapp.exe
- <arch> 表示您希望基于此运行的架构(比如 ivb、hsw、knl)。
- 为基于此运行的架构准确编译二进制。
- 支持多线程运行
例如:
sde -knl -iform 1 -odyn_mask_profile myapp_knl_msk.out -top_blocks 5000 -- ./myapp.knl.exe
- sde -<arch> -iform 1 -odyn_mask_profile myapp_msk.out -top_blocks 5000 -- ./myapp.exe
动态掩码配置文件为 XML 输出,其中包含根据不同类型的指令(屏蔽或非屏蔽)的线程得出的汇总表,及其指令和运算总数。
此外,该掩码配置文件还可打印各指令的动态指令数和运算次数。
汇总表(动态掩码配置文件)
示例: 英特尔® SDE (Knights Landing) 动态掩码配置文件输出(下列快照):列 标题 描述 一 mask 分类屏蔽指令和非屏蔽指令 二 cat 区分指令类型(比如,内存指令(数据传输)、稀疏指令(聚集/分散)或计算指令(掩码)) 三 vec-length 注明矢量寄存器宽度 四 #elements 注明矢量寄存器(如第三列 vec-length 所示)中的最大元素数,以及元素大小(见第五列) 五 element_s 注明元素(或数据类型)的大小(单位:位,比如 64b = 64 位 = 8 字节) 六 element_t 根据元素类型进行分类(比如 fp - floating point 和 int – integer) 七 icount 各类型的总指令数 八 comp_count 各类型执行指令的相应计算数 九 %max-comp 显示各类型的矢量通道利用率 - 例如,在上述快照中,仅突出显示的两行需用于计算“屏蔽” FLOP 数。
- 请注意,(在运行过程中)您需主要观察带 “mask” 类型和 “element_t = fp” 的 “屏蔽” 指令来计算屏蔽 FLOP 数。
- “comp_count” 显示的数字主要为屏蔽 FLOP 数。
- 不过同样,FMA 在 comp_count 计数器中仅算作 1 次 FLOP。
- 请参阅下一部分了解如果将屏蔽 FMA 考虑在内(算作 2 次 FLOP)。
- 例如,在上述快照中,仅突出显示的两行需用于计算“屏蔽” FLOP 数。
- 根据指令详情(动态掩码配置文件)
- 除了按照线程得出的“汇总表”,动态掩码配置文件还可打印各指令的计算数。
- 下图显示其中一个快照。
- 图例中,屏蔽 “vfmadd213pd” 指令的执行数 = 862280 加上计算数 = 5052521。 所以,该指令的总执行数没有采用所有矢量通道计算。
- 上述快照中,“vfmadd213pd” 指令的执行数 = 4000 加上计算数 = 32000 (4000 * 8)。 因此,该例(非屏蔽)中指令的总执行数采用了所有矢量通道计算。
- 由于汇总表将 FMA 指令(及其分类)以 1 次 FLOP 进行计算,因此您需要为指令详情(如上所述)中的所有屏蔽 FMA 指令的计算数加上“多一次”,按照每 FMA 2 次 FLOP 进行计算。
- 计算屏蔽 FLOP
步骤 1
- 在汇总表中,将带有“mask” 类型的所有“屏蔽”指令的 “comp_count” 值与 “element_t = fp” 相加。
- 步骤 2
- 解析指令详情中带掩码的 FMA 指令,并将 “computation-counts” 与步骤 1 中评估的总和相加(一次)。
- 以此得出屏蔽 FLOP 总数。
注意事项/警告:- 如前所述,在英特尔 AVX-512 (KNL/SKL) 指令混合输出中,所有 FMA(及其分类)指令(屏蔽或全部矢量)均标记为屏蔽指令(比如 VFMADD132PD_ZMMf64_MASKmskw_ZMMf64_MEMf64_AVX512)。
- 因此,您可采用动态掩码配置文件“instruction-details” 评估所有 FMA 指令(屏蔽或非屏蔽-全部矢量)的 “computation-count”。
验证
乍一看,上述方法可能令人无所适从,不过由于指令细节非常详细,您也可以自己编写脚本解析以上信息。 我们希望未来的英特尔 SDE 版本能够提供脚本(目前仅供内部使用),用以评估 FLOP 数。
以下为部分应用的 FLOP 数验证汇总。
- 误差幅度主要表现为参考数和采用英特尔 SDE 评估的 FLOP 数之间的数量差。
- 造成差异的主要原因包括理论评估与实际代码生成之间的差别,以 FLOP 计算的指令等等。我们未对此差异进行深入的研究。
- 不过大家会发现,这种误差幅度非常小。
工作负载 | 参考 FLOP (来自于 NERSC) | MPI 等级 | FLOP 数 (使用英特尔® SDE 计算) | 误差幅度 |
---|---|---|---|---|
MiniFE | 5.05435E+12 | 144 | 5.18039E+12 | 1.03 |
miniGhost | 6.55500E+12 | 96 | 6.85624E+12 | 1.05 |
AMG | 1.30418E+12 | 96 | 1.43311E+12 | 1.10 |
UMT | 1.30211E+13 | 96 | 1.38806E+13 | 1.07 |
脚注:
屏蔽: 甚至在英特尔® AVX/AVX2 (IvyBridge/Haswell) 中,编译器也借助混合等特性在内部支持“屏蔽”。 因此,条件性矢量化循环中将会有未使用的计算(例如,编译器计算真假分支,将两者加以混合后丢弃未使用的部分)。 这意味着 FLOP 会将有用计算估计过高。 屏蔽版 (KNL/SKL) 可能更加准确,因为掩码的显示数比较精确(假设编译器在所有场合均使用掩码)。