我在试着理解为什么一些简单的环路会以这样的速度运行
第一种情况:
L1:
add rax, rcx # (1)
add rcx, 1 # (2)
cmp rcx, 4096 # (3)
jl L1
根据IACA,吞吐量是1个周期,瓶颈是端口1,05。我不明白为什么它是1 cylce。毕竟我们有两个循环承载的依赖关系:
(1) -> (1) ( Latancy is 1)
(2) -> (2), (2) -> (1), (2) -> (3) (Latency is 1 + 1 + 1).
而且这种Latency是循环进行的,所以它应该会减慢我们的迭代。
Throughput Analysis Report
--------------------------
Block Throughput: 1.00 Cycles Throughput Bottleneck: Port0, Port1, Port5
Port Binding In Cycles Per Iteration:
-------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 |
-------------------------------------------------------------------------
| Cycles | 1.0 0.0 | 1.0 | 0.0 0.0 | 0.0 0.0 | 0.0 | 1.0 |
-------------------------------------------------------------------------
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | |
---------------------------------------------------------------------
| 1 | 1.0 | | | | | | CP | add rax, rcx
| 1 | | 1.0 | | | | | CP | add rcx, 0x1
| 1 | | | | | | 1.0 | CP | cmp rcx, 0x1000
| 0F | | | | | | | | jl 0xfffffffffffffff2
Total Num Of Uops: 3
第二种情况:
L1:
add rax, rcx
add rcx, 1
add rbx, rcx
cmp rcx, 4096
jl L1
Block Throughput: 1.65 Cycles Throughput Bottleneck: InterIteration
Port Binding In Cycles Per Iteration:
-------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 |
-------------------------------------------------------------------------
| Cycles | 1.4 0.0 | 1.4 | 0.0 0.0 | 0.0 0.0 | 0.0 | 1.3 |
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | |
---------------------------------------------------------------------
| 1 | 0.6 | 0.3 | | | | | | add rax, rcx
| 1 | 0.3 | 0.6 | | | | | CP | add rcx, 0x1
| 1 | 0.3 | 0.3 | | | | 0.3 | CP | add rbx, rcx
| 1 | | | | | | 1.0 | CP | cmp rcx, 0x1000
| 0F | | | | | | | | jl 0xffffffffffffffef
我更不明白为什么吞吐量是1.65。
在第一个循环中,有两条dep链,一条用于rax,另一条用于rcx。
add rax, rcx # depends on rax and rcx from the previous iteration, produces rax for the next iteration
add rcx, 1 # latency = 1
add rcx,1
的2周期延迟dep链-
在任何给定的迭代中,只需要前一个迭代的结果就可以生成此迭代的结果。迭代中没有循环携带的依赖项,只有在迭代之间。
正如我几天前在回答您的问题时所解释的,cmp/jcc不是环载dep链的一部分。
如果cmov
或setcc
读取它生成的标志输出,则cmp
仅是dep链的一部分。控制依赖关系是预测的,而不是等待类似的数据依赖关系。
实际上,在我的E6600(第一代Core2,我目前没有SnB可用)上:
; Linux initializes most registers to zero on process startup, and I'm lazy so I depended on this for this one-off test. In real code, I'd xor-zero ecx
global _start
_start:
L1:
add eax, ecx ; (1)
add ecx, 1 ; (2)
cmp ecx, 0x80000000 ; (3)
jb L1 ; can fuse with cmp on Core2 (in 32bit mode)
mov eax, 1
int 0x80
我将其移植到32位,因为Core2只能在32位模式下进行宏融合,并使用了jb,因为Core2只能对无符号分支条件进行宏融合。我使用了一个大的循环计数器,所以我不需要在此之外再使用一个循环。(IDK为什么选择像4096这样的小循环计数。你确定你没有从短循环之外的其他东西中测量额外的开销吗?)
$ yasm -Worphan-labels -gdwarf2 -felf tinyloop.asm && ld -m elf_i386 -o tinyloop tinyloop.o
$ perf stat -e task-clock,cycles,instructions,branches ./tinyloop
Performance counter stats for './tinyloop':
897.994122 task-clock (msec) # 0.993 CPUs utilized
2,152,571,449 cycles # 2.397 GHz
8,591,925,034 instructions # 3.99 insns per cycle
2,147,844,593 branches # 2391.825 M/sec
0.904020721 seconds time elapsed
因此,它以每周期3.99 INSN的速度运行,这意味着每周期约有一次迭代。
如果你的Ivybridge运行的代码速度只有你的一半,我会感到惊讶。更新:根据聊天中的讨论,是的,似乎IVB实际上只获得2.14 IPC。(每1.87c迭代一次)。将添加rax、rcx更改为添加rax、rbx或其他内容,以消除上一次迭代对循环计数器的依赖性,从而将吞吐量提高到3.8 IPC(每1.05c迭代一次)。我不明白为什么会这样。
对于一个不依赖于宏融合的类似循环,(add
/inc-ecx
/jnz
)我还可以每1c进行一次迭代。(每个周期2.99 INSN)。
然而,在同样读取ecx的循环中有第四个insn会大大降低速度。Core2可以每个时钟发出4个UOP,即使(像SnB/IvB)它只有三个ALU端口。(很多代码都包含内存UOP,因此这是有意义的。)
add eax, ecx ; changing this to add eax,ebx helps when there are 4 non-fusing insns in the loop
; add edx, ecx ; slows us down to 1.34 IPC, or one iter per 3c
; add edx, ebx ; only slows us to 2.28 IPC, or one iter per 1.75c
; with neither: 3 IPC, or one iter per 1c
inc ecx
jnz L1 # loops 2^32 times, doesn't macro-fuse on Core2
我预计仍将以3 IPC运行,或每4/3=1.333c运行一台iter。然而,前SnB CPU有更多的瓶颈,如ROB读取和寄存器读取瓶颈。SnB切换到物理寄存器文件消除了这些减速。
在您的第二个循环中,IDK为什么它没有在每1.333c运行一次迭代。insn更新rbx
直到该迭代的其他指令之后才能运行,但这就是乱序执行的目的。您确定它与每1.85个周期一次迭代一样慢吗?您使用perf
进行了测量,以获得足够高的计数以获得有意义的数据?(rdtsc
周期计数不准确,除非您禁用turbo和频率缩放,但perf计数器仍然计算实际的核心周期)。
我不希望它与
L1:
add rax, rcx
add rbx, rcx # before/after inc rcx shouldn't matter because of out-of-order execution
add rcx, 1
cmp rcx, 4096
jl L1
问题内容: 因此,当我运行此代码时,我的JFrame变得无响应。我设法将其追溯到gameLoop()下的while循环。无论使用其中调用Thread.sleep()的delay(1000 / FRAMERATE),它都不允许键或鼠标侦听器执行其工作。 下面的完整代码,gameLoop()中存在问题 如果很重要,程序将从此处开始,然后转到Game类 可能无关紧要,但这是github存储库的插件htt
如何在不停止主GUI线程的情况下停止循环?(线程。睡眠(1000)未工作)
问题内容: 我正在使用带有node_redis的Node.js,并遍历一个对象并在Redis中查找数据,然后返回结果。 我有这样的设置: 问题在于,它会在完成对redis的调用之前循环通过。因此,在实际更新总值之前,将调用回调。由于延迟,它似乎也跳过了一些项目。 有没有更好的方法来解决这个问题? 谢谢! 编辑: 好的,所以我这样更新了它: 这似乎可行,它在适当的时间触发了回调,但是似乎只有最后一个
问题内容: 我想在循环内添加延迟/睡眠: 我这样尝试过: 只有第一种情况是正确的:显示后,它将等待3秒钟,然后显示,但随后将不断重复。 我想要的是在显示3秒之后显示出来,然后它需要第二次等待3秒,依此类推。 问题答案: 该函数是非阻塞的,将立即返回。因此,您的循环将非常快速地迭代,并且将快速连续地发起3秒超时触发。这就是为什么您的第一个警报会在3秒钟后弹出,而其余所有警报都将连续不断地出现。 您可
问题内容: 我使用以下代码为基于RotatedTranstion的ImageView创建了动画: 这将产生以下动画: 轮换行动 就像您在动画gif中注意到的那样,动画不是连续的,即在动画周期之间存在很小的延迟(暂停)。 我试图看一下API,但无法弄清楚是什么原因造成了这种延迟以及如何摆脱这种延迟。 问题答案: 每个周期之间的明显停顿是由内插器引起的,默认情况下会使用该插值器(因此它在每个周期的末尾
问题内容: 因此,我将顺序的ajax链接在一起,以按顺序加载URL数组。最初,我使用代替,并且无论哪种方式都可以正常工作- 只要所有网址都存在。但是,由于可能会丢失文件,因此我想对此进行补偿,然后,最后通知用户丢失了哪些文件,以便更轻松地进行纠正。 但是,问题是,在丢失的文件/ 404上,代码会像应执行的那样执行,但随后退出循环,从而阻止了进一步的ajax调用。因此,我认为,我需要某种方式来处理并