- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近一直在学习 SIMD in assembly (x86_64),并且有一些意想不到的结果。归结为以下内容。
我有两个循环运行多次的程序。第一个程序包含一个执行 4 条 SIMD 指令的循环,第二个程序包含这个完全相同的循环和一个额外的指令。代码如下所示:
第一个程序:
section .bss
doublestorage: resb 8
section .text
global _start
_start:
mov rax, 0x0000000100000001
mov [doublestorage], rax
cvtpi2pd xmm1, [doublestorage]
cvtpi2pd xmm2, [doublestorage]
cvtpi2pd xmm3, [doublestorage]
cvtpi2pd xmm4, [doublestorage]
cvtpi2pd xmm5, [doublestorage]
cvtpi2pd xmm6, [doublestorage]
cvtpi2pd xmm7, [doublestorage]
mov rax, (1 << 31)
loop:
movupd xmm1, xmm3
movupd xmm2, xmm5
divpd xmm1, xmm2
addpd xmm4, xmm1
dec rax
jnz loop
mov rax, 60
mov rdi, 0
syscall
第二个程序:
section .bss
doublestorage: resb 8
section .text
global _start
_start:
mov rax, 0x0000000100000001
mov [doublestorage], rax
cvtpi2pd xmm1, [doublestorage]
cvtpi2pd xmm2, [doublestorage]
cvtpi2pd xmm3, [doublestorage]
cvtpi2pd xmm4, [doublestorage]
cvtpi2pd xmm5, [doublestorage]
cvtpi2pd xmm6, [doublestorage]
cvtpi2pd xmm7, [doublestorage]
mov rax, (1 << 31)
loop:
movupd xmm1, xmm3
movupd xmm2, xmm5
divpd xmm1, xmm2
addpd xmm4, xmm1
movupd xmm6, xmm7
dec rax
jnz loop
mov rax, 60
mov rdi, 0
syscall
现在,我的想法是:第二个程序有更多的指令要执行,因此执行时间会长得多。但是,如果我对两个程序都计时,那么第二个程序比第一个程序花费的时间更少。我总共运行了这两个程序 100 次,结果是:
Runtime first program: mean: 5.6129 s, standard deviation: 0.0156 s
Runtime second program: mean: 5.5056 s, standard deviation: 0.0147 s
我得出结论,第二个程序运行得相当快。这些结果对我来说似乎违反直觉,所以我想知道造成这种行为的原因是什么。
为了完整起见,我正在运行 Ubuntu 15.10 和 NASM 编译器 (-elf64),并使用 Intel Core i7-5600。另外,我检查了反汇编,编译器没有进行任何优化:
第一个程序的Objdump:
exec/instr4: file format elf64-x86-64
Disassembly of section .text:
00000000004000b0 <.text>:
4000b0: 48 b8 01 00 00 00 01 movabs $0x100000001,%rax
4000b7: 00 00 00
4000ba: 48 89 04 25 28 01 60 mov %rax,0x600128
4000c1: 00
4000c2: 66 0f 2a 0c 25 28 01 cvtpi2pd 0x600128,%xmm1
4000c9: 60 00
4000cb: 66 0f 2a 14 25 28 01 cvtpi2pd 0x600128,%xmm2
4000d2: 60 00
4000d4: 66 0f 2a 1c 25 28 01 cvtpi2pd 0x600128,%xmm3
4000db: 60 00
4000dd: 66 0f 2a 24 25 28 01 cvtpi2pd 0x600128,%xmm4
4000e4: 60 00
4000e6: 66 0f 2a 2c 25 28 01 cvtpi2pd 0x600128,%xmm5
4000ed: 60 00
4000ef: 66 0f 2a 34 25 28 01 cvtpi2pd 0x600128,%xmm6
4000f6: 60 00
4000f8: 66 0f 2a 3c 25 28 01 cvtpi2pd 0x600128,%xmm7
4000ff: 60 00
400101: b8 00 00 00 80 mov $0x80000000,%eax
400106: 66 0f 10 cb movupd %xmm3,%xmm1
40010a: 66 0f 10 d5 movupd %xmm5,%xmm2
40010e: 66 0f 5e ca divpd %xmm2,%xmm1
400112: 66 0f 58 e1 addpd %xmm1,%xmm4
400116: 48 ff c8 dec %rax
400119: 75 eb jne 0x400106
40011b: b8 3c 00 00 00 mov $0x3c,%eax
400120: bf 00 00 00 00 mov $0x0,%edi
400125: 0f 05 syscall
第二个程序的Objdump:
exec/instr5: file format elf64-x86-64
Disassembly of section .text:
00000000004000b0 <.text>:
4000b0: 48 b8 01 00 00 00 01 movabs $0x100000001,%rax
4000b7: 00 00 00
4000ba: 48 89 04 25 2c 01 60 mov %rax,0x60012c
4000c1: 00
4000c2: 66 0f 2a 0c 25 2c 01 cvtpi2pd 0x60012c,%xmm1
4000c9: 60 00
4000cb: 66 0f 2a 14 25 2c 01 cvtpi2pd 0x60012c,%xmm2
4000d2: 60 00
4000d4: 66 0f 2a 1c 25 2c 01 cvtpi2pd 0x60012c,%xmm3
4000db: 60 00
4000dd: 66 0f 2a 24 25 2c 01 cvtpi2pd 0x60012c,%xmm4
4000e4: 60 00
4000e6: 66 0f 2a 2c 25 2c 01 cvtpi2pd 0x60012c,%xmm5
4000ed: 60 00
4000ef: 66 0f 2a 34 25 2c 01 cvtpi2pd 0x60012c,%xmm6
4000f6: 60 00
4000f8: 66 0f 2a 3c 25 2c 01 cvtpi2pd 0x60012c,%xmm7
4000ff: 60 00
400101: b8 00 00 00 80 mov $0x80000000,%eax
400106: 66 0f 10 cb movupd %xmm3,%xmm1
40010a: 66 0f 10 d5 movupd %xmm5,%xmm2
40010e: 66 0f 5e ca divpd %xmm2,%xmm1
400112: 66 0f 58 e1 addpd %xmm1,%xmm4
400116: 66 0f 10 f7 movupd %xmm7,%xmm6
40011a: 48 ff c8 dec %rax
40011d: 75 e7 jne 0x400106
40011f: b8 3c 00 00 00 mov $0x3c,%eax
400124: bf 00 00 00 00 mov $0x0,%edi
400129: 0f 05 syscall
最佳答案
有 no such thing as an "i7 5600" .我假设你的意思是 i7 5600U ,这是一款低功耗 (15W TDO) CPU,具有 2.6GHz 基础频率/3.2GHz 涡轮频率。
你能仔细检查一下这是否可重现吗?确保 CPU 时钟速度在两次测试中保持恒定,因为您的低功耗 CPU 可能无法在除法单元一直忙碌的情况下全速运行。
也许对于使用性能计数器(例如 perf stat ./a.out
)进行测试也很有用,测量核心时钟周期。 (不是“引用”周期。您想计算时钟实际运行的实际周期。)
IACA最多只支持 Haswell。除了两个循环的每次迭代 14c 之外,它没有说明任何其他内容,这会成为除法器吞吐量的瓶颈。 (Agner Fog 对 divpd
的测量值为 one per 8-14c throughput on Haswell, one per 8c on Broadwell。)
有a recent question about broadwell throughput ,但这是关于使前端饱和。
这个循环应该纯粹是 divpd
吞吐量 (one per 8c on Broadwell) 的瓶颈。如果效果是真实的,我想出的唯一解释是 movupd
insns 之一并不总是被消除,而是从 divpd
中窃取 p0 用于有时一个循环。
循环中的三个未融合域微指令都在不同的端口上运行,因此它们不可能相互延迟。 (p0 上的 divpd
,p1 上的 addpd
,p6 上的 predicted-taken fused cmp/jcc
)。
实际上,即使是该理论也站不住脚。未消除的 movaps xmm,xmm
使用 Broadwell 上的端口 5。我假设 movupd xmm,xmm
的奇怪选择也解码为 port5 uop。 (Agner Fog 甚至没有列出 movups
/movupd
的 reg-reg 形式的条目,因为每个人总是使用 movaps
。或者 movapd
如果他们喜欢将 insn 类型与数据匹配,即使它长一个字节并且现有的 uarch 不关心 s
与 d
的旁路延迟,只有 movaps
用于 float/double 和 movdqa
用于整数。)
有趣的是,我的 2.4GHz E6600(Conroe/merom 微架构)在 4.5 秒内运行您的循环。 Agner Fog 的表格将 Merom 上的 divpd
列为 5-31c 中的一个。 1.0/1.0
大概发生在 5c 中。 Sandybridge 的 best-case divide 比 Nehalem 慢得多。只有使用 Skylake 时,最佳情况下的吞吐量才能像 Merom 一样快速下降。 (对于 128b divpd
,吞吐量固定为每 4c 一个)。
顺便说一句,这是您的代码版本,它使用一些更常规的方法在 regs 中设置 FP 数据:
default REL ; use RIP-relative for access to globals by default, so you don't have to write `[rel my_global]`
section .rodata
; ALIGN 16 ; only desirable if we're doing a 128b load instead of a 64b broadcast-load
one_dp: dq 1.0
section .text
global _start
_start:
mov rax, 0x0000000100000001
mov [rsp-16], rax ; if you're going to store/reload, use the stack for scratch space, not a static location that will probably cache-miss.
cvtpi2pd xmm1, [rsp-16] ; this is the form with xmm, mm/m64 args. Interestingly, for the memory operand form, this should perform the same but saves a byte in the encoding.
cvtdq2pd xmm8, [rsp-16] ; this is the "normal" insn, with xmm, xmm/m64 args.
movq xmm9, rax
cvtdq2pd xmm9, xmm9
; Fun fact: 64bit int <-> FP is only available for scalar until AVX-512 introduces packed conversions for qword integer vectors.
;mov eax, 1 ; still 1 from earlier
cvtsi2sd xmm2, eax
unpcklpd xmm2, xmm2 ; broadcast
pcmpeqw xmm3,xmm3 ; generate the constant on the fly, from Agner Fog's asm guide
psllq xmm3, 54
psrlq xmm3, 2 ; (double)1.0 in both halves.
movaps xmm4, xmm3 ; duplicate the data instead of re-doing the conversion. Shorter and cheaper.
movaps xmm5, xmm3
movaps xmm6, xmm3
;movaps xmm7, [ones] ; load 128b constant
movddup xmm7, [one_dp] ; broadcast-load
mov eax, (1 << 31) ; 1<<31 fits in a 32bit reg just fine.
;IACA_start
.loop:
;movupd xmm1, xmm3
;movupd xmm2, xmm5
movaps xmm1, xmm3 ; prob. no perf diff, but weird to see movupd used for reg-reg moves
movaps xmm2, xmm5
divpd xmm1, xmm2
addpd xmm4, xmm1
;movaps xmm6, xmm7
dec eax
jnz .loop
;IACA_end
mov eax, 60
xor edi,edi
syscall ; exit(0)
对于 IACA,我使用了:
%macro IACA_start 0
mov ebx, 111
db 0x64, 0x67, 0x90
%endmacro
%macro IACA_end 0
mov ebx, 222
db 0x64, 0x67, 0x90
%endmacro
.loop:
movapd xmm1, xmm3 ; replace the only operand that div writes
divpd xmm1, xmm2
addpd xmm4, xmm1
dec eax
jnz .loop
然后循环只有 4 个融合域微指令。应该使差异为零,因为 divpd
吞吐量应该仍然是唯一的瓶颈。
或使用 AVX:
vdivpd xmm0, xmm1, xmm2
vaddpd xmm4, xmm4, xmm0
cmp/jcc
关于loops - 时间性能 SIMD 汇编程序 : longer loop executes faster,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36652462/
Strassen 的算法在多项式上比 n 次方正则矩阵乘法快。 “多项式更快”是什么意思? 最佳答案 您的问题与“复杂性”的理论概念有关。例如,据说正则矩阵乘法的复杂度为 O(n^3)。这意味着随着维
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
假设我有两个 PHP 语句: echo "foo"."bar" echo "foo", "bar" 注意连接字符串的不同方式 - 使用 . 或 ,. 我意识到这两种方法之间的实际区别,使用 , 为关键
我有一个 RGB 图像,并尝试将 RGB 上的每个像素设置为黑色,其中相应的 alpha 像素也为黑色。所以基本上我试图将 Alpha“烘焙”到我的 RGB 中。我已经尝试使用 PIL 像素访问对象、
可能这个问题以前已经以许多不同的方式回答过很多次了。然而,我一直在寻找更具体的东西。通用词典,我相信比哈希表更快,因为它们不需要经历装箱/拆箱的过程。 但是,哈希表不是经过排序的,这意味着搜索可以更快
以这种方式加入给定的选择会更快吗 select ... join table1 on condition1 join table2 on condition2 然后这个 select ... join
我观看了演讲并阅读了博客文章,但我仍然不确定...这是为什么 template struct conditional { template using f = T; }; template<> str
我想知道用离散数据集编码的二维图形。对我来说,似乎由于计算机以离散集合运行,所以对图形做同样的事情也许更有意义。 例如,与其让一条线由两个 vector 表示,让计算机整理出像素配置,然后必须用代数方
我正在开发一个将大量数据写入磁盘的 C++ 程序。以下函数对数据进行 gzip 压缩并将其写入文件。压缩数据约为100GB。压缩并写出数据的函数如下: void constructSNVFastqD
我最近遇到了这段SQL: SELECT members.id FROM members, members_to_groups WHERE members.id = members_to_groups.
所以我一直在研究 pthreads,特别是尝试计算两个矩阵的乘积。我的代码非常困惑,因为它本应是我自己的一个快速有趣的小项目,但我使用的线程理论非常类似于: #include #include #
我看到了被选中的answer对此post . 我很惊讶 (x & 255) == (x % 256) 如果 x 是无符号整数,我想知道总是替换 % 是否有意义& in x % n for n = 2^
Anaconda是什么? Anaconda 是一个开源的 Python 发行版本,主要面向数据科学、机器学习和数据分析等领域。它不仅包含了 Python 解释器本身,更重要的是集成了大量的用于科学计
我正在使用Ubuntu 14.04操作系统的g2.8xlarge EC-2实例上启用cuDNN的情况下运行py-faster-rcnn。一切都已编译,似乎工作正常。我通过以下方式登录到远程实例: ss
要求用户输入的简单程序可以使用 datainputstream 或扫描仪。哪个会更快? Datainputstream 是二进制的,所以它可能更快?有意见吗?我只是很好奇,因为我正在构建一个程序,我希
我正在 INRIA Person 数据集上训练 Faster-RCNN(VGG-16 架构)。我接受了 180,000 个训练步骤的训练。但是当我评估网络时,它会用相同的图像给出不同的结果。以下是图片
我是 python 新手,我为 Hackerrank 问题提交了此代码 Arrays and Simple Queries ,但对于大量测试用例,程序“由于超时而终止”。我怎样才能提高效率? 我已将主
如果将程序分成头文件和源文件,如果提供给智能编译管理器,可能会受益于更快的编译,这就是我正在研究的内容。 理论工作的意愿:为每个源文件创建一个线程并一次将每个源文件编译成目标文件。然后将这些目标文件链
方法一: SELECT * FROM `wordpressusers` WHERE user_login='user10000001' PhpMyadmin 的结果: 方法2: SELECT user
据我所知set.add使用FastFloat的equals方法 对我来说重要的只是点后的前两位数(!!!),所以在 equals 方法中我使用 Math.abs() >= 0.001 来使 equal
我是一名优秀的程序员,十分优秀!