- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个循环在 Intel Conroe/Merom 上每 3 个周期运行一次迭代,如预期的那样在 imul
吞吐量上出现瓶颈。但是在 Haswell/Skylake 上,它每 11 个周期运行一次迭代,显然是因为 setnz al
依赖于最后一个 imul
。
; synthetic micro-benchmark to test partial-register renaming
mov ecx, 1000000000
.loop: ; do{
imul eax, eax ; a dep chain with high latency but also high throughput
imul eax, eax
imul eax, eax
dec ecx ; set ZF, independent of old ZF. (Use sub ecx,1 on Silvermont/KNL or P4)
setnz al ; ****** Does this depend on RAX as well as ZF?
movzx eax, al
jnz .loop ; }while(ecx);
setnz al
依赖于
rax
,则 3ximul/setcc/movzx 序列形成循环携带的依赖链。如果不是,则每个
setcc
/
movzx
/3x
imul
链都是独立的,从更新循环计数器的
dec
fork 出来。在 HSW/SKL 上测得的每次迭代 11c 可以用延迟瓶颈完美解释:3x3c(imul) + 1c(setcc 读取-修改-写入)+ 1c(同一寄存器内的 movzx)。
xor
-zero/set-flags/
setcc
无论如何都更好(在这种情况下,
xor eax,eax
/
dec ecx
/10x23131)。这打破了所有 CPU 上的 eax 依赖(除了早期的 P6 系列,如 PII 和 PIII),仍然避免了部分寄存器合并惩罚,并节省了 1c 的
setnz al
延迟。它还在
handle xor-zeroing in the register-rename stage 的 CPU 上使用少一个 ALU uop。有关使用
movzx
的异或归零的更多信息,请参阅该链接。
setcc
/
cmp
/
setcc al
它也可以使用
movzx eax,al
代替
xor
(Godbolt compiler-explorer example),而铛使用XOR零/CMP/setcc除非您将多个 bool 条件像
movzx
。
count += (a==b) | (a==~b)
吞吐量)。
imul
-zeroing 在除 PPro/PII/PIII/early-Pentium-M 之外的所有乱序 CPU 上打破了对旧值
xor
的依赖(它仍然避免部分寄存器合并惩罚,但不会破坏 dep )。
Agner Fog's microarch guide describes this。用
eax
替换异或归零会使其在 Core2 上每 4.78 个周期减慢到一个:
2-3c stall (in the front-end?) to insert a partial-reg merging uop 当
mov eax,0
读取 0x251812231143 1343 之后的 0x2518122311343 1343 之后。
imul
来打败 mov-elimination,就像
eax
一样。 (IvB、HSW 和 SKL 可以以 0 延迟重命名
setnz al
,但 Core2 不能)。这使得 Core2/SKL 中的所有内容都相等,除了部分寄存器行为。
Different parts of a general purpose register can be stored in different temporary registers in order to remove false dependences.
movzx eax, al
短序列放入运行 100M 或 1G 迭代的小
mov rax,rax
循环中。我使用 Linux
movzx eax, bl
以与
in my answer here 相同的方式在相同的硬件(桌面 Skylake i7 6700k)上测量了周期。
%rep 4
测量)。这会检测(不存在)移动消除和额外的合并 uops。
dec ebp/jnz
的计数在 HSW 上正好是 0,在 SKL 上很小(大约 1.8k),并且不随循环迭代计数而扩展。可能这些计数来自某些内核代码。当循环从 LSD 运行时,
perf
在测量噪声范围内。有些循环在 LSD 或无 LSD 之间交替(例如,如果解码在错误的位置开始,它们可能不适合 uop 缓存),但我在测试时没有遇到这种情况。
ocperf.py stat -e ...,uops_issued.any,uops_executed.thread
和/或 lsd.uops
每个周期运行 4。它需要一个 ALU uop,所以它不会像 lsd.uops ~= uops_issued
那样被消除。 mov ah, bh
每周期运行 2 个(负载吞吐量瓶颈)。 mov ah, bl
每个周期运行 1。 (循环内的 dep-breaking mov eax, ebx
消除了瓶颈。)mov ah, [rsi]
或 mov ah, 123
每个周期运行 1。 (一个破坏性的 xor eax,eax
让它成为 setz ah
和循环分支的 p06 吞吐量瓶颈。)setc ah
对旧值有错误的依赖性,而 xor eax,eax
则没有(对于 reg 或内存 src)? (那么 setcc
呢?当然,您用于 reg-reg 移动的两个操作码中的哪一个都无关紧要?)ah
每个周期运行 1。 mov r8, r/m8
每个周期运行 1。 mov r/m8, r8
每个周期运行 1。 add ah, 123
每周期运行 0.5。读取 [ABCD]H 当它们“干净”时很特别(在这种情况下,RCX 最近根本没有修改)。 add dh, cl
或
add dh, dh
。
add dh, ch
~=
inc eax
。
mov eax, esi
每个周期运行 1。每组偶尔的 dep-breaking uops_issue.any
让 OOO 执行成为 uop 吞吐量的瓶颈,而不是延迟。 lsd.uops
每个周期运行 1 个,作为微融合 ALU+负载 uop。 (uops_issued=4G + 循环开销,uops_executed=8G + 循环开销)。mov al, bl
让它成为每个时钟 2 个负载的瓶颈。 xor eax,eax
每个周期运行 1。 mov al, [rsi]
每周期运行 0.5。 (每 2 个周期 1 个)。读 [ABCD]H 很特别。 xor eax,eax
+ 6x mov al, 123
+ mov al, bh
:每个迭代 2c,每个时钟 4 uops 的瓶颈。 xor eax,eax
每周期运行 0.5。 (每 2 个周期 1 个)。读取 [ABCD]H 显然会为 mov al,bh
造成额外的延迟。 dec ebp/jnz
每个周期运行 1。 add dl, ch
一样,但如果
dl
是脏的,它不会触发合并。因此(除了忽略
add dl, cl
合并),它的行为与根本不进行部分 reg 重命名的 CPU 相同。似乎
add eax, 123
从未与
ah
分开重命名?
AH
/AL
对可以并行运行。 RAX
如果 inc al
是“脏的”,则插入合并 uop,但实际的 inc ah
已重命名。这是 IvyBridge 及更高版本的 Agner Fog describes。 mov ecx, eax
每 2 个周期运行 1 个。 (在写入完整寄存器后读取高 8 寄存器有额外的延迟。)ah
具有零延迟并且不占用 HSW 和 SKL 上的执行端口。 (就像 Agner Fog 为 IvyBridge 描述的那样,但他说 HSW 不会重命名 movzx)。 mov
有 1c 延迟并占用一个执行端口。 ( mov-elimination never works for the movzx eax, ah
case ,仅在不同架构寄存器之间。)movzx ecx, al
/
movzx ecx, cl
以保持一致性),并且从未注意到任何差异。
same,same
的一些 super 奇怪的内容,请参阅 INC instruction vs ADD 1: Does it matter?(甚至 Core2/Nehalem 上的 AL
:不要从除 1 以外的移位读取标志)。AH
循环中的部分标志内容。
最佳答案
其他答案欢迎更详细地解决 Sandybridge 和 IvyBridge。
我无权访问该硬件。
我没有发现 HSW 和 SKL 之间的任何部分 reg 行为差异。
在 Haswell 和 Skylake 上,到目前为止我测试过的所有东西都支持这个模型:
AL 从未与 RAX (或来自 r15 的 r15b)分开重命名。因此,如果您从未接触过 high8 寄存器(AH/BH/CH/DH),那么一切都与没有部分 reg 重命名(例如 AMD)的 CPU 完全一样。
对 AL 的只写访问合并到 RAX,依赖于 RAX。对于加载到 AL 中的内容,这是一个在 p0156 上执行的微融合 ALU+加载 uop,这是最有力的证据之一,表明它在每次写入时真正合并,而不仅仅是像 Agner 推测的那样进行一些花哨的双重簿记。
Agner(和英特尔)说 Sandybridge 可能需要为 AL 合并 uop,因此它可能与 RAX 分开重命名。对于 SnB,Intel's optimization manual (section 3.5.2.4 Partial Register Stalls) 说
SnB (not necessarily later uarches) inserts a merging uop in the following cases:
After a write to one of the registers AH, BH, CH or DH and before a following read of the 2-, 4- or 8-byte form of the same register. In these cases a merge micro-op is inserted. The insertion consumes a full allocation cycle in which other micro-ops cannot be allocated.
After a micro-op with a destination register of 1 or 2 bytes, which is not a source of the instruction (or the register's bigger form), and before a following read of a 2-,4- or 8-byte form of the same register. In these cases the merge micro-op is part of the flow.
add al,bl
将 RMW 完整的 RAX 而不是单独重命名它,因为源寄存器之一是(部分)RAX。我的猜测是这不适用于像
mov al, [rbx + rax]
这样的负载;
rax
在寻址模式下可能不算作来源。
xor al,al
没有帮助, mov al, 0
也没有帮助。 movzx ebx, al
有 zero latency (renamed) ,不需要执行单元。 (即移动消除适用于 HSW 和 SKL)。 如果它是脏的,它会触发 AH 的合并 ,我想这是它在没有 ALU 的情况下工作所必需的。英特尔在引入 mov-elimination 的同一个 uarch 中放弃了 low8 重命名可能并非巧合。 (Agner Fog的微弓指南这里有一个错误,说在HSW或SKL上没有消除零扩展 Action ,只有IvB。)movzx eax, al
在重命名时不会被消除。英特尔上的 mov-elimination 永远不会同样适用。 mov rax,rax
也没有被消除,即使它不必对任何东西进行零扩展。 (尽管没有必要为其提供特殊的硬件支持,因为它只是一个空操作,与 mov eax,eax
不同)。无论如何,在零扩展时更喜欢在两个单独的架构寄存器之间移动,无论是使用 32 位 mov
还是 8 位 movzx
。 movzx eax, bx
在 HSW 或 SKL 上重命名时不会被消除。它具有 1c 延迟并使用 ALU uop。 Intel 的优化手册仅提到 8 位 movzx 的零延迟(并指出 movzx r32, high8
从未重命名)。 ah
和 mov ah, reg8
或 mov ah, [mem8]
重命名 AH,不依赖旧值。这些都是 32 位版本通常不需要 ALU uop 的指令。 (但是 mov ah, bl
没有被消除;它确实需要一个 p0156 ALU uop,所以这可能是一个巧合)。 inc ah
)弄脏了它。 setcc ah
依赖于旧的 ah
,但仍然弄脏它。我认为 mov ah, imm8
是相同的,但还没有测试那么多的极端情况。setcc ah
的循环有时可以从 LSD 运行,参见本文末尾的 0x25181231343141 循环。也许只要 rcr
在循环结束时是干净的,它就可以使用?)。ah
是脏的, ah
合并到重命名的 setcc ah
,而不是强制合并到 ah
。例如rax
(%rep 4
/inc al
/test ebx,ebx
/setcc ah
/inc al
)不产生合并微指令,只有在大约8.7c运行(等待时间的8 inc ah
从微指令减慢由资源冲突为inc al
。另外,ah
/inc ah
DEP链)。setcc ah
始终实现为读-修改-写。英特尔可能认为不值得使用只写 setcc r8
uop 来优化 setcc
情况,因为编译器生成的代码非常罕见 setcc ah
。 (但请参阅问题中的 Godbolt 链接:clang4.0 with setcc ah
会这样做。)-m32
已停用)。使用 uops_issued/executed perf 计数器检测到,这清楚地显示了差异。 mov ah, 123
)作为 ALU uop 的一部分免费合并。 (仅使用一些简单的 uops 进行测试,例如 inc al
/add
,而不是 inc
或 div r8
)。同样,即使 AH 是脏的,也不会触发合并 uop。 mul r8
或 lea eax, [rsi + rcx]
)清除 AH 脏状态(无合并 uop)。 xor eax,eax
) 首先触发 AH 的合并。我想它不是特殊 shell ,而是像 AX/RAX 的任何其他 RMW 一样运行。 (待办事项:测试 mov ax, 1
,虽然这不应该很特别,因为它没有重命名。)mov ax, bx
有 1c 延迟,不破坏,仍然需要一个执行端口。 xor ah,ah
/add ah, cl
每个时钟可以运行 1 个(瓶颈增加延迟)。add al, dl
/
push
的循环,这是有道理的,但这意味着它可以运行具有平衡 0x251812231340x1221313/.40x12413 的循环这不是我所看到的SKL:即使平衡从LSD运行(如
pop
/
push
/
pop
(有可能是瑞士央行的LSD和HSW/SKL之间的真正区别
push
/
pop
防止:。
SnB may just "lock down" the uops in the IDQ instead of repeating them multiple times, so a 5-uop loop takes 2 cycles to issue instead of 1.25)无论如何,它出现当高 8 寄存器脏时,或者当它包含堆栈引擎 uops 时,HSW/SKL 不能使用 LSD。
SKL150: Short Loops Which Use AH/BH/CH/DH Registers May Cause Unpredictable System Behaviour
Problem: Under complex micro-architectural conditions, short loops of less than 64 instruction that use AH, BH, CH, or DH registers as well as their corresponding wider registers (e.g. RAX, EAX, or AX for AH) may cause unpredictable system behaviour. This can only happen when both logical processors on the same physical processor are active.
push rax
。
pop rdx
软件包仅提供更新
you have to edit config files to actually have it loaded 。所以
我的 Skylake 测试是在 i7-6700k 上进行的,微码修订版为 0x84,即 doesn't include the fix for SKL150 。它与我测试的每种情况下的 Haswell 行为相匹配,IIRC。 (例如,Haswell 和我的 SKL 都可以从 LSD 运行
times 6 imul rax, rdx
/
microcode: sig=0x506e3, pf=0x2, revision=0x84
/
intel-ucode
/
setne ah
循环)。我启用了 HT(这是 SKL150 出现的先决条件),但我在一个大部分空闲的系统上进行测试,因此我的线程拥有自己的核心。
add ah,ah
总是恰好为零,包括真实程序而不是合成循环。硬件错误(而不是微代码错误)通常需要禁用整个功能才能修复。这就是 SKL-avx512 (SKX) 为
reported to not have a loopback buffer 的原因。幸运的是,这不是性能问题:SKL 在 Broadwell 上增加的 uop-cache 吞吐量几乎总是能跟上问题/重命名。
rcr ebx,1
从输入 BL 到输出 BL 的延迟为 2c,因此即使 RAX 和 AH 不是关键路径的一部分,它也可以为关键路径增加延迟。 (我以前见过其他操作数的这种额外延迟,在 Skylake 上有向量延迟,其中 int/float 延迟永远“污染”寄存器。TODO:写下来。)mov eax,ebx
/
lsd.uops
解包字节具有额外的延迟,而
add bl, ah
/
movzx ecx, al
/0x2518141/0x2518141 3 吞吐量仍然更好,3
movzx edx, ah
或 movzx
/shr eax,8
每次添加有 1c 延迟)。在许多极端情况下,我还没有进行大量测试来确认这一点。movzx
指令都有 2c 延迟(从读取未修改的 DH 开始),该程序也可以每 2 个时钟运行 1 个迭代。global _start
_start:
mov ebp, 100000000
.loop:
add ah, dh
add bh, dh
add ch, dh
add al, dh
add bl, dh
add cl, dh
add dl, dh
dec ebp
jnz .loop
xor edi,edi
mov eax,231 ; __NR_exit_group from /usr/include/asm/unistd_64.h
syscall ; sys_exit_group(0)
Performance counter stats for './testloop':
48.943652 task-clock (msec) # 0.997 CPUs utilized
1 context-switches # 0.020 K/sec
0 cpu-migrations # 0.000 K/sec
3 page-faults # 0.061 K/sec
200,314,806 cycles # 4.093 GHz
100,024,930 branches # 2043.675 M/sec
900,136,527 instructions # 4.49 insn per cycle
800,219,617 uops_issued_any # 16349.814 M/sec
800,219,014 uops_executed_thread # 16349.802 M/sec
1,903 lsd_uops # 0.039 M/sec
0.049107358 seconds time elapsed
%if 1
imul eax,eax
mov dh, al
inc dh
inc dh
inc dh
; add al, dl
mov cl,dl
movzx eax,cl
%endif
Runs at ~2.35c per iteration on both HSW and SKL. reading `dl` has no dep on the `inc dh` result. But using `movzx eax, dl` instead of `mov cl,dl` / `movzx eax,cl` causes a partial-register merge, and creates a loop-carried dep chain. (8c per iteration).
%if 1
imul eax, eax
imul eax, eax
imul eax, eax
imul eax, eax
imul eax, eax ; off the critical path unless there's a false dep
%if 1
test ebx, ebx ; independent of the imul results
;mov ah, 123 ; dependent on RAX
;mov eax,0 ; breaks the RAX dependency
setz ah ; dependent on RAX
%else
mov ah, bl ; dep-breaking
%endif
add ah, ah
;; ;inc eax
; sbb eax,eax
rcr ebx, 1 ; dep on add ah,ah via CF
mov eax,ebx ; clear AH-dirty
;; mov [rdi], ah
;; movzx eax, byte [rdi] ; clear AH-dirty, and remove dep on old value of RAX
;; add ebx, eax ; make the dep chain through AH loop-carried
%endif
add ah,ah
)具有 20c 循环携带延迟,并且从 LSD 运行,即使它具有 add ah,dh
和 add dh,ah
。00000000004000e0 <_start.loop>:
4000e0: 0f af c0 imul eax,eax
4000e3: 0f af c0 imul eax,eax
4000e6: 0f af c0 imul eax,eax
4000e9: 0f af c0 imul eax,eax
4000ec: 0f af c0 imul eax,eax
4000ef: 85 db test ebx,ebx
4000f1: 0f 94 d4 sete ah
4000f4: 00 e4 add ah,ah
4000f6: d1 db rcr ebx,1
4000f8: 89 d8 mov eax,ebx
4000fa: ff cd dec ebp
4000fc: 75 e2 jne 4000e0 <_start.loop>
Performance counter stats for './testloop' (4 runs):
4565.851575 task-clock (msec) # 1.000 CPUs utilized ( +- 0.08% )
4 context-switches # 0.001 K/sec ( +- 5.88% )
0 cpu-migrations # 0.000 K/sec
3 page-faults # 0.001 K/sec
20,007,739,240 cycles # 4.382 GHz ( +- 0.00% )
1,001,181,788 branches # 219.276 M/sec ( +- 0.00% )
12,006,455,028 instructions # 0.60 insn per cycle ( +- 0.00% )
13,009,415,501 uops_issued_any # 2849.286 M/sec ( +- 0.00% )
12,009,592,328 uops_executed_thread # 2630.307 M/sec ( +- 0.00% )
13,055,852,774 lsd_uops # 2859.456 M/sec ( +- 0.29% )
4.565914158 seconds time elapsed ( +- 0.08% )
add
清除它之前对 %if 1
执行某些操作。)setcc ah
,它在 HSW/SKL 上每次迭代都以 5.0c 运行(add ah,ah
吞吐量瓶颈)。 (注释掉的存储/重新加载也可以工作,但是 SKL 的存储转发速度比 HSW 快,并且是 variable-latency ...) # mov ah, bl version
5,009,785,393 cycles # 4.289 GHz ( +- 0.08% )
1,000,315,930 branches # 856.373 M/sec ( +- 0.00% )
11,001,728,338 instructions # 2.20 insn per cycle ( +- 0.00% )
12,003,003,708 uops_issued_any # 10275.807 M/sec ( +- 0.00% )
11,002,974,066 uops_executed_thread # 9419.678 M/sec ( +- 0.00% )
1,806 lsd_uops # 0.002 M/sec ( +- 3.88% )
1.168238322 seconds time elapsed ( +- 0.33% )
关于assembly - Haswell/Skylake 上的部分寄存器究竟如何执行?写AL好像对RAX有假依赖,AH不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45660139/
我有一些未知的 C++ 代码是在发布版本中编译的,因此对其进行了优化。我正在努力解决的问题是: xor al, al add esp, 8 cmp byte ptr [ebp+
print_string: lodsb ; grab a byte from SI cmp al, 0 ;or al, al ; logical or AL by i
如何用 C 语言编写 test al,al 代码? 我试过 if((n & 0xFF) & 0){} 但这不正确。 谢谢。 最佳答案 我猜你接下来要检查零标志,即 jz 或类似的。在那种情况下你会想要
我在我的 Centos5 机器上运行了这个: ls -al & ; ls -al 我期待它在后台运行 ls -al,同时在前台运行 ls -al,并演示终端的输出是如何被破坏的通过这样做。 但是,我得
ArrayList al = new ArrayList(); 和有什么区别? ArrayList al = new ArrayList(0)? 最佳答案 ArrayList(0) 具有指定初始容量的
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: List versus ArrayList 之间的区别 ArrayList al = new ArrayLi
这是我的代码: section .data digit db 0,10 section .text global _start _start: call _printRAXD
我已经在 XCode 中创建了一个项目并添加了 OpenAL 框架。当我尝试包含 AL/al.h 时,编译器仍然找不到它。 我在哪里添加 OpenAL 的包含目录? 编辑:抱歉我忘了补充:我正在使用
问题陈述:需要从ymm0寄存器中提取位于其值在寄存器AL中的位置的字节。 我的方法:(相当难看): ; Set XMM1 to be a "shift one byte by righ
在调试使用信号量进行跨进程同步的应用程序时,我偶然发现了使用PowerShell代替“其他”进程的想法。在PowerShell中执行以下操作可以正常工作: // In C# application:
我正在尝试为用户显示电影推荐列表。模型已经过训练,但在尝试显示预测时出现错误。 als = ALS(maxIter=5, regParam=0.01, userCol="userID", itemCo
我们在 Azure Spark 上使用 ALS 来构建我们的推荐系统。 由于计算能力的原因,我们无法为每个用户输出不同的推荐列表。因此,我们将用户分为聚类,并使用 ALS 为每个单独的聚类质心输出推荐
我正在阅读一个反汇编的 win32 c++ 程序,我看到了很多: AND AL,0xFF 这是完全没有意义的还是为什么编译器会生成这些? 这是一个更长的例子: movsx eax, byte pt
我对用于推荐引擎的 ALS 有疑问? ALS 是确定性的吗?比如,如果你输入相同的数据和相同的参数,你是否应该总是得到相同的输出(或非常相似的结果)? 最佳答案 简短的回答应该是:NO。矩阵分解算法的
我正在使用 gtk 和 xlib(xtst) 创建一个程序来将假按键发送到应用程序,我创建了这个循环来将按键发送到事件窗口: Display *dis; dis = XOpenDisp
我正在尝试使用带有隐式反馈的 Spark MLib ALS 进行协作过滤。输入数据只有两个字段userId和productId。我没有产品评分,只有用户购买过哪些产品的信息,仅此而已。因此,为了训练
我正在做一个处理 x86 汇编语言的二进制炸弹实验室作业(我相信是 at&t)。我正在运行我的代码并走到最后,但最后我将我的 306 值与这个 %al 寄存器进行比较,我不知道如何获得它的值,因为我尝
有人可以指导我在linux中ls -ali输出的每一列描述什么吗? 最佳答案 ls -ali 类似这样的事情 67403780 -rw-------. 1 root root 1114 12月
我找到了一些声称使用 openAL 列出所有音频输出设备的示例,但是我只能让它们列出当前在 OSX(Yosemite、Maverick)上选择的设备。我使用的是 mac,有默认声卡(内置输出)以及 a
我想根据日期对“ls -al”命令的输出进行排序。我可以使用命令轻松地为一列执行此操作: $ ls -al | sort -k6 -M -r 但是如何同时对第 6 列和第 7 列执行此操作?命令: $
我是一名优秀的程序员,十分优秀!