在i7上访问“原始”寄存器时是否存在瓶颈?

时间:2019-03-17 02:48:38

标签: performance optimization x86 intel cpu-architecture

简短版本:

在Intel i7上,访问不存在的“原始”寄存器(eaxebxecxedx)存在某种瓶颈在“新”寄存器中(r8dr9d等)?我正在计时一些代码,如果我尝试并行运行三个添加指令,则只要三个添加指令中只有两个引用“原始”寄存器(例如,我使用{ {1}},eaxebx)。如果我尝试使用三个“原始”寄存器,则CPI最高约为0.4。我在i7-3770和i7-4790上都观察到了。

详细信息:

我试图为我的计算机体系结构课程开发一个新的(希望很有趣)实验室。他们的目标是在Intel i7处理器上计时一些汇编代码的时间,并观察诸如(a)处理器的吞吐量和(b)数据依赖性的后果之类的情况。

当我尝试编写一些显示平均CPI为0.33的汇编代码(即,表明CPU可以保持每个周期3条指令的吞吐量)时,我发现只有在以下两种情况下,这才有可能三个指令访问“原始”通用寄​​存器。

实验设置

这是实验的基本概述:使用r9d对几千条指令的时间段进行计时,然后将“周期数”与定时指令的数量作图,以估计吞吐量。例如,在循环内运行此代码

rdtsc

允许我们报告运行 mov $0, %eax cpuid rdtsc movl %eax, %r12d addl $1, %eax addl $1, %eax # the line above is copied "n" times # (I use a ruby script to generate this part of the assembly) addl $1, %eax rdtsc subl %r12d, %eax n指令序列所需的时间(以参考周期为单位)。 (上面的代码段是一个较长的程序的一部分,该程序重复多次测量,抛出前几千次试验,并报告最低和/或最常见的结果。)

有意义的结果

当我对单个寄存器进行一系列加法运算时,我得到了预期的结果:

addl

将参考周期转换为(估计的)实际周期后,处理器平均每个周期大约一条指令。这是有道理的,因为每个定时指令都依赖于前一条指令,从而防止并行执行。请注意,我们在结束instructions elapsed reference ref cycles estimated actual actual cycles between rdtsc cycles per instruction cycles per instruction 200 145 0.72 169 0.84 300 220 0.73 256 0.85 400 314 0.79 365 0.91 500 408 0.82 474 0.95 600 483 0.81 562 0.94 700 577 0.82 671 0.96 800 652 0.81 758 0.95 900 746 0.83 867 0.96 1000 840 0.84 977 0.98 1100 915 0.83 1064 0.97 1200 1009 0.84 1173 0.98 ........................................................................ 3500 3019 0.86 3510 1.00 3600 3094 0.86 3598 1.00 3700 3188 0.86 3707 1.00 3800 3282 0.86 3816 1.00 3900 3357 0.86 3903 1.00 4000 3451 0.86 4013 1.00 之前不会发出序列化指令。结果,当我们“停止”计时器时,最后几十个计时指令尚未完成。因此,该表的前几行的CPI人为地降低了。随着指令数量的增加,这种“计数不足”的影响限制为零。

如果我们修改定时代码以在rdtsceax的加法之间交替,我们还将得到预期的结果:CPI趋于0.5:

ebx

问题:尝试并行运行3条指令时,我使用哪个寄存器有什么重要性?

当我尝试同时对 mov $0, %eax cpuid rdtsc movl %eax, %r12d addl $1, %eax addl $1, %ebx addl $1, %eax addl $1, %ebx # the pair of lines above are copied until there are `n` lines total being timed addl $1, %eax addl $1, %ebx rdtsc subl %r12d, %eax instructions elapsed reference ref cycles estimated actual actual cycles between rdtsc cycles per instruction cycles per instruction 1000 432 0.43 502 0.50 1200 510 0.42 593 0.49 1400 601 0.43 699 0.50 1600 695 0.43 808 0.51 1800 773 0.43 899 0.50 2000 864 0.43 1005 0.50 2200 955 0.43 1110 0.50 eaxebx进行加法运算时,CPI高于预期的.33:

ecx

但是,如果我使用 mov $0, %eax cpuid rdtsc movl %eax, %r12d addl $1, %eax addl $1, %ebx addl $1, %ecx addl $1, %eax addl $1, %ebx addl $1, %ecx # the group of lines above are copied until there are `n` lines total being timed addl $1, %eax addl $1, %ebx addl $1, %ecx rdtsc subl %r12d, %eax instructions elapsed reference ref cycles estimated actual actual cycles between rdtsc cycles per instruction cycles per instruction 1200 408 0.34 474 0.40 1500 492 0.33 572 0.38 1800 595 0.33 692 0.38 2100 698 0.33 812 0.39 2400 782 0.33 909 0.38 2700 885 0.33 1029 0.38 3000 988 0.33 1149 0.38 3300 1091 0.33 1269 0.38 3600 1178 0.33 1370 0.38 r9dr10d,则会得到预期的结果:

r11d

实际上,只要三个寄存器中的最多两个来自集合instructions elapsed reference ref cycles estimated actual actual cycles between rdtsc cycles per instruction cycles per instruction 1200 350 0.29 407 0.34 1500 444 0.30 516 0.34 1800 519 0.29 603 0.34 2100 613 0.29 713 0.34 2400 707 0.29 822 0.34 2700 782 0.29 909 0.34 3000 876 0.29 1019 0.34 eaxebxecx,我就能得到预期的结果。这是为什么?知道瓶颈是问题,解码,寄存器重命名还是退出?

我在i7-3770和i7-4790上都观察到了这种行为。物有所值:Ryzen 7和i5-6500的CPI始终为.38到.40,无论使用什么寄存器。


代码

对于那些好奇的人,这是我使用的代码模板:

edx

0 个答案:

没有答案