代码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):
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
有人可以解释Broadwell上的Code1会发生什么吗? 我的猜测是
然而,在Code1案例中,Broadwell以某种方式使用vpaddd污染了Port1
只有当Port0和Port1已满时,Haswell才能使用Port5 ;
您是否有任何想法通过FMA指令完成Broadwell上的~5000000 clk?
我试图重新排序。 double和qword的相似行为;
我使用的是Windows 8.1和Win 10;
将Code3添加为Marat Dukhan长期VEX的想法;
使用Skylake经验扩展结果表;
上传了VS2015社区+ MASM示例代码here
我尝试使用xmm寄存器而不是ymm(代码4)。 Broadwell的结果相同。
我添加了Code5作为Peter Cordes的想法(将vpaddd替换为其他intructions(vpxor,vpor,vpand,vpandn,vpsubd))。如果新指令不是归零惯用法(vpxor,vpsubd具有相同的寄存器),则结果在BDW上是相同的。使用Code4和Code5更新了示例项目。
我添加了Code6作为Stephen Canon的想法(内存操作数)。结果是~8200000 clks。 使用Code6更新示例项目;
我检查了CPU频率和AIDA64系统稳定性测试的可能性。频率稳定,没有节流迹象;
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
我遵循了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
哈斯韦尔的港口分布接近完美。然后我查了一下 资源停顿计数器(事件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避免这种失速?
Code6发生了变化,正如Peter Cordes引起我的注意,只有vpaddds使用了内存操作数。对HSW和SKL没有影响,BDW变得更糟。
正如Marat Dukhan测量的那样,不仅vpadd / vpsub / vpand / vpandn / vpxor受到了影响,而且还有其他Port5限制性指令,如vmovaps,vblendps,vpermps,vshufps,vbroadcastss;
正如IwillnotexistIdonotexist建议的那样,我尝试了其他操作数。一个成功的修改是Code7,其中所有vpaddds都使用ymm15。这个版本可以生成BDW~5000000 clks,但只是一段时间。在约600万FMA对之后,它达到了通常的~7730000 clks:
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
我尝试将Code7的xmm版本作为Code8。效果类似,但运行时间越长,持续时间越长。我没有发现1.6GHz i5-5250U和3.7GHz i7-5775C之间存在显着差异。
16和17是在禁用超线程的情况下完成的。启用HTT后效果会更差。
答案 0 :(得分:17)
我对你没有任何解释,因为我在Haswell,但我确实有代码可以帮助你或其他人使用Broadwell或Skylake硬件隔离你的问题。如果您可以在您的机器上运行并分享结果,我们可以深入了解您的机器发生了什么。
最近的英特尔酷睿i7处理器有7个性能监视器计数器(PMC),3个固定功能和4个通用处理器,可用于配置代码。固定功能PMC是:
核心:参考时钟周期的比率决定了动态频率缩放的相对加速或减速。
虽然访问这些计数器的软件存在(参见下面的评论),但我不知道它们仍然发现它们不够精细。</ p>
因此,我在过去几天给自己写了一个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();
}
在我的机器上,我得到了以下结果:
> ./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批次的测试是苹果对苹果的比较。cpu_clk_unhalted.core_clk/(10.0*cpu_clk_unhalted.ref_xclk)
也不到3 GHz。uops_issued.any
:发出的指令数约为17B,但发出的指令数约为16B。这是因为循环控制的两个指令是融合在一起的;好兆头。此外,在5.3B(大约25%的时间)内大约1.3B时钟周期,没有发布uop,而其余时间(4B时钟周期)接近全部,一次发出4 uop。uops_executed_port.port_[0-7]
:端口饱和度。我们身体健康。在融合后的16B uop中,端口0,1和5吃了5B超过5.3B周期(这意味着它们最佳分布:Float,float,int),Port 6 ate 1B(融合的dec-branch op)和端口2,3,4和7相比之下可以忽略不计。resource_stalls
:发生了1.3B,其中2/3是由于保留站(RS)而另外三分之一是由于未知原因造成的。uops_retired.all
和inst_retired.all
上进行比较而建立的累积分布,我们知道我们将在60%的时间内退休4次uops,0%uops 13%的时间和2次uop其余当时,其他数额可以忽略不计。*idq*
次):IDQ很少能阻止我们。lsd
:循环流检测器正在运行;从它那里向前端供应了近16B的熔合微珠。ild
:指令长度解码不是瓶颈,也不会遇到单个长度更改前缀。br_inst_exec/br_misp_exec
:分支错误预测是一个可以忽略不计的问题。icache.misses
:可忽略不计。fp_assist
:可忽略不计。没有遇到异常。 (我相信没有DAZ denormals-are-zero冲洗,他们需要一个协助,这应该在这里注册)因此,在英特尔Haswell上,它一帆风顺。如果你可以在你的机器上运行我的套件,那就太好了。
make
内核模块。nmi_watchdog=0 modprobe.blacklist=iTCO_wdt,iTCO_vendor_support
重新启动计算机。否则,NMI监管机构将篡改无线核心周期计数器。insmod perfcount.ko
模块。 dmesg | tail -n 10
应该说它成功加载并说有3个Ff计数器和4个Gp计数器,否则就说明没有这样做了。perfcountdemo.c
,尝试更改限制亲缘关系的核心pfcPinThread()
。答案 1 :(得分:11)
更新:以前的版本包含6条VPADDD
条指令(问题中为5条),额外的VPADDD
导致Broadwell不平衡。修复后,Haswell,Broadwell和Skylake向端口0,1和5发出几乎相同数量的uop。
没有端口污染,但是uop被安排在次优,大多数uops在Broadwell上进入端口5,并且在端口0和1饱和之前成为瓶颈。
为了演示正在发生的事情,我建议(ab)使用PeachPy.IO上的演示:
在Google Chrome中打开www.peachpy.io(在其他浏览器中无法使用)。
使用下面的代码替换默认代码(实现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()
我在不同的微体系结构上有许多机器作为PeachPy.io的后端。选择Intel Haswell,Intel Broadwell或Intel Skylake并按“Quick Run”。系统将编译您的代码,将其上载到服务器,并可视化执行期间收集的性能计数器。
以下是Intel Haswell上执行端口的uops分布: