【问题标题】:Understanding Linux perf FP counters and computation of FLOPS in a C++ program了解 Linux perf FP 计数器和 C++ 程序中的 FLOPS 计算
【发布时间】:2021-10-17 18:07:41
【问题描述】:

我正在尝试测量在 C++ 程序 (FLOPS) 中执行的计算次数。我使用的是基于 Broadwell 的 CPU 而不是 GPU。我尝试了以下命令,其中包含了我找到的所有与 FP 相关的事件。

perf stat -e fp_arith_inst_retired.128b_packed_double,fp_arith_inst_retired.128b_packed_single,fp_arith_inst_retired.256b_packed_double,fp_arith_inst_retired.256b_packed_single,fp_arith_inst_retired.double,fp_arith_inst_retired.packed,fp_arith_inst_retired.scalar,fp_arith_inst_retired.scalar_double,fp_arith_inst_retired.scalar_single,fp_arith_inst_retired.single,inst_retired.x87 ./test_exe

我得到的东西如下:

 Performance counter stats for './test_exe':

                 0      fp_arith_inst_retired.128b_packed_double    (36.36%)
                 0      fp_arith_inst_retired.128b_packed_single     (36.36%)
                 0      fp_arith_inst_retired.256b_packed_double     (36.37%)
                 0      fp_arith_inst_retired.256b_packed_single     (36.37%)
     4,520,439,602      fp_arith_inst_retired.double     (36.37%)
                 0      fp_arith_inst_retired.packed     (36.36%)
     4,501,385,966      fp_arith_inst_retired.scalar     (36.36%)
     4,493,140,957      fp_arith_inst_retired.scalar_double     (36.37%)
                 0      fp_arith_inst_retired.scalar_single     (36.36%)
                 0      fp_arith_inst_retired.single     (36.36%)
        82,309,806      inst_retired.x87              (36.36%)

      65.861043789 seconds time elapsed

      65.692904000 seconds user
       0.164997000 seconds sys

问题:

  1. 虽然C++程序是一个大项目,但我没有使用任何SSE/AVX指令。我不熟悉 SSE/AVX 指令集。该项目只是由“普通” C++编写的。为什么它包含许多fp_arith_inst_retired.doublefp_arith_inst_retired.scalarfp_arith_inst_retired.scalar_double?这些计数器与 SSE/AVX 计算有关,对吧?
  2. 括号中的百分比是什么意思?比如(36.37%)
  3. 如何根据 perf 结果计算 C++ 程序中的 FLOPS?

谢谢。

【问题讨论】:

    标签: c++ linux profiling perf flops


    【解决方案1】:

    C++ 编译器在 x86-64 上进行 FP 数学运算的正常方法是使用 SSE 指令的标量版本,例如addsd xmm0, [rdi] (https://www.felixcloutier.com/x86/addsd)。只有旧版 32 位版本默认使用 x87 FPU 进行标量数学运算。

    如果您的编译器无法自动矢量化任何内容(例如,您没有使用 g++ -O3 -march=native),并且您所做的唯一数学运算是使用 double 而不是 float,那么所有数学运算将是使用 scalar-double 指令完成。

    每条此类指令都将被fp_arith_inst_retired.double.scalar.scalar-double 事件计数。它们重叠,基本上是同一事件的子过滤器。 (FMA 操作算作两个,即使它们仍然只有一条指令,所以这些是 FLOP 计数,而不是微指令或指令)。

    所以你有4,493,140,957 FLOPs 超过65.86 秒。
    4493140957 / 65.86 / 1e9 ~= 0.0682 GFLOP/s,即非常低。

    如果您对 128b_packed_double 有任何计数,则将其乘以 2。如 perf list 描述中所述:“每个计数代表 2 个计算操作,每个元素一个计算操作 " 因为一个 128 位向量包含两个 64 位 double 元素。所以这个偶数的每个计数都是 2 FLOPs。对于其他人类似,请遵循perf list 输出中描述的比例因子,例如256b_packed_single 乘以 8。

    因此,您确实需要按类型和宽度分隔 SIMD 事件,但您可以只查看 .scalar 而不区分单数和双数。

    另见FLOP measurementFLOPS in Python using a Haswell CPU (Intel Core Processor (Haswell, no TSX)) 的副本之一,链接到您的previous question


    (36.37%) 是在硬件计数器上编程的总时间的多少。您使用的事件多于计数器,因此 perf 为您多路复用它们,每隔一段时间交换一次,并根据该统计采样进行推断,以估计运行时的总数。见Perf tool stat output: multiplex and scaling of "cycles"

    您可以通过省略给定构建中为零的事件来获得非零非冗余事件的准确计数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-02-05
      • 2012-09-21
      • 1970-01-01
      • 2012-05-18
      • 2017-03-24
      相关资源
      最近更新 更多