gpt4 book ai didi

concurrency - SSE指令: which CPUs can do atomic 16B memory operations?

转载 作者:行者123 更新时间:2023-12-03 09:08:38 27 4
gpt4 key购买 nike

考虑 x86 CPU 上的单次内存访问(单次读取或单次写入,而不是读取+写入)SSE 指令。该指令正在访问 16 字节(128 位)的内存,并且访问的内存位置与 16 字节对齐。

文档“英特尔® 64 位架构内存订购白皮书”指出,对于“读取或写入地址在 8 字节边界上对齐的四字(8 字节)的指令”而言,内存操作似乎作为单个内存访问执行,无论内存类型。

问题:是否存在 Intel/AMD/etc x86 CPU 可以保证读取或写入与 16 字节边界对齐的 16 字节(128 位)作为单个内存访问执行? 是这样,它是哪种特定类型的 CPU(Core2/Atom/K8/Phenom/...)?如果您对此问题提供答案(是/否),还请注明方法用于确定答案 - PDF 文档查找、蛮力测试、数学证明或用于确定答案的任何其他方法。

此问题涉及 http://research.swtch.com/2010/02/off-to-races.html 等问题。

更新:

我用 C 语言创建了一个简单的测试程序,您可以在计算机上运行它。请在您的 Phenom、Athlon、Bobcat、Core2、Atom、Sandy Bridge 或您碰巧拥有的任何支持 SSE2 的 CPU 上编译并运行它。谢谢。

// Compile with:
// gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.

#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;

unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));

void* thread1(void *arg) {
for (int i=0; i<100*1000*1000; i++) {
int mask = _mm_movemask_ps((__m128)x);
n1[mask]++;

x = (v4si){0,0,0,0};
}
return NULL;
}

void* thread2(void *arg) {
for (int i=0; i<100*1000*1000; i++) {
int mask = _mm_movemask_ps((__m128)x);
n2[mask]++;

x = (v4si){-1,-1,-1,-1};
}
return NULL;
}

int main() {
// Check memory alignment
if ( (((uintptr_t)&x) & 0x0f) != 0 )
abort();

memset(n1, 0, sizeof(n1));
memset(n2, 0, sizeof(n2));

pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);

for (unsigned i=0; i<16; i++) {
for (int j=3; j>=0; j--)
printf("%d", (i>>j)&1);

printf(" %10u %10u", n1[i], n2[i]);
if(i>0 && i<0x0f) {
if(n1[i] || n2[i])
printf(" Not a single memory access!");
}

printf("\n");
}

return 0;
}

我笔记本中的 CPU 是 Core Duo(不是 Core2)。这个特殊的 CPU 没有通过测试,它实现了 16 字节的内存读/写,粒度为 8 字节。输出是:
0000    96905702      10512
0001 0 0
0010 0 0
0011 22 12924 Not a single memory access!
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 3092557 1175 Not a single memory access!
1101 0 0
1110 0 0
1111 1719 99975389

最佳答案

Erik Rigtorp 对最近的 Intel 和 AMD CPU 进行了一些实验测试,以寻找撕裂。结果在 https://rigtorp.se/isatomic/ .请记住,没有关于这种行为的文档或保证,IDK 是否有可能使用这种 CPU 的自定义多插槽机器比他测试的机器具有更少的原子性。但是在当前的 x86 CPU(不是 K10)上,对齐加载/存储的 SIMD 原子性只是随着缓存和 L1d 缓存之间的数据路径宽度而缩放。



仅限 x86 ISA guarantees atomicity for things up to 8B ,因此实现可以像 Pentium III/Pentium M/Core Duo 那样自由地实现 SSE/AVX 支持:内部数据以 64 位的一半处理。一个 128 位存储作为两个 64 位存储完成。在 Yonah 微架构 (Core Duo) 中,进出缓存的数据路径只有 64b 宽。 (来源:Agner Fog's microarch doc)。

最近的实现在内部确实具有更宽的数据路径,并将 128b 指令作为单个操作处理。 Core 2 Duo (conroe/merom) 是第一个具有 128b 数据路径的 Intel P6 后裔微架构。 (关于 P4 的 IDK,但幸运的是它已经足够老了,完全无关紧要。)

这就是为什么 OP 发现 128b ops 在 Intel Core Duo (Yonah) 上不是原子的,但其他海报发现它们在后来的 Intel 设计中是原子的,从 Core 2 (Merom) 开始。

The diagrams on this Realworldtech writeup about Merom vs. Yonah显示 Merom(和 P4)中 ALU 和 L1 数据缓存之间的 128 位路径,而低功耗 Yonah 具有 64 位数据路径。在所有 3 种设计中,L1 和 L2 高速缓存之间的数据路径均为 256b。

数据路径宽度的下一个跳跃来自英特尔的 Haswell, featuring 256b (32B) AVX/AVX2 loads/stores ,以及 L1 和 L2 缓存之间的 64Byte 路径。我希望 256b 加载/存储在 Haswell、Broadwell 和 Skylake 中是原子的,但我没有要测试的。我忘记了 Skylake 是否再次拓宽了在 Skylake-EP(服务器版本)中为 AVX512 做准备的路径,或者 AVX512 的初始实现是否会像 SnB/IvB 的 AVX,并且有 512b 加载/存储占用加载/存储端口2个周期。

正如 janneb 在他出色的实验答案中指出的那样,多核系统中套接字之间的缓存一致性协议(protocol)可能比您在共享最后一级缓存 CPU 中获得的协议(protocol)更窄。对宽负载/存储的原子性没有架构要求,因此设计人员可以自由地将它们在套接字内设为原子,但如果方便,则在套接字之间设为非原子。 IDK 对于 AMD 的 Bulldozer 系列或 Intel 的套接字间逻辑数据路径有多宽。 (我说“逻辑”,因为即使数据以较小的 block 传输,它也可能在完全接收之前不会修改缓存行。)

查找有关 AMD CPU 的类似文章应该可以得出关于 128b 操作是否是原子的合理结论。仅检查指令表会有所帮助:

K8 解码 movaps reg, [mem]到 2 m-ops,而 K10 和推土机系列将其解码为 1 m-ops。 AMD 的低功耗 bobcat 将其解码为 2 ops,而 jaguar 将 128b movaps 解码为 1 m-op。 (它支持类似于推土机系列 CPU 的 AVX1:256b insns(甚至 ALU 操作)被拆分为两个 128b 操作。英特尔 SnB 仅拆分 256b 加载/存储,同时具有全宽 ALU。)

janneb 的 Opteron 2435 是 6-core Istanbul CPU, which is part of the K10 family ,所以这个单操作 -> 原子结论在单个套接字中看起来是准确的。

英特尔 Silvermont 使用单个 uop 进行 128b 加载/存储,每个时钟的吞吐量为 1。这与整数加载/存储相同,因此很可能是原子的。

关于concurrency - SSE指令: which CPUs can do atomic 16B memory operations?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7646018/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com