了解 lfence 对具有两个长依赖链的循环的影响,以增加长度

2024-03-02

我正在玩代码这个答案 https://stackoverflow.com/a/50496379/5801661,稍微修改一下:

BITS 64

GLOBAL _start

SECTION .text

_start:
 mov ecx, 1000000

.loop:

 ;T is a symbol defined with the CLI (-DT=...)

 TIMES T imul eax, eax
 lfence
 TIMES T imul edx, edx


 dec ecx
jnz .loop

 mov eax, 60           ;sys_exit
 xor edi, edi
 syscall

如果没有lfence我得到的结果与该答案中的静态分析一致。

当我介绍一个single lfence我希望CPU执行imul edx, edx的序列k-th并行迭代imul eax, eax下一个序列(k+1-th)迭代。
像这样的东西(调用A the imul eax, eax序列和D the imul edx, edx one):

|
| A
| D A
| D A
| D A
| ...
| D A
| D
|
V time

采取或多或少相同数量的周期,但对于一个不成对的并行执行。

当我测量原始版本和修改版本的周期数时,taskset -c 2 ocperf.py stat -r 5 -e cycles:u '-x ' ./main-$T for T在下面的范围内我得到

T   Cycles:u    Cycles:u    Delta
    lfence      no lfence

10  42047564    30039060    12008504
15  58561018    45058832    13502186
20  75096403    60078056    15018347
25  91397069    75116661    16280408
30  108032041   90103844    17928197
35  124663013   105155678   19507335
40  140145764   120146110   19999654
45  156721111   135158434   21562677
50  172001996   150181473   21820523
55  191229173   165196260   26032913
60  221881438   180170249   41711189
65  250983063   195306576   55676487
70  281102683   210255704   70846979
75  312319626   225314892   87004734
80  339836648   240320162   99516486
85  372344426   255358484   116985942
90  401630332   270320076   131310256
95  431465386   285955731   145509655
100 460786274   305050719   155735555

的价值观如何Cycles:u lfence需要解释一下吗?
我本以为它们会与Cycles:u no lfence自从单身以来lfence应仅防止两个块并行执行第一次迭代。
我不认为这是因为lfence开销,因为我相信这对所有人来说都应该是恒定的Ts.

我想修复我的问题脑膜在处理代码的静态分析时。


支持带有源文件的存储库 https://github.com/margaretbloom/interleaved-cycle/tree/master.


我认为您测量得很准确,并且解释是微架构的,而不是任何类型的测量错误。


我认为你的中低 T 结果支持以下结论:lfence阻止前端甚至发出过去的lfence直到所有先前的指令失效,而不是让两个链中的所有微指令都已发出并等待lfence打开开关并让每个链中的乘法开始按交替周期进行调度。

(port1 将立即获得 edx,eax,empty,edx,eax,empty,... 对于 Skylake 的 3c 延迟/1c 吞吐量乘数,如果lfence不会阻塞前端,并且开销不会随 T 缩放。)

你输了imul当只有来自第一条链的微指令在调度程序中时的吞吐量,因为前端尚未咀嚼imul edx,edx并循环分支。对于窗口末尾的相同数量的周期,管道大部分已耗尽,仅剩下来自第二条链的微指令。


开销增量看起来呈线性,直到 T=60 左右。我没有计算数字,但到那里的坡度看起来是合理的T * 0.25发出第一条链的时钟与 3c 延迟执行瓶颈。 IE。增量增长速度可能是无围栏周期总数的 1/12.

所以(鉴于lfence我在下面测量了开销),T

no_lfence cycles/iter ~= 3T                  # OoO exec finds all the parallelism
lfence    cycles/iter ~= 3T + T/4 + 9.3      # lfence constant + front-end delay
                delta ~=      T/4 + 9.3

@Margaret 报道说T/4比更适合2*T / 4,但我预计在开始和结束时都为 T/4,三角洲的斜率总共为 2T/4。


