3 回答
TA贡献1802条经验 获得超10个赞
在《英特尔®64和IA-32架构开发人员手册》中。3A如今包含您提到的内存订购白皮书的规格,在第8.2.3.1节中说,正如您自己指出的那样,
Intel-64内存排序模型可确保以下各项
内存访问指令,似乎要执行组成内存操作
作为单个内存访问:
•读取或写入单个字节的指令。
•读取或写入地址(2字节)对齐的字(2个字节)的指令
字节边界。
•读取或写入地址对齐的双字(4个字节)的指令
在4个字节的边界上。
•读取或写入地址对齐在其上的四字(8字节)的指令
8字节边界。
任何锁定的指令(XCHG指令或其他读-修改-写
带有LOCK前缀的指令)似乎作为不可分割的和
不间断的装载顺序,然后是存储顺序,与对齐方式无关。
现在,由于上面的列表不包含双四字(16字节)的相同语言,因此该体系结构不保证访问16字节内存的指令是原子的。
话虽如此,最后一段确实暗示了一条出路,即带有LOCK前缀的CMPXCHG16B指令。您可以使用CPUID指令确定处理器是否支持CMPXCHG16B(“ CX16”功能位)。
在相应的AMD文档《AMD64技术AMD64体系结构程序员手册》第2卷:系统编程中,我找不到相似的清晰语言。
编辑:测试程序结果
(修改了测试程序,使#迭代次数增加了10倍)
在Xeon X3450(x86-64)上:
0000 999998139 1572
0001 0 0
0010 0 0
0011 0 0
0100 0 0
0101 0 0
0110 0 0
0111 0 0
1000 0 0
1001 0 0
1010 0 0
1011 0 0
1100 0 0
1101 0 0
1110 0 0
1111 1861 999998428
在Xeon 5150(32位)上:
0000 999243100 283087
0001 0 0
0010 0 0
0011 0 0
0100 0 0
0101 0 0
0110 0 0
0111 0 0
1000 0 0
1001 0 0
1010 0 0
1011 0 0
1100 0 0
1101 0 0
1110 0 0
1111 756900 999716913
在Opteron 2435(x86-64)上:
0000 999995893 1901
0001 0 0
0010 0 0
0011 0 0
0100 0 0
0101 0 0
0110 0 0
0111 0 0
1000 0 0
1001 0 0
1010 0 0
1011 0 0
1100 0 0
1101 0 0
1110 0 0
1111 4107 999998099
这是否意味着Intel和/或AMD保证16字节内存访问在这些计算机上是原子的?恕我直言,事实并非如此。它不在文档中作为保证的体系结构行为,因此无法知道在这些特定处理器上16字节内存访问是否确实是原子的,或者测试程序是否仅由于某种原因未能触发它们。因此依靠它是危险的。
编辑2:如何使测试程序失败
哈!我设法使测试程序失败。在与上述相同的Opteron 2435上,具有相同的二进制文件,但是现在通过“ numactl”工具运行它,指定每个线程在单独的套接字上运行,我得到:
0000 999998634 5990
0001 0 0
0010 0 0
0011 0 0
0100 0 0
0101 0 0
0110 0 0
0111 0 0
1000 0 0
1001 0 0
1010 0 0
1011 0 0
1100 0 1不是单个内存访问!
1101 0 0
1110 0 0
1111 1366 999994009
那么,这意味着什么呢?好吧,Opteron 2435可以保证也可以不保证16字节内存访问对于套接字内访问是原子的,但是至少在两个套接字之间的HyperTransport互连上运行的缓存一致性协议不能提供这种保证。
编辑3:应“ GJ”请求,用于线程功能的ASM。
这是为Opteron 2435系统上使用的GCC 4.4 x86-64版本的线程函数生成的asm:
.globl thread2
.type thread2, @function
thread2:
.LFB537:
.cfi_startproc
movdqa .LC3(%rip), %xmm1
xorl %eax, %eax
.p2align 5,,24
.p2align 3
.L11:
movaps x(%rip), %xmm0
incl %eax
movaps %xmm1, x(%rip)
movmskps %xmm0, %edx
movslq %edx, %rdx
incl n2(,%rdx,4)
cmpl $1000000000, %eax
jne .L11
xorl %eax, %eax
ret
.cfi_endproc
.LFE537:
.size thread2, .-thread2
.p2align 5,,31
.globl thread1
.type thread1, @function
thread1:
.LFB536:
.cfi_startproc
pxor %xmm1, %xmm1
xorl %eax, %eax
.p2align 5,,24
.p2align 3
.L15:
movaps x(%rip), %xmm0
incl %eax
movaps %xmm1, x(%rip)
movmskps %xmm0, %edx
movslq %edx, %rdx
incl n1(,%rdx,4)
cmpl $1000000000, %eax
jne .L15
xorl %eax, %eax
ret
.cfi_endproc
为了完整起见,.LC3是包含thread2使用的(-1,-1,-1,-1)向量的静态数据:
.LC3:
.long -1
.long -1
.long -1
.long -1
.ident "GCC: (GNU) 4.4.4 20100726 (Red Hat 4.4.4-13)"
.section .note.GNU-stack,"",@progbits
另请注意,这是AT&T ASM语法,而不是Windows程序员可能更熟悉的Intel语法。最后,这是进行曲=本机,这使GCC更喜欢MOVAPS;但这没关系,如果我使用march = core2,它将使用MOVDQA来存储到x,并且仍然可以重现故障。
TA贡献1824条经验 获得超6个赞
的“AMD架构程序员手册卷1:应用程序编程”表示在节3.9.1:“ CMPXCHG16B可被用来执行在64位模式的16字节的原子访问(与某些对齐限制)”。
但是,没有关于SSE指令的评论。实际上,在4.8.3中有一条注释,即LOCK前缀“与128位媒体指令一起使用时会导致无效操作码异常”。因此,在我看来,AMD处理器不能保证对SSE指令进行原子128位访问是完全结论性的,并且进行原子128位访问的唯一方法是使用CMPXCHG16B。
“ 英特尔64和IA-32体系结构软件开发人员手册第3A卷:系统编程指南,第1部分 ”在8.1.1中说:“可以使用多次内存访问来实现访问大于四字的数据的x87指令或SSE指令。 ” 这是非常确定的,ISA不能保证128位SSE指令是原子的。 英特尔文档的第2A卷说CMPXCHG16B:“此指令可以与LOCK前缀一起使用,以允许原子执行该指令。”
此外,在这种情况下,CPU制造商尚未发布针对特定CPU型号的128b SSE原子操作的书面保证。
- 3 回答
- 0 关注
- 913 浏览
添加回答
举报