36
  • 代码1:

    vzeroall
    mov             rcx, 1000000
    startLabel1:
    vfmadd231ps     ymm0, ymm0, ymm0
    vfmadd231ps     ymm1, ymm1, ymm1
    vfmadd231ps     ymm2, ymm2, ymm2
    vfmadd231ps     ymm3, ymm3, ymm3
    vfmadd231ps     ymm4, ymm4, ymm4
    vfmadd231ps     ymm5, ymm5, ymm5
    vfmadd231ps     ymm6, ymm6, ymm6
    vfmadd231ps     ymm7, ymm7, ymm7
    vfmadd231ps     ymm8, ymm8, ymm8
    vfmadd231ps     ymm9, ymm9, ymm9
    vpaddd          ymm10, ymm10, ymm10
    vpaddd          ymm11, ymm11, ymm11
    vpaddd          ymm12, ymm12, ymm12
    vpaddd          ymm13, ymm13, ymm13
    vpaddd          ymm14, ymm14, ymm14
    dec             rcx
    jnz             startLabel1
    
  • 代码2:

    vzeroall
    mov             rcx, 1000000
    startLabel2:
    vmulps          ymm0, ymm0, ymm0
    vmulps          ymm1, ymm1, ymm1
    vmulps          ymm2, ymm2, ymm2
    vmulps          ymm3, ymm3, ymm3
    vmulps          ymm4, ymm4, ymm4
    vmulps          ymm5, ymm5, ymm5
    vmulps          ymm6, ymm6, ymm6
    vmulps          ymm7, ymm7, ymm7
    vmulps          ymm8, ymm8, ymm8
    vmulps          ymm9, ymm9, ymm9
    vpaddd          ymm10, ymm10, ymm10
    vpaddd          ymm11, ymm11, ymm11
    vpaddd          ymm12, ymm12, ymm12
    vpaddd          ymm13, ymm13, ymm13
    vpaddd          ymm14, ymm14, ymm14
    dec             rcx
    jnz             startLabel2
    
  • Code3(与 Code2 相同,但具有长 VEX 前缀):

    vzeroall
    mov             rcx, 1000000
    startLabel3:
    byte            0c4h, 0c1h, 07ch, 059h, 0c0h ;long VEX form vmulps ymm0, ymm0, ymm0
    byte            0c4h, 0c1h, 074h, 059h, 0c9h ;long VEX form vmulps ymm1, ymm1, ymm1
    byte            0c4h, 0c1h, 06ch, 059h, 0d2h ;long VEX form vmulps ymm2, ymm2, ymm2
    byte            0c4h, 0c1h, 06ch, 059h, 0dbh ;long VEX form vmulps ymm3, ymm3, ymm3
    byte            0c4h, 0c1h, 05ch, 059h, 0e4h ;long VEX form vmulps ymm4, ymm4, ymm4
    byte            0c4h, 0c1h, 054h, 059h, 0edh ;long VEX form vmulps ymm5, ymm5, ymm5
    byte            0c4h, 0c1h, 04ch, 059h, 0f6h ;long VEX form vmulps ymm6, ymm6, ymm6
    byte            0c4h, 0c1h, 044h, 059h, 0ffh ;long VEX form vmulps ymm7, ymm7, ymm7
    vmulps          ymm8, ymm8, ymm8
    vmulps          ymm9, ymm9, ymm9
    vpaddd          ymm10, ymm10, ymm10
    vpaddd          ymm11, ymm11, ymm11
    vpaddd          ymm12, ymm12, ymm12
    vpaddd          ymm13, ymm13, ymm13
    vpaddd          ymm14, ymm14, ymm14
    dec             rcx
    jnz             startLabel3
    
  • Code4(与 Code1 相同,但带有 xmm 寄存器):

    vzeroall
    mov             rcx, 1000000
    startLabel4:
    vfmadd231ps     xmm0, xmm0, xmm0
    vfmadd231ps     xmm1, xmm1, xmm1
    vfmadd231ps     xmm2, xmm2, xmm2
    vfmadd231ps     xmm3, xmm3, xmm3
    vfmadd231ps     xmm4, xmm4, xmm4
    vfmadd231ps     xmm5, xmm5, xmm5
    vfmadd231ps     xmm6, xmm6, xmm6
    vfmadd231ps     xmm7, xmm7, xmm7
    vfmadd231ps     xmm8, xmm8, xmm8
    vfmadd231ps     xmm9, xmm9, xmm9
    vpaddd          xmm10, xmm10, xmm10
    vpaddd          xmm11, xmm11, xmm11
    vpaddd          xmm12, xmm12, xmm12
    vpaddd          xmm13, xmm13, xmm13
    vpaddd          xmm14, xmm14, xmm14
    dec             rcx
    jnz             startLabel4
    
  • Code5(与 Code1 相同,但具有非归零 vpsubd`s):

    vzeroall
    mov             rcx, 1000000
    startLabel5:
    vfmadd231ps     ymm0, ymm0, ymm0
    vfmadd231ps     ymm1, ymm1, ymm1
    vfmadd231ps     ymm2, ymm2, ymm2
    vfmadd231ps     ymm3, ymm3, ymm3
    vfmadd231ps     ymm4, ymm4, ymm4
    vfmadd231ps     ymm5, ymm5, ymm5
    vfmadd231ps     ymm6, ymm6, ymm6
    vfmadd231ps     ymm7, ymm7, ymm7
    vfmadd231ps     ymm8, ymm8, ymm8
    vfmadd231ps     ymm9, ymm9, ymm9
    vpsubd          ymm10, ymm10, ymm11
    vpsubd          ymm11, ymm11, ymm12
    vpsubd          ymm12, ymm12, ymm13
    vpsubd          ymm13, ymm13, ymm14
    vpsubd          ymm14, ymm14, ymm10
    dec             rcx
    jnz             startLabel5
    
  • Code6b:(已修订,仅用于 vpaddds 的内存操作数)

    vzeroall
    mov             rcx, 1000000
    startLabel6:
    vfmadd231ps     ymm0, ymm0, ymm0
    vfmadd231ps     ymm1, ymm1, ymm1
    vfmadd231ps     ymm2, ymm2, ymm2
    vfmadd231ps     ymm3, ymm3, ymm3
    vfmadd231ps     ymm4, ymm4, ymm4
    vfmadd231ps     ymm5, ymm5, ymm5
    vfmadd231ps     ymm6, ymm6, ymm6
    vfmadd231ps     ymm7, ymm7, ymm7
    vfmadd231ps     ymm8, ymm8, ymm8
    vfmadd231ps     ymm9, ymm9, ymm9
    vpaddd          ymm10, ymm10, [mem]
    vpaddd          ymm11, ymm11, [mem]
    vpaddd          ymm12, ymm12, [mem]
    vpaddd          ymm13, ymm13, [mem]
    vpaddd          ymm14, ymm14, [mem]
    dec             rcx
    jnz             startLabel6
    
  • Code7:(与 Code1 相同,但 vpaddds 使用 ymm15)

    vzeroall
    mov             rcx, 1000000
    startLabel7:
    vfmadd231ps     ymm0, ymm0, ymm0
    vfmadd231ps     ymm1, ymm1, ymm1
    vfmadd231ps     ymm2, ymm2, ymm2
    vfmadd231ps     ymm3, ymm3, ymm3
    vfmadd231ps     ymm4, ymm4, ymm4
    vfmadd231ps     ymm5, ymm5, ymm5
    vfmadd231ps     ymm6, ymm6, ymm6
    vfmadd231ps     ymm7, ymm7, ymm7
    vfmadd231ps     ymm8, ymm8, ymm8
    vfmadd231ps     ymm9, ymm9, ymm9
    vpaddd          ymm10, ymm15, ymm15
    vpaddd          ymm11, ymm15, ymm15
    vpaddd          ymm12, ymm15, ymm15
    vpaddd          ymm13, ymm15, ymm15
    vpaddd          ymm14, ymm15, ymm15
    dec             rcx
    jnz             startLabel7
    
  • Code8:(与 Code7 相同,但使用 xmm 而不是 ymm)

    vzeroall
    mov             rcx, 1000000
    startLabel8:
    vfmadd231ps     xmm0, ymm0, ymm0
    vfmadd231ps     xmm1, xmm1, xmm1
    vfmadd231ps     xmm2, xmm2, xmm2
    vfmadd231ps     xmm3, xmm3, xmm3
    vfmadd231ps     xmm4, xmm4, xmm4
    vfmadd231ps     xmm5, xmm5, xmm5
    vfmadd231ps     xmm6, xmm6, xmm6
    vfmadd231ps     xmm7, xmm7, xmm7
    vfmadd231ps     xmm8, xmm8, xmm8
    vfmadd231ps     xmm9, xmm9, xmm9
    vpaddd          xmm10, xmm15, xmm15
    vpaddd          xmm11, xmm15, xmm15
    vpaddd          xmm12, xmm15, xmm15
    vpaddd          xmm13, xmm15, xmm15
    vpaddd          xmm14, xmm15, xmm15
    dec             rcx
    jnz             startLabel8
    

在禁用 Turbo 和 C1E 的情况下测量的 TSC 时钟:

          Haswell        Broadwell                  Skylake

CPUID     306C3, 40661   306D4, 40671               506E3

Code1     ~5000000        ~7730000 ->~54% slower    ~5500000 ->~10% slower
Code2     ~5000000       ~5000000                  ~5000000
Code3     ~6000000       ~5000000                  ~5000000
Code4     ~5000000       ~7730000                  ~5500000
Code5     ~5000000       ~7730000                  ~5500000
Code6b    ~5000000       ~8380000                  ~5500000
Code7     ~5000000       ~5000000                  ~5000000
Code8     ~5000000       ~5000000                  ~5000000 
  1. 有人可以解释一下在 Broadwell 上 Code1 会发生什么吗? 我的猜测是 Broadwell 在 Code1 的情况下以某种方式用 vpaddds 污染了 Port1,但是 Haswell 只有在 Port0 和 Port1 已满时才能使用 Port5

  2. 你有什么想法用 FMA 指令完成 Broadwell 上的 ~5000000 clk 吗?

  3. 我试图重新排序。double 和 qword 的类似行为;

  4. 我使用的是 Windows 8.1 和 Win 10;

    更新:


  5. 将 Code3 作为 Marat Dukhan 的想法添加了长 VEX;

  6. 使用 Skylake 体验扩展了结果表;

  7. 在这里上传了一个 VS2015 Community + MASM 示例代码

    更新2:


  8. 我尝试使用 xmm 寄存器而不是 ymm(代码 4)。在 Broadwell 上的结果相同。

    更新3:


  9. 我将 Code5 添加为 Peter Cordes 的想法(将 vpaddd 替换为其他指令(vpxor、vpor、vpand、vpandn、vpsubd))。如果新指令不是归零习惯用法(vpxor, vpsubd with same register),则在 BDW 上的结果相同。使用 Code4 和 Code5 更新的示例项目。

    更新4:


  10. 我将 Code6 添加为 Stephen Canon 的想法(内存操作数)。结果是 ~8200000 时钟。使用 Code6 更新的示例项目;

  11. 我用 AIDA64 的系统稳定性测试检查了 CPU 频率和可能的节流。频率稳定,无节流迹象;

    在此处输入图像描述

  12. Intel IACA 2.1 Haswell 吞吐量分析:

    Intel(R) Architecture Code Analyzer Version - 2.1
    Analyzed File - Assembly.obj
    Binary Format - 64Bit
    Architecture  - HSW
    Analysis Type - Throughput
    
    Throughput Analysis Report
    --------------------------
    Block Throughput: 5.10 Cycles       Throughput Bottleneck: Port0, Port1, Port5
    
    Port Binding In Cycles Per Iteration:
    ---------------------------------------------------------------------------------------
    |  Port  |  0   -  DV  |  1   |  2   -  D   |  3   -  D   |  4   |  5   |  6   |  7   |
    ---------------------------------------------------------------------------------------
    | Cycles | 5.0    0.0  | 5.0  | 0.0    0.0  | 0.0    0.0  | 0.0  | 5.0  | 1.0  | 0.0  |
    ---------------------------------------------------------------------------------------
    
    | Num Of |                    Ports pressure in cycles                     |    |
    |  Uops  |  0  - DV  |  1  |  2  -  D  |  3  -  D  |  4  |  5  |  6  |  7  |    |
    ---------------------------------------------------------------------------------
    |   1    | 1.0       |     |           |           |     |     |     |     | CP | vfmadd231ps ymm0, ymm0, ymm0
    |   1    |           | 1.0 |           |           |     |     |     |     | CP | vfmadd231ps ymm1, ymm1, ymm1
    |   1    | 1.0       |     |           |           |     |     |     |     | CP | vfmadd231ps ymm2, ymm2, ymm2
    |   1    |           | 1.0 |           |           |     |     |     |     | CP | vfmadd231ps ymm3, ymm3, ymm3
    |   1    | 1.0       |     |           |           |     |     |     |     | CP | vfmadd231ps ymm4, ymm4, ymm4
    |   1    |           | 1.0 |           |           |     |     |     |     | CP | vfmadd231ps ymm5, ymm5, ymm5
    |   1    | 1.0       |     |           |           |     |     |     |     | CP | vfmadd231ps ymm6, ymm6, ymm6
    |   1    |           | 1.0 |           |           |     |     |     |     | CP | vfmadd231ps ymm7, ymm7, ymm7
    |   1    | 1.0       |     |           |           |     |     |     |     | CP | vfmadd231ps ymm8, ymm8, ymm8
    |   1    |           | 1.0 |           |           |     |     |     |     | CP | vfmadd231ps ymm9, ymm9, ymm9
    |   1    |           |     |           |           |     | 1.0 |     |     | CP | vpaddd ymm10, ymm10, ymm10
    |   1    |           |     |           |           |     | 1.0 |     |     | CP | vpaddd ymm11, ymm11, ymm11
    |   1    |           |     |           |           |     | 1.0 |     |     | CP | vpaddd ymm12, ymm12, ymm12
    |   1    |           |     |           |           |     | 1.0 |     |     | CP | vpaddd ymm13, ymm13, ymm13
    |   1    |           |     |           |           |     | 1.0 |     |     | CP | vpaddd ymm14, ymm14, ymm14
    |   1    |           |     |           |           |     |     | 1.0 |     |    | dec rcx
    |   0F   |           |     |           |           |     |     |     |     |    | jnz 0xffffffffffffffaa
    Total Num Of Uops: 16
    
  13. 我按照 jcomeau_ictx 的想法,修改了 Agner Fog 的 testp.zip(2015-12-22 发布)BDW 306D4 上的端口使用情况:

               Clock   Core cyc   Instruct      uop p0     uop p1     uop p5     uop p6 
    Code1:   7734720    7734727   17000001    4983410    5016592    5000001    1000001
    Code2:   5000072    5000072   17000001    5000010    5000014    4999978    1000002
    

    港口分布与 Haswell 上的一样近乎完美。然后我检查了资源停止计数器(事件 0xa2)

              Clock   Core cyc   Instruct      res.stl.   RS stl.    SB stl.    ROB stl.
    Code1:   7736212    7736213   17000001    3736191    3736143          0          0
    Code2:   5000068    5000072   17000001    1000050     999957          0          0
    

    在我看来,来自 RS 摊位的 Code1 和 Code2 差异。来自英特尔 SDM 的评论:“由于没有可用的符合条件的 RS 条目,周期停止。”

    我怎样才能避免使用 FMA 的这种失速?

    更新5:


  14. Code6 发生了变化,正如 Peter Cordes 引起我的注意,只有 vpaddds 使用内存操作数。对 HSW 和 SKL 没有影响,BDW 变得更糟。

  15. 正如 Marat Dukhan 测量的那样,不仅 vpadd/vpsub/vpand/vpandn/vpxor 受到影响,还有其他 Port5 有界指令,如 vmovaps、vblendps、vpermps、vshufps、vbroadcastss;

  16. 正如 IwillnotexistIdonotexist 建议的那样,我尝试了其他操作数。一个成功的修改是 Code7,其中所有 vpaddd 都使用 ymm15。这个版本可以在 BDW 上产生约 5000000 个时钟,但只是一段时间。在约 600 万个 FMA 对之后,它达到通常的约 7730000 个时钟:

    Clock   Core cyc   Instruct   res.stl.   RS stl.     SB stl.    ROB stl.
    5133724    5110723   17000001    1107998     946376          0          0
    6545476    6545482   17000001    2545453          1          0          0
    6545468    6545471   17000001    2545437      90910          0          0
    5000016    5000019   17000001     999992     999992          0          0
    7671620    7617127   17000003    3614464    3363363          0          0
    7737340    7737345   17000001    3737321    3737259          0          0
    7802916    7747108   17000003    3737478    3735919          0          0
    7928784    7796057   17000007    3767962    3676744          0          0
    7941072    7847463   17000003    3781103    3651595          0          0
    7787812    7779151   17000005    3765109    3685600          0          0
    7792524    7738029   17000002    3736858    3736764          0          0
    7736000    7736007   17000001    3735983    3735945          0          0
    
  17. 我尝试了 Code7 的 xmm 版本作为 Code8。效果类似,但运行时间越快,持续时间越长。我没有发现 1.6GHz i5-5250U 和 3.7GHz i7-5775C 之间有显着差异。

  18. 16 和 17 是在禁用超线程的情况下制作的。启用 HTT 后效果会更小。

4

2 回答 2

17

更新

因为我在 Haswell 上,所以我没有任何解释给你,但我确实有代码可以分享,可以帮助你或其他人使用 Broadwell 或 Skylake 硬件隔离你的问题。如果您可以在您的机器上运行它并分享结果,我们可以深入了解您的机器发生了什么。

介绍

最近的英特尔酷睿 i7 处理器有 7 个性能监视器计数器 (PMC)、3 个固定功能和 4 个通用,可用于分析代码。固定功能的 PMC 是:

  • 指令已停用
  • 未停止的核心周期(时钟滴答声,包括 TurboBoost 的影响)
  • 未暂停的参考周期(固定频率时钟滴答)

内核:参考时钟周期的比率决定了动态频率缩放的相对加速或减速。

尽管存在访问这些计数器的软件(请参阅下面的评论),但我不知道它们并且仍然发现它们不够细粒度。

因此,在过去的几天里,我为自己编写了一个 Linux 内核模块,perfcount以授予我对英特尔性能计数器监视器的访问权限,以及一个用户空间测试平台和代码库,用于将 FMA 代码包装在对我的 LKM 的调用中。将遵循有关如何重现我的设置的说明。

我的测试平台源代码如下。它会预热,然后多次运行您的代码,并通过一长串指标对其进行测试。我将您的循环计数更改为 10 亿。因为一次只能对 4 个通用 PMC 进行编程,所以我一次进行 4 个测量。

perfcountdemo.c

/* Includes */
#include "libperfcount.h"
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* Function prototypes */
void code1(void);
void code2(void);
void code3(void);
void code4(void);
void code5(void);

/* Global variables */
void ((*FN_TABLE[])(void)) = {
    code1,
    code2,
    code3,
    code4,
    code5
};


/**
 * Code snippets to bench
 */

void code1(void){
    asm volatile(
    ".intel_syntax noprefix\n\t"
    "vzeroall\n\t"
    "mov             rcx, 1000000000\n\t"
    "LstartLabel1:\n\t"
    "vfmadd231ps     %%ymm0, %%ymm0, %%ymm0\n\t"
    "vfmadd231ps     ymm1, ymm1, ymm1\n\t"
    "vfmadd231ps     ymm2, ymm2, ymm2\n\t"
    "vfmadd231ps     ymm3, ymm3, ymm3\n\t"
    "vfmadd231ps     ymm4, ymm4, ymm4\n\t"
    "vfmadd231ps     ymm5, ymm5, ymm5\n\t"
    "vfmadd231ps     ymm6, ymm6, ymm6\n\t"
    "vfmadd231ps     ymm7, ymm7, ymm7\n\t"
    "vfmadd231ps     ymm8, ymm8, ymm8\n\t"
    "vfmadd231ps     ymm9, ymm9, ymm9\n\t"
    "vpaddd          ymm10, ymm10, ymm10\n\t"
    "vpaddd          ymm11, ymm11, ymm11\n\t"
    "vpaddd          ymm12, ymm12, ymm12\n\t"
    "vpaddd          ymm13, ymm13, ymm13\n\t"
    "vpaddd          ymm14, ymm14, ymm14\n\t"
    "dec             rcx\n\t"
    "jnz             LstartLabel1\n\t"
    ".att_syntax noprefix\n\t"
    : /* No outputs we care about */
    : /* No inputs we care about */
    : "xmm0",  "xmm1",  "xmm2",  "xmm3",  "xmm4",  "xmm5",  "xmm6",  "xmm7",
      "xmm8",  "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
      "rcx",
      "memory"
    );
}
void code2(void){

}
void code3(void){

}
void code4(void){

}
void code5(void){

}



/* Test Schedule */
const char* const SCHEDULE[] = {
    /* Batch */
    "uops_issued.any",
    "uops_issued.any<1",
    "uops_issued.any>=1",
    "uops_issued.any>=2",
    /* Batch */
    "uops_issued.any>=3",
    "uops_issued.any>=4",
    "uops_issued.any>=5",
    "uops_issued.any>=6",
    /* Batch */
    "uops_executed_port.port_0",
    "uops_executed_port.port_1",
    "uops_executed_port.port_2",
    "uops_executed_port.port_3",
    /* Batch */
    "uops_executed_port.port_4",
    "uops_executed_port.port_5",
    "uops_executed_port.port_6",
    "uops_executed_port.port_7",
    /* Batch */
    "resource_stalls.any",
    "resource_stalls.rs",
    "resource_stalls.sb",
    "resource_stalls.rob",
    /* Batch */
    "uops_retired.all",
    "uops_retired.all<1",
    "uops_retired.all>=1",
    "uops_retired.all>=2",
    /* Batch */
    "uops_retired.all>=3",
    "uops_retired.all>=4",
    "uops_retired.all>=5",
    "uops_retired.all>=6",
    /* Batch */
    "inst_retired.any_p",
    "inst_retired.any_p<1",
    "inst_retired.any_p>=1",
    "inst_retired.any_p>=2",
    /* Batch */
    "inst_retired.any_p>=3",
    "inst_retired.any_p>=4",
    "inst_retired.any_p>=5",
    "inst_retired.any_p>=6",
    /* Batch */
    "idq_uops_not_delivered.core",
    "idq_uops_not_delivered.core<1",
    "idq_uops_not_delivered.core>=1",
    "idq_uops_not_delivered.core>=2",
    /* Batch */
    "idq_uops_not_delivered.core>=3",
    "idq_uops_not_delivered.core>=4",
    "rs_events.empty",
    "idq.empty",
    /* Batch */
    "idq.mite_all_uops",
    "idq.mite_all_uops<1",
    "idq.mite_all_uops>=1",
    "idq.mite_all_uops>=2",
    /* Batch */
    "idq.mite_all_uops>=3",
    "idq.mite_all_uops>=4",
    "move_elimination.int_not_eliminated",
    "move_elimination.simd_not_eliminated",
    /* Batch */
    "lsd.uops",
    "lsd.uops<1",
    "lsd.uops>=1",
    "lsd.uops>=2",
    /* Batch */
    "lsd.uops>=3",
    "lsd.uops>=4",
    "ild_stall.lcp",
    "ild_stall.iq_full",
    /* Batch */
    "br_inst_exec.all_branches",
    "br_inst_exec.0x81",
    "br_inst_exec.0x82",
    "icache.misses",
    /* Batch */
    "br_misp_exec.all_branches",
    "br_misp_exec.0x81",
    "br_misp_exec.0x82",
    "fp_assist.any",
    /* Batch */
    "cpu_clk_unhalted.core_clk",
    "cpu_clk_unhalted.ref_xclk",
    "baclears.any"

};
const int NUMCOUNTS = sizeof(SCHEDULE)/sizeof(*SCHEDULE);


/**
 * Main
 */

int main(int argc, char* argv[]){
    int i;

    /**
     * Initialize
     */

    pfcInit();
    if(argc <= 1){
        pfcDumpEvents();
        exit(1);
    }
    pfcPinThread(3);


    /**
     * Arguments are:
     * 
     *     perfcountdemo #codesnippet
     * 
     * There is a schedule of configuration that is followed.
     */

    void (*fn)(void) = FN_TABLE[strtoull(argv[1], NULL, 0)];
    static const uint64_t ZERO_CNT[7] = {0,0,0,0,0,0,0};
    static const uint64_t ZERO_CFG[7] = {0,0,0,0,0,0,0};

    uint64_t cnt[7]                   = {0,0,0,0,0,0,0};
    uint64_t cfg[7]                   = {2,2,2,0,0,0,0};

    /* Warmup */
    for(i=0;i<10;i++){
        fn();
    }

    /* Run master loop */
    for(i=0;i<NUMCOUNTS;i+=4){
        /* Configure counters */
        const char* sched0 = i+0 < NUMCOUNTS ? SCHEDULE[i+0] : "";
        const char* sched1 = i+1 < NUMCOUNTS ? SCHEDULE[i+1] : "";
        const char* sched2 = i+2 < NUMCOUNTS ? SCHEDULE[i+2] : "";
        const char* sched3 = i+3 < NUMCOUNTS ? SCHEDULE[i+3] : "";
        cfg[3] = pfcParseConfig(sched0);
        cfg[4] = pfcParseConfig(sched1);
        cfg[5] = pfcParseConfig(sched2);
        cfg[6] = pfcParseConfig(sched3);

        pfcWrConfigCnts(0, 7, cfg);
        pfcWrCountsCnts(0, 7, ZERO_CNT);
        pfcRdCountsCnts(0, 7, cnt);
        /* ^ Should report 0s, and launch the counters. */
        /************** Hot section **************/
        fn();
        /************ End Hot section ************/
        pfcRdCountsCnts(0, 7, cnt);
        pfcWrConfigCnts(0, 7, ZERO_CFG);
        /* ^ Should clear the counter config and disable them. */

        /**
         * Print the lovely results
         */

        printf("Instructions Issued                : %20llu\n", cnt[0]);
        printf("Unhalted core cycles               : %20llu\n", cnt[1]);
        printf("Unhalted reference cycles          : %20llu\n", cnt[2]);
        printf("%-35s: %20llu\n", sched0, cnt[3]);
        printf("%-35s: %20llu\n", sched1, cnt[4]);
        printf("%-35s: %20llu\n", sched2, cnt[5]);
        printf("%-35s: %20llu\n", sched3, cnt[6]);
    }

    /**
     * Close up shop
     */

    pfcFini();
}

在我的机器上,我得到了以下结果:

哈斯韦尔酷睿 i7-4700MQ

> ./perfcountdemo 0
Instructions Issued                :          17000001807
Unhalted core cycles               :           5305920785
Unhalted reference cycles          :           4245764952
uops_issued.any                    :          16000811079
uops_issued.any<1                  :           1311417889
uops_issued.any>=1                 :           4000292290
uops_issued.any>=2                 :           4000229358
Instructions Issued                :          17000001806
Unhalted core cycles               :           5303822082
Unhalted reference cycles          :           4243345896
uops_issued.any>=3                 :           4000156998
uops_issued.any>=4                 :           4000110067
uops_issued.any>=5                 :                    0
uops_issued.any>=6                 :                    0
Instructions Issued                :          17000001811
Unhalted core cycles               :           5314227923
Unhalted reference cycles          :           4252020624
uops_executed_port.port_0          :           5016261477
uops_executed_port.port_1          :           5036728509
uops_executed_port.port_2          :                 5282
uops_executed_port.port_3          :                12481
Instructions Issued                :          17000001816
Unhalted core cycles               :           5329351248
Unhalted reference cycles          :           4265809728
uops_executed_port.port_4          :                 7087
uops_executed_port.port_5          :           4946019835
uops_executed_port.port_6          :           1000228324
uops_executed_port.port_7          :                 1372
Instructions Issued                :          17000001816
Unhalted core cycles               :           5325153463
Unhalted reference cycles          :           4261060248
resource_stalls.any                :           1322734589
resource_stalls.rs                 :            844250210
resource_stalls.sb                 :                    0
resource_stalls.rob                :                    0
Instructions Issued                :          17000001814
Unhalted core cycles               :           5327823817
Unhalted reference cycles          :           4262914728
uops_retired.all                   :          16000445793
uops_retired.all<1                 :            687284798
uops_retired.all>=1                :           4646263984
uops_retired.all>=2                :           4452324050
Instructions Issued                :          17000001809
Unhalted core cycles               :           5311736558
Unhalted reference cycles          :           4250015688
uops_retired.all>=3                :           3545695253
uops_retired.all>=4                :           3341664653
uops_retired.all>=5                :                 1016
uops_retired.all>=6                :                    1
Instructions Issued                :          17000001871
Unhalted core cycles               :           5477215269
Unhalted reference cycles          :           4383891984
inst_retired.any_p                 :          17000001871
inst_retired.any_p<1               :            891904306
inst_retired.any_p>=1              :           4593972062
inst_retired.any_p>=2              :           4441024510
Instructions Issued                :          17000001835
Unhalted core cycles               :           5377202052
Unhalted reference cycles          :           4302895152
inst_retired.any_p>=3              :           3555852364
inst_retired.any_p>=4              :           3369559466
inst_retired.any_p>=5              :            999980244
inst_retired.any_p>=6              :                    0
Instructions Issued                :          17000001826
Unhalted core cycles               :           5349373678
Unhalted reference cycles          :           4280991912
idq_uops_not_delivered.core        :              1580573
idq_uops_not_delivered.core<1      :           5354931839
idq_uops_not_delivered.core>=1     :               471248
idq_uops_not_delivered.core>=2     :               418625
Instructions Issued                :          17000001808
Unhalted core cycles               :           5309687640
Unhalted reference cycles          :           4248083976
idq_uops_not_delivered.core>=3     :               280800
idq_uops_not_delivered.core>=4     :               247923
rs_events.empty                    :                    0
idq.empty                          :               649944
Instructions Issued                :          17000001838
Unhalted core cycles               :           5392229041
Unhalted reference cycles          :           4315704216
idq.mite_all_uops                  :              2496139
idq.mite_all_uops<1                :           5397877484
idq.mite_all_uops>=1               :               971582
idq.mite_all_uops>=2               :               595973
Instructions Issued                :          17000001822
Unhalted core cycles               :           5347205506
Unhalted reference cycles          :           4278845208
idq.mite_all_uops>=3               :               394011
idq.mite_all_uops>=4               :               335205
move_elimination.int_not_eliminated:                    0
move_elimination.simd_not_eliminated:                    0
Instructions Issued                :          17000001812
Unhalted core cycles               :           5320621549
Unhalted reference cycles          :           4257095280
lsd.uops                           :          15999287982
lsd.uops<1                         :           1326629729
lsd.uops>=1                        :           3999821996
lsd.uops>=2                        :           3999821996
Instructions Issued                :          17000001813
Unhalted core cycles               :           5320533147
Unhalted reference cycles          :           4257105096
lsd.uops>=3                        :           3999823498
lsd.uops>=4                        :           3999823498
ild_stall.lcp                      :                    0
ild_stall.iq_full                  :                 3468
Instructions Issued                :          17000001813
Unhalted core cycles               :           5323278281
Unhalted reference cycles          :           4258969200
br_inst_exec.all_branches          :           1000016626
br_inst_exec.0x81                  :           1000016616
br_inst_exec.0x82                  :                    0
icache.misses                      :                  294
Instructions Issued                :          17000001812
Unhalted core cycles               :           5315098728
Unhalted reference cycles          :           4253082504
br_misp_exec.all_branches          :                    5
br_misp_exec.0x81                  :                    2
br_misp_exec.0x82                  :                    0
fp_assist.any                      :                    0
Instructions Issued                :          17000001819
Unhalted core cycles               :           5338484610
Unhalted reference cycles          :           4271432976
cpu_clk_unhalted.core_clk          :           5338494250
cpu_clk_unhalted.ref_xclk          :            177976806
baclears.any                       :                    1
                                   :                    0

我们可能会看到,在 Haswell 上,一切都很顺利。我将从上面的统计数据中做一些笔记:

  • 发出的指示对我来说非常一致。它总是在附近17000001800,这是一个好兆头:这意味着我们可以很好地估计我们的开销。其他固定功能计数器的同上。它们都匹配得相当好这一事实意味着 4 个批次的测试是苹果对苹果的比较。
  • 核心:参考周期的比率约为 5305920785/4245764952,我们得到的平均频率缩放约为 1.25;这与我的观察结果非常吻合,我的核心频率从 2.4 GHz 上升到 3.0 GHz。cpu_clk_unhalted.core_clk/(10.0*cpu_clk_unhalted.ref_xclk)也给出了不到 3 GHz 的频率。
  • 发出的指令与核心周期的比率给出了 IPC,17000001807/5305920785 ~ 3.20,这也是正确的:每个时钟周期 2 个 FMA+1 VPADDD,持续 4 个时钟周期,每进入的第 5 个时钟周期有 2 个额外的循环控制指令平行。
  • uops_issued.any:发出的指令数约为 17B,但发出的微指令数约为 16B。那是因为循环控制的两条指令融合在一起了。好兆头。此外,在 5.3B(25% 的时间)中,大约 1.3B 时钟周期没有发出微指令,而在其余时间(4B 时钟周期)的几乎全部时间内,一次发出 4 微指令。
  • uops_executed_port.port_[0-7]:端口饱和。我们身体很好。在 16B 融合后的 uop 中,端口 0、1 和 5 在 5.3B 周期内各消耗 5B uop(这意味着它们的分布最佳:分别为 Float、float、int),端口 6 消耗 1B(融合的 dec-branch op) ,相比之下,端口 2、3、4 和 7 的消耗量可以忽略不计。
  • resource_stalls:其中1.3B发生,其中2/3是由于保留站(RS),另外三分之一是未知原因。
  • 根据我们在 和 上进行比较uops_retired.all而建立的累积分布inst_retired.all,我们知道我们将在 60% 的时间内停用 4 微指令,在 13% 的时间停用 0 微指令,在其余时间停用 2 微指令,否则数量可以忽略不计。
  • (无数*idq*次):IDQ 很少支持我们。
  • lsd:循环流检测器正在工作;从它向前端提供了近 16B 个融合的 uop。
  • ild: 指令长度解码不是瓶颈,没有遇到单个变长前缀。
  • br_inst_exec/br_misp_exec: 分支错误预测是一个可以忽略不计的问题。
  • icache.misses: 可以忽略不计。
  • fp_assist: 可以忽略不计。未遇到异常。(我相信如果没有 DAZ 非正规零刷新,他们需要帮助,应该在此处注册)

因此,在 Intel Haswell 上,它一帆风顺。如果你能在你的机器上运行我的套件,那就太好了。

复制说明

  • 规则#1:在对它做任何事情之前检查我所有的代码。永远不要盲目相信互联网上的陌生人。
  • 获取 perfcountdemo.c、libperfcount.clibperfcount.h 将它们放在同一个目录中并一起编译。
  • 抓取perfcount.cMakefile,将它们放在同一目录中,以及make内核模块。
  • 使用 GRUB 引导标志重新引导您的机器nmi_watchdog=0 modprobe.blacklist=iTCO_wdt,iTCO_vendor_support。否则,NMI 看门狗将篡改 unhalted-core-cycle 计数器。
  • insmod perfcount.ko模块。dmesg | tail -n 10应该说它已成功加载并说有 3 个 Ff 计数器和 4 个 Gp 计数器,否则给出未能这样做的原因。
  • 运行我的应用程序,最好在系统的其余部分没有负载时运行。尝试perfcountdemo.c通过将参数更改为 来更改您限制亲和力的核心pfcPinThread()
  • 在此处编辑结果。
于 2015-12-29T17:02:12.633 回答
11

更新:以前的版本包含 6VPADDD条指令(与问题中的 5 条相比),额外VPADDD导致 Broadwell 不平衡。修复后,Haswell、Broadwell 和 Skylake 向端口 0、1 和 5 发出几乎相同数量的微指令。

没有端口污染,但 uops 的调度并不理想,大多数 uops 都流向 Broadwell 的 5 号端口,并在 0 号和 1 号端口饱和之前成为瓶颈。

为了演示发生了什么,我建议(ab)使用PeachPy.IO上的演示:

  1. 在谷歌浏览器中打开 www.peachpy.io(在其他浏览器中无法使用)。

  2. 用下面的代码替换默认代码(实现 SDOT 函数),这实际上是您移植到PeachPy语法的示例:

    n = Argument(size_t)
    x = Argument(ptr(const_float_))
    incx = Argument(size_t)
    y = Argument(ptr(const_float_))
    incy = Argument(size_t)
    
    with Function("sdot", (n, x, incx, y, incy)) as function:
        reg_n = GeneralPurposeRegister64()
        LOAD.ARGUMENT(reg_n, n)
    
        VZEROALL()
    
        with Loop() as loop:
            for i in range(15):
                ymm_i = YMMRegister(i)
                if i < 10:
                    VFMADD231PS(ymm_i, ymm_i, ymm_i)
                else:
                    VPADDD(ymm_i, ymm_i, ymm_i)
            DEC(reg_n)
            JNZ(loop.begin)
    
        RETURN()
    
  3. 我有许多不同微架构上的机器作为 PeachPy.io 的后端。选择 Intel Haswell、Intel Broadwell 或 Intel Skylake,然后按“快速运行”。系统将编译您的代码,将其上传到服务器,并可视化执行期间收集的性能计数器。

  4. 以下是 Intel Haswell 上执行端口上的 uops 分布:

英特尔 Haswell 的端口压力

  1. 这是来自英特尔 Broadwell 的相同情节:

英特尔 Broadwell 的端口压力

  1. 显然,无论 uops 调度程序中的缺陷是什么,它都已在 Intel Skylake 中修复,因为该机器上的端口压力与 Haswell 上的相同。
于 2015-12-31T10:09:40.813 回答