大约 T=60 后,delta 增长得更快(但仍然是线性的),斜率大约等于总无栅栏周期,因此每 T 大约 3c。我认为在这一点上,调度程序(预订站)的大小限制了无序窗口。您可能在 Haswell 或 Sandybridge/IvyBridge 上进行了测试,(分别有 60 个条目或 54 个条目的调度程序 https://www.realworldtech.com/haswell-cpu/4/。 Skylake 的条目有 97 个(但并未完全统一;IIRC BeeOnRope 的测试表明并非所有条目都可用于任何类型的 uop。例如,有些条目特定于加载和/或存储。)

The RS tracks un-executed uops. Each RS entry holds 1 unfused-domain uop that's waiting for its inputs to be ready, and its execution port, before it can dispatch and leave the RS1.

After an lfence, the front-end issues at 4 per clock while the back-end executes at 1 per 3 clocks, issuing 60 uops in ~15 cycles, during which time only 5 imul instructions from the edx chain have executed. (There's no load or store micro-fusion here, so every fused-domain uop from the front-end is still only 1 unfused-domain uop in the RS2.)

对于大T,RS很快就被填满,此时前端只能以后端的速度前进。 (对于小 T,我们进行下一次迭代lfence在此之前,这就是前端停滞的原因)。当 T > RS_size 时,后端看不到任何来自eaximul 链,直到后端有足够的进展edx链条在RS中腾出了空间。就在这时,一imul每个链可以每 3 个周期调度一次,而不仅仅是第 1 条或第 2 条链。

记得从第一部分开始,就在之后花费的时间lfence只执行第一个链=之前的时间lfence仅执行第二条链。这也适用于这里。

即使没有,我们也能得到一些这种效果lfence,对于 T > RS_size,但是长链的两侧都有可能重叠。 ROB 至少是 RS 大小的两倍,因此当不因以下原因而停滞时,乱序窗口lfence即使 T 略大于调度程序容量,也应该能够保持两条链持续运行。 (请记住,uop 在执行后立即离开 RS。我不确定这是否意味着他们必须finish执行并转发结果,或者只是开始执行,但这对于短 ALU 指令来说是一个微小的区别。一旦完成,只有 ROB 会按照程序顺序保留它们,直到他们退休。)

ROB 和寄存器文件不应限制无序窗口大小(http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/)在这个假设的情况下,或者在你的真实情况下。它们都应该很大。


阻塞前端是一个实现细节lfence关于英特尔的 uarches。说明书上只说了后面的说明不能execute。该措辞将允许前端将它们全部发布/重命名到调度程序(预订站)和 ROB 中,同时lfence仍在等待,只要没有人被分派到执行单元。

所以较弱lfence可能会有平坦的开销,直到 T=RS_size,然后与您现在看到的 T>60 的斜率相同。(开销的恒定部分可能会更低。)

请注意,保证了条件/间接分支的推测执行lfence适用于执行,而不是(据我所知)代码获取。仅仅触发代码获取对于 Spectre 或 Meltdown 攻击来说没有(据我所知)有用。可能用于检测其解码方式的定时侧通道可以告诉您有关获取的代码的一些信息......

我认为当相关 MSR 启用时,AMD 的 LFENCE 在实际 AMD CPU 上至少同样强大。 (LFENCE 是否在 AMD 处理器上进行序列化? https://stackoverflow.com/questions/51844886/is-lfence-serializing-on-amd-processors).


Extra lfence高架:

你的结果很有趣,但我一点也不惊讶,因为有大量的持续开销lfence本身(对于小 T),以及随 T 缩放的组件。

请记住lfence不允许稍后的指令开始,直到较早的指令完成retired。这可能比其结果准备好旁路转发到其他执行单元(即正常延迟)至少晚几个周期/管道阶段。

因此,对于小 T 来说,通过要求结果不仅准备好,而且还写回寄存器文件,在链中添加额外的延迟绝对是很重要的。

可能需要一个额外的周期左右lfence允许发出/重命名阶段在检测到其之前的最后一条指令退出后再次开始操作。问题/重命名过程需要多个阶段(周期),并且可能 lfence 会在start这样做,而不是在将微指令添加到核心的 OoO 部分之前的最后一步。

甚至背靠背lfence根据 Agner Fog 的测试,SnB 系列本身具有 4 个周期吞吐量。阿格纳·福格报道 https://agner.org/optimize/2 个融合域微指令(没有未融合的),但在 Skylake 上,如果我只有 1 个融合域,我会以 6 个融合域(仍然没有未融合)来测量它lfence。但随着更多lfence背靠背,uop 更少了!下降至约 2 uop/lfence有很多背靠背,这就是阿格纳的衡量标准。

lfence/dec/jnz(没有工作的紧密循环)在 SKL 上每约 10 个周期运行 1 次迭代,因此这可能会让我们了解真正的额外延迟lfence即使没有前端和 RS-full 瓶颈,也会添加到 dep 链中。

测量lfence开销仅one配送链, OoO exec 不相关:

.loop:
    ;mfence                  ; mfence here:  ~62.3c (with no lfence)
    lfence                   ; lfence here:  ~39.3c
    times 10 imul eax,eax    ; with no lfence: 30.0c
    ; lfence                 ; lfence here:  ~39.6c
    dec   ecx
    jnz   .loop

Without lfence,以预期的每迭代 30.0c 运行。和lfence,每迭代运行温度约为 39.3c,因此lfence有效地为关键路径 dep 链增加了约 9.3c 的“额外延迟”。 (还有 6 个额外的融合域微指令)。

With lfence在 imul 链之后、循环分支之前,它的速度稍微慢一些。但并不是整个周期变慢,因此这表明前端在单个问题组中发出循环分支 + 和 imullfence允许恢复执行。既然如此,我不知道为什么它会慢。这不是来自分支未命中。


获得您期望的行为:

按照程序顺序交错链,就像 @BeeOnRope 在注释中建议的那样,不需要乱序执行来利用 ILP,所以它非常简单:

.loop:
    lfence      ; at the top of the loop is the lowest-overhead place.

%rep T
    imul   eax,eax
    imul   edx,edx
%endrep

    dec     ecx
    jnz    .loop

你可以放一对短的times 8 imula 内的链%rep让OoO exec 过得轻松。


脚注1:前端/RS/ROB如何交互

我的思维模型是前端的问题/重命名/分配阶段向两个 RS 添加新的 uopsandROB 同时。

Uop 执行后离开 RS,但保留在 ROB 中直到按顺序退出。 ROB 可能很大,因为它永远不会无序扫描以查找第一个就绪的微指令,而只会按顺序扫描以检查最旧的微指令是否已完成执行并准备好退出。

(我假设 ROB 实际上是一个具有开始/结束索引的循环缓冲区,而不是一个实际上每个周期都将微指令复制到右侧的队列。但只需将其视为具有固定最大大小的队列/列表,其中前端在前面添加 uops,并且只要完全执行完毕,退休逻辑就会从末尾退休/提交 uops,直到某个每个周期每个超线程的退休限制,这通常不是瓶颈。Skylake 确实增加了它以获得更好的效果超线程,每个逻辑线程每个时钟可能有 8 个。也许退休还意味着释放物理寄存器,这有助于 HT,因为当两个线程都处于活动状态时,ROB 本身是静态分区的。这就是每个逻辑线程的退休限制的原因。)

哎呀喜欢nop, xor eax,eax, or lfence,在前端处理(不需要任何端口上的任何执行单元)添加only到 ROB,处于已执行状态。 (ROB 条目大概有一个位将其标记为准备退出与仍在等待执行完成。这就是我正在谈论的状态。对于 uopsdid需要一个执行端口,我假设 ROB 位是通过完成端口 https://stackoverflow.com/questions/791798/what-is-the-eu-in-x86-architecture-calculates-effective-address#comment64889806_11389785来自执行单元。并且相同的完成端口信号释放其 RS 条目。)

Uops 从问题到问题都保留在 ROB 中退休.

从发行到发行,Uops 一直保留在 RS 中执行. RS 在少数情况下可以重放微指令, e.g. 用于缓存行分割负载的另一半 https://stackoverflow.com/questions/45128763/how-can-i-accurately-benchmark-unaligned-access-speed-on-x86-64,或者如果它是在预期负载数据到达时进行调度的,但实际上它没有到达。 (缓存未命中或其他冲突,例如IvyBridge 上的指针追逐循环中附近的依赖存储对性能产生奇怪的影响。添加额外的负载会加快速度吗? https://stackoverflow.com/questions/54084992/weird-performance-effects-from-nearby-dependent-stores-in-a-pointer-chasing-loop.) 或者当加载端口推测它可以在开始 TLB 查找之前绕过 AGU 以缩短小偏移量的指针追逐延迟时 -当基址+偏移量与基址位于不同页面时是否会受到惩罚? https://stackoverflow.com/questions/52351397/is-there-a-penalty-when-baseoffset-is-in-a-different-page-than-the-base

所以我们知道 RS 无法在调度时立即删除 uop,因为它可能需要重播。 (甚至可能发生在消耗负载数据的非负载微指令上。)但是任何需要重放的推测都是短程的,而不是通过微指令链,因此一旦结果从执行单元的另一端出来,微指令就可以从 RS 中删除。这可能是完成端口所做的一部分,同时将结果放在旁路转发网络上。


脚注 2:微融合 uop 需要多少个 RS 条目?

TL:DR:P6 系列:RS 已熔合,SnB 系列:RS 未熔合。

微融合 uop 被发送到 Sandybridge 系列中的两个独立的 RS 条目,但只有 1 个 ROB 条目。 (假设发行前没有未层压,请参阅 Intel 优化手册的 HSW 2.3.5 节或 SnB 2.4.2.4 节,以及微融合和寻址模式 https://stackoverflow.com/questions/26046634/micro-fusion-and-addressing-modes。 Sandybridge 系列更紧凑的 uop 格式在所有情况下都无法表示 ROB 中的索引寻址模式。)

负载可以在 ALU uop 的其他操作数准备就绪之前独立分派。 (或者对于微融合存储,存储地址或存储数据微指令可以在其输入准备好时进行调度,而无需等待两者。)

我使用问题中的两深度链方法在 Skylake 上进行实验测试(RS 大小 = 97), 带有微熔or edi, [rdi] vs. mov+or,以及另一个部门链rsi. (完整测试代码,Godbolt 上的 NASM 语法 https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAKxAEZSAbAQwDtQmBnDzAWwCMGAT1IdUAV2LJMIAOQBSAMwAhRUoDUBRQBECmDgQapUAB1VrOPALQM8LANZq5AJicASAgDoLzp46cA2Z381fA5OPzdNFz9AgI1OO24CNUtkNQU1VGRjTGIAMw9jQTV9JmTLTAIE1MNkO1I0Fl0ADwJLDgB3QmQEPQbjMUsePGBiMrxUFg5SYyZgTEs8pjEGAmnkQWQGPtt9YjFkAgmp0jETDgB9PC4xTHQvFmEz40vMZsxkMV17ggRiTCY6EYHHuzw4ag8AHofO4fHIAAwAQQRiKwSxWyX%2BDBRzgArHg8mi1BcLgBNREAZQAshcAGrYABKJJRalZjmUbM5agAwgAFACqOI5bL5/LUtl0DBYJhZIoFPMmxFQmDUiKpWllrNFagpdkEzDsKrVGqReMwDG4OKcuLE3BKPCYxCqNmALBRTBdLB4GBVxn8pDU/gALFbcZgWPg8jjTdaCUSAJKI7mIi5UxEMgDSFNDDuQStZieTF1KTrU8M1rO9ADc1Jg%2BM0A7QmxWQnwy81gwH4R2AOxd5oATnLMbDEdzSpzTDzqALSZT4fQZZb1dr9YDLicLfQbe7nfb/j77aHoYX49QJ4tmFDaNsKsLKZLmhHN5Yd7nFwXJ4jBOjiOAhj4D1iUfFFiyqJ0QF/TkzDZVhFy5NliA4YwA0sYNQwJNRaArbYmAQ1liHwAM5FxJQ%2BDEKNcRNRFOVw/C1CQvBiNI8i8g4SQSOos1vyjJFORXNkSKUQi8E4gMRKgtkBLZOsUKw%2BEFMU4dkRHTDsKRD0RhYdJN1NYVWWQHhjFZAEG3bWgnAUINcWCdl1G3dsFC0VkODsPBjN%2BFU8jwJDkiDNQ%2BEEXRwUmDRejUbzfPFXQxiOUKUXvMDHSfREPEMExINNPT1DZI4eD0dJ4TUFcROY4T8E41kzCIZ01GYXQWA2NQg2QAMODwIztnMdB0H%2BLhbGAYqfQizg2lmX4hRy1k8oKhQisBRdGLKxjKrsjRUFq%2Brwya/xkEUAAxMAwAOo7WRakb9EscaEEyFghAikg6tQQFLEUbBDEBB7iA6R18DYA7Js5GbwTmzJiAIojHFIiSqKqjkaqA3a6rKbbBBO46FH2xxsqBjrZqKx6GMhoSJKcYT62cJQnHhdDYbWj1REDNItsa4Q1CrDgPCGmsul%2BMLrm63rvSwNQOnEBhFz4FVcV/PF/mMgAVDC8jUfb%2BQpbAK0eu4mKh8rRKoi9LT4qTUBrWsmDMkmKsNk3WUJ2tIdMr9Ixd%2BXZeteW1CV1SVbVjWtfBvRdZJ9rOKNq87e5kzLeWsPbZotkHeDgNnZHBcf3TiN3ayxO4aUATTLK1jw6j1RDOMi2zKK%2Bja7W3wwXW2q8ke6tIQryEqFfNQIAblg8ltO4AEpJPztQK5CMXCL1rEAoosSywQswMkbhGGC%2B8ejM7lVeZujqeAADnE9zLFniAV/7wf0BHsv4b0ZJ0CnxcSfNOfKK0fs8hVtaV/OJugJbuDYKBBt6i0IHvHgPAFBOGWifLElVz5qDEJfbg18KzVXvpPEgz9oavxLlRVO%2BAx4NxMP/degCND31AbvGemBgAL3%2BINHuF8B6oJvipPOa1gFYOnkJJgfBwT4I/u2L%2BxCkF/zXhvYB1DwHikgdAgM/DwSIOQaw4e6C776B4Tg/WC9uyiPruIl4ZCpFUKoDvWRL96EELkVA3wKiUHqNvuobhj9sEzxtsInWY9aBGJMRQ6R5iwF8ysQwuhrJe5IMcWg5xrin56yUW/Be3i1q%2BOeP4x6gSLEhNwdY4RjCIl9zUTEzhqgu4qg8J%2BWJeNwS4jUM0bWyAGwfGaLLHGbIOBiDbMQPgcl1KcKwGkWSgMOldNXH0isVBBppSMKYdpLkxktMbLLfSm9jKETMrQJS2yzCSFafMtQVA2wzJlEiRKVTkTWgzrxVKC5MocNUKoAAcpSKklhJhCADNKZI5JqQgEErGFWJIlDxgVhSEk7INROR0srPA6BtIkgAPL8gVgKBWFx9qIoZGmdFFxU4MDyNAisK4i79M5A0oOa46z7M4RKdsB8a6CQ5BwQQrxmiEAgPCIeOlLB8EIKqEFEcKwUsdkxHWxKzZV1IJZXxY8SRPKZG8QgFxRjiErnkJUPA1CQltMQSEtgthiCwJCCwOqWDXAIOgC4wYPAIArCyjgyAPTryXsy1lH52UEBVUqMQxhOXsO4q7XOv5uCHGOBCJU6AyhMHdJ6LCgQkQcAdAwBgFwWBiH4Lkf500anNRCIueEHhtkKX6ZMaQdcc35XBP5HqWEi0ho%2BHFbSHgBEcFjVpQMIYkSsWzYhPQbYgzwgHAmjhrF2LIGzX1AdQ6R0yCHowWQuIZCkBYLIeEy7UCyERFwXgAhiiiAkFIPwChaDLoIGuud867AgFxE4DwDKezUwUAoA%2BA4D5zVxPCXEC6ZBBmXaumQ67SCbpkMujgIB4SkHPYBudpA4CwBgIgFAqAjJ4G2GQCgEA0CofQyAFgFgnC0DmgoUg3lVi5HAxAPgF7SB8vw8QQQshT0NBQ/lJoiK7qMZg6QLADo2DbBo/gf4Yaqx6Bo28D4XxpAyGYxKc0TGz3EA6gp%2BdzA2AgE4NwfgnybACPgPOkwTbwMyEWOaPIwYUhaCVk5fwRVLBaH9prJyQGD2SGkLQVTi7/00ZAy86kag71EaLRkCAuBCCPWcCegM3IUPGDQ7kY9HnVQ7u04IM9F6h5XpvZBhgsg/2kB4DegcRb/C4gHFZGmZWKv%2BH9ABoDIGwMQagxluDiGIBIHEAQAYBByCUGw3F3D9AdZEGIHQUgHQxjGBUz%2BpdK6fOyEi74mhfmqQBY8EF%2BECh0swcy6QXogIs0QE87%2B5dhXB0eHK4O0rl3KuXbm9xhrIgmvQfXbt69QYezrYHE4Hsw7/BbNoP4AcQYBzftyzILbBW6AKSLcW4t9A6sbtkNt17x2nDeYe8j5rO352icYpMEAQYgA)

; loop body
%rep T
%if FUSE
    or edi, [rdi]    ; static buffers are in the low 32 bits of address space, in non-PIE
%else
    mov  eax, [rdi]
    or   edi, eax
%endif
%endrep

%rep T
%if FUSE
    or esi, [rsi]
%else
    mov  eax, [rsi]
    or   esi, eax
%endif
%endrep

看着uops_executed.thread(未融合域)每个周期(或每秒)perf为我们计算),我们可以看到不依赖于单独负载与折叠负载的吞吐量数字。

使用较小的 T (T=30),可以利用所有 ILP,无论有或没有微融合,我们每个时钟都能获得约 0.67 uop。 (我忽略了来自 dec/jnz 的每个循环迭代 1 个额外 uop 的小偏差。与我们看到的微融合 uop 仅使用 1 个 RS 条目所看到的效果相比,它可以忽略不计)

记住负载+or是 2 uop,并且我们有 2 个飞行中的 dep 链,所以这是 4/6,因为or edi, [rdi]有6个周期的延迟。 (不是 5,这令人惊讶,见下文。)

在 T=60 时,对于 FUSE=0,我们仍然每个时钟执行约 0.66 个未融合的微指令,对于 FUSE=1,每个时钟执行约 0.64 个未融合微指令。我们仍然可以找到基本上所有的 ILP,但它才刚刚开始下降,因为两个 dep 链的长度为 120 uops(相对于 RS 大小为 97)。

在 T=120 时,对于 FUSE=0,每个时钟有 0.45 个未融合的微指令,对于 FUSE=1,每个时钟有 0.44 个未融合的微指令。我们肯定已经过了膝盖了,但仍然发现someILP 的。

如果微融合 uop 仅占用 1 个 RS 条目,则 FUSE=1 T=120 的速度应与 FUSE=0 T=60 大致相同,但事实并非如此。相反,FUSE=0 或 1 在任何 T 上几乎没有区别。(包括较大的 T=200:FUSE=0:0.395 uops/时钟,FUSE=1:0.391 uops/时钟)。我们必须去very在我们开始 1 个深度链在飞行中的时间之前,T 大 T 完全控制了 2 个在飞行中的时间,并下降到 0.33 uops/时钟 (2/6)。

奇怪的是:融合与非融合的吞吐量差异如此之小,但仍然可测量,并且单独的mov加载速度更快。

其他奇怪之处:总计uops_executed.thread is slightly在任何给定 T 下,FUSE=0 的值较低。例如 T=60 时为 2,418,826,591 与 2,419,020,155。这种差异可重复至 2.4G 中的 +- 60k,足够精确。 FUSE=1 的总时钟周期较慢,但大部分差异来自于每个时钟的微指令数较低,而不是更多的微指令数。

简单的寻址模式如[rdi]假设只有 4 个周期延迟,因此负载 + ALU 应该只有 5 个周期。但我测量了 6 个周期的加载使用延迟or rdi, [rdi],或者使用单独的 MOV 加载,或者使用任何其他 ALU 指令,我永远无法将加载部分设为 4c。

复杂的寻址模式如[rdi + rbx + 2064]当 dep 链中有 ALU 指令时,具有相同的延迟,因此看来 Intel 的 4c 延迟适用于简单寻址模式only当一个负载转发到另一个负载的基址寄存器时适用(最多 +0..2047 位移且无索引)。

指针追逐很常见,因此这是一种有用的优化,但我们需要将其视为特殊的负载-负载转发快速路径,而不是更快准备好供 ALU 指令使用的一般数据。


P6 系列不同:RS 条目保存融合域 uop。

@哈迪发现2002 年英特尔专利 https://patents.google.com/patent/US20040034757A1/en,其中图 12 显示了融合域中的 RS。

在 Conroe(第一代 Core 2 Duo,E6600)上进行的实验测试表明,对于 T=50,FUSE=0 和 FUSE=1 之间存在很大差异。 (RS大小为32个条目 https://www.realworldtech.com/merom/6/).

  • T=50 FUSE=1:2.346G周期总时间(0.44IPC)

  • T=50 FUSE=0:3.272G 周期的总时间(0.62IPC = 0.31 负载+OR 每个时钟)。 (perf / ocperf.py没有活动uops_executed在 Nehalem 之前的 uarches 上,我没有oprofile安装在该机器上。)

  • T=24 FUSE=0 和 FUSE=1 之间的差异可以忽略不计,大约为 0.47 IPC 与 0.9 IPC(每个时钟约 0.45 负载+OR)。

T=24 仍然是循环中超过 96 字节的代码,对于 Core 2 的 64 字节(预解码)循环缓冲区来说太大,因此由于适合循环缓冲区,它的速度并没有更快。如果没有 uop 缓存,我们必须担心前端,但我认为我们很好,因为我专门使用 2 字节单 uop 指令,这些指令应该可以轻松地以每个时钟 4 个融合域 uop 进行解码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解 lfence 对具有两个长依赖链的循环的影响,以增加长度 的相关文章

  • Blazor WebAssembly 反序列化比下载慢很多?怎么了?

    在我的 Blazor 应用程序中 我有一个具有类似方法的组件 我已将 GetFromJsonAsync 调用替换为其中的代码 以缩小缓慢部分的范围 private async Task GetData IsLoading true stri
  • 改进绩效反思 - 我应该考虑哪些替代方案?

    我需要动态地设置对象上的一堆或属性的值 将其称为传输对象 将在短时间内创建相当数量的此类传输对象并设置其属性 我想避免使用反射 还有其他选择吗 如果是的话 有我可以查看的示例实现吗 Use Delegate CreateDelegate h
  • 用于计算三角函数、对数或类似函数的算法。仅限加减法

    我正在修复 Ascota 170 古董机械可编程计算机 它已经开始工作了 现在我正在寻找一种算法来展示其功能 例如计算三角或对数表 或类似的东西 不幸的是 从数学运算来看 计算机只能进行整数的加减法 从 1E12到1E12的55个寄存器 甚
  • 为什么 Python 对于一个简单的 for 循环来说这么慢?

    我们正在做一些kNN and SVDPython 中的实现 其他人选择了 Java 我们的执行时间非常不同 我使用 cProfile 来查看我在哪里犯了错误 但一切都很好fine http wiki python org moin Pyth
  • 使用 Numba 加速矢量距离计算

    以下是我为 3 D 环形几何中的距离 平方 计算编写的一些函数 用于该 3 D 空间中的粒子集合 import itertools import time import numpy as np import scipy import num
  • 如何加快编辑距离计算速度

    我正在尝试运行模拟来测试平均值编辑距离 http en wikipedia org wiki Levenshtein distance之间随机 二进制字符串 我的程序是用 python 编写的 但我正在使用这个C扩展 https githu
  • 在LPC2148 ARM处理器上创建中断向量的汇编代码

    我最近刚刚开始使用 LPC2148 ARM 处理器 我试图理解一些有关创建中断向量的汇编代码 这是代码 Runtime Interrupt Vectors Vectors b start reset start ldr pc undf un
  • 如何防止Googlebot淹没网站?

    我正在中间的专用服务器上运行一个内容很多但流量很少的网站 有时 Googlebot 会踩踏我们 导致 Apache 耗尽内存 导致服务器崩溃 我怎样才能避免这种情况 在谷歌网站管理员工具上注册 验证您的网站并限制谷歌机器人 提交站点地图 阅
  • 与 SSE 比较 16 字节字符串

    我有 16 字节的 字符串 它们可能更短 但您可能会假设它们在末尾用零填充 但您可能不会假设它们是 16 字节对齐的 至少不总是 如何编写一个例程将它们与 SSE 内在函数进行比较 是否相等 我发现这个代码片段可能会有帮助 但我不确定它是否
  • 如何提高 Field.set 的性能(也许使用 MethodHandles)?

    我正在编写一些调用的代码Field set https docs oracle com en java javase 11 docs api java base java lang reflect Field html set java l
  • 为什么在我的例子中 For 循环比 Map、Reduce 和 List 理解更快

    我编写了一个简单的脚本来测试速度 这就是我发现的结果 实际上 for 循环在我的例子中是最快的 这真的让我感到惊讶 请查看下面 正在计算平方和 这是因为它在内存中保存列表还是有意为之 谁能解释一下这一点 from functools imp
  • 去除字符串的最佳方法是什么?

    我需要具有最佳性能的想法来删除 过滤字符串 I have string Input view 512 3 159 删除 view 和 的最佳性能方法是什么 和引号 我可以做这个 Input Input Replace view Replac
  • IEnumerable 作为 DataTable 性能问题

    我有以下扩展 它生成一个DataTable从一个IEnumerable public static DataTable AsDataTable
  • 双线性序列给出奇数结果

    我试图让我的表现技能 不存在 达到标准 但在将公式写入代码时遇到了问题 这是我试图将其引用为 转换 为代码的公式 考虑一个序列 u 其中 u 定义如下 号码u 0 1是第一个u 对于每个x in u then y 2 x 1 and z 3
  • iOS 自定义单元格设计放在哪里? awakeFromNib 还是 cellForRowAtIndexPath?

    所以 基本上我用笔尖做了一个定制单元 希望我应用一些定制设计 比如颜色和阴影 我发现了两种应用样式的方法 awakeFromNib override func awakeFromNib super awakeFromNib Containe
  • 如何有效地从 DB2 表中删除所有行

    我有一个大约有 50 万行的表 我想删除所有行 如果我做简单的delete from tbl 事务日志已满 我不关心这种情况下的事务 无论如何我都不想回滚 我可以删除许多事务中的行 但是有更好的方法吗 如何有效地从 DB2 中的表中删除所有
  • 只读有运行时开销吗?

    出于某种原因 我一直认为readonly字段有与其相关的开销 我认为这是 CLR 跟踪是否存在readonly字段是否已初始化 这里的开销是一些额外的内存使用量 用于跟踪状态以及分配值时的检查 也许我这么认为是因为我不知道readonly字
  • .NET 中 UniqueQueue 和 UniqueReplacementQueue 集合最有效的实现

    考虑到入队和出队操作的速度同样重要 NET 中 UniqueQueue 和 UniqueReplacementQueue 集合最有效 就速度而言 的实现是什么 UniqueQueue是一个不可能出现重复的队列 因此 如果我将一个元素推送到队
  • 比较运算符性能 <= 与 !=

    让我们首先声明代码可读性胜过微优化 我们应该将其留给编译器 这只是一个奇怪的案例 具体细节似乎与一般建议相比很有趣 因此 我在搞素数生成器函数 并提出了一种奇怪的行为 其中 人们建议效率最高 实际上效率最低 而 C private stat
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的

随机推荐