Ale*_*lex 3 concurrency x86 multithreading x86-64 hyperthreading
超线程技术是英特尔推出的一种同步多线程技术.
这些资源包括执行引擎,缓存和系统总线接口; 资源共享允许两个逻辑处理器更有效地相互协作,并允许停滞的逻辑处理器从另一个逻辑处理器借用资源.
在具有超线程的Intel CPU中,一个CPU内核(具有多个ALU)可以在同一时钟执行来自2个线程的指令.两个线程共享:存储缓冲区,缓存L1/L2和系统总线.
但是如果两个线程在一个Core上同时执行,则thread-1存储原子值,而thread-2加载此值,将用于此交换的内容:共享存储缓冲区,共享缓存L1/L2还是通常的缓存L3?
如果两个线程来自同一个进程(相同的虚拟地址空间)和两个不同进程(不同的虚拟地址空间),会发生什么?
Sandy Bridge Intel CPU - 缓存L1:
低12位 - 对于确定当前设定数值很重要
4 KB - 标准页面大小
我想你会去往L1的往返.(与单个线程中的store-> load forwarding不同,这比这更快.)
英特尔的优化手册说,存储和加载缓冲区在线程之间是静态分区的,这告诉我们很多关于它如何工作的信息.我还没有测试过大部分内容,所以如果我的预测与实验不符,请告诉我.
更新:请参阅此问答,了解吞吐量和延迟的一些实验性测试.
存储必须在写入线程中退出,然后在一段时间之后从存储缓冲区/队列中提交到L1 .此时它将对另一个线程可见,并且来自任一线程的该地址的加载应该在L1中命中.在此之前,另一个线程应该使用旧数据获得L1命中,并且存储线程应该通过store-> load forwarding获取存储的数据.
存储数据在存储uop执行时进入存储缓冲区,但是在知道它是非推测性的,即它退出之前,它不能提交给L1.但是,存储缓冲区还将退出与ROB(无序核心中的ReOrder缓冲区)与对L1的承诺分离,这对于缓存中的存储非常有用.无序核心可以继续工作,直到存储缓冲区填满为止.
如果不使用内存防护,则在具有超线程的同一核心上运行的两个线程可以看到StoreLoad重新排序,因为线程之间不会发生存储转发. Jeff Preshing的内存重新排序在Act代码中可以用来在实践中测试它,使用CPU亲和性来运行同一物理内核的不同逻辑CPU上的线程.
一个原子读-修改-写操作必须做出其商店全局可见的(提交到L1)作为其执行的一部分,否则它不会是原子.只要数据不跨越高速缓存行之间的边界,它就可以锁定该高速缓存行.(AFAIK这就是CPU通常如何实现原子RMW操作,如lock add [mem], 1
或lock cmpxchg [mem], rax
.)
无论哪种方式,一旦完成,数据将在核心的L1缓存中变热,其中任一线程都可以通过加载来获得缓存命中.
我怀疑两个超线程对共享计数器(或任何其他lock
ed操作,如同xchg [mem], eax
)执行原子增量将实现与单个线程大致相同的吞吐量.这比在单独的物理内核上运行的两个线程要高得多,其中高速缓存行必须在两个内核的L1高速缓存之间跳转(通过L3).
movNT
(非时间)弱排序存储绕过缓存,并将其数据放入行填充缓冲区.如果它在缓存中很热,它们也会从L1中驱逐该行.它们可能必须在数据进入填充缓冲区之前退出,因此来自另一个线程的负载在进入填充缓冲区之前可能根本看不到它.然后可能它与一个movnt存储相同,后面是一个线程内的加载.(即到DRAM的往返,几百个周期的延迟).不要将NT存储用于您希望另一个线程立即读取的一小段数据.
由于Intel CPU共享L1缓存的方式,L1命中是可能的. 英特尔在其大多数(全部?)设计中使用虚拟索引,物理标记(VIPT) L1缓存.(例如Sandybridge系列.)但是由于索引位(选择一组8个标签)低于页面偏移量,因此它的行为与PIPT高速缓存完全相同(将其视为低12位的转换为无 - op),但具有VIPT缓存的速度优势:它可以与TLB查找并行地从集合中获取标记以转换高位.请参阅本答复中的"L1也使用速度技巧,如果它更大则无效"段落.
由于L1d缓存的行为类似于PIPT,并且相同的物理地址实际上意味着相同的内存,因此对于缓存行是否具有相同虚拟地址的相同进程的2个线程无关紧要,或者它是否是映射块的两个独立进程共享内存到每个进程中的不同地址.这就是为什么L1d可以(并且是)两种超线程的竞争性,而没有误报高速缓存命中的风险.与dTLB不同,后者需要使用核心ID标记其条目.
此答案的先前版本在此处有一段基于Skylake降低L1关联性的错误观点.这是Skylake的L2,这是4路,而在Broadwell和之前的8路.尽管如此,关于更近期答案的讨论可能会引起关注.
英特尔的x86手册vol3,第11.5.6章说明了Netburst(P4)可以选择不以这种方式工作.默认为"自适应模式",它允许核心内的逻辑处理器共享数据.
有一个"共享模式":
在共享模式下,L1数据高速缓存在逻辑处理器之间竞争性地共享.即使逻辑处理器使用相同的CR3寄存器和分页模式也是如此.
在共享模式下,L1数据高速缓存中的线性地址可以是别名,这意味着高速缓存中的一个线性地址可以指向不同的物理位置.解决混叠的机制可能导致颠簸.因此,IA32_MISC_ENABLE [bit 24] = 0是基于支持Intel超线程技术的Intel NetBurst微体系结构的处理器的首选配置
在Nehalem/SnB的搜索中,对于超线程没有任何说明,所以我认为当他们在另一个uarch中引入HT支持时,他们不包括"慢模式"支持,因为他们知道他们已经获得了"快速模式"在netburst中正常工作.我有点想知道这种模式是否仅存在,以防他们发现了一个错误并且不得不通过微码更新来禁用它.
本回答的其余部分仅解决了P4的正常设置,我非常确定Nehalem和SnB系列CPU的工作方式.
理论上可以构建一个OOO SMT CPU内核,它可以在退出时立即从一个线程看到另一个线程的存储,但是在它们离开存储缓冲区并提交到L1d之前(即在它们变为全局可见之前).这不是英特尔设计的工作方式,因为它们静态地对存储队列进行分区而不是竞争性地共享它.
即使线程共享一个存储缓冲区,也不允许在尚未退出的存储的线程之间存储转发,因为它们在那时仍然是推测性的.这会将两个线程捆绑在一起,造成分支错误预测和其他回滚.
对多个硬件线程使用共享存储队列将需要额外的逻辑来始终转发到来自同一线程的加载,但仅将退役存储转发到来自其他线程的加载.除晶体管数量外,这可能会产生很大的功率成本.您不能完全省略非退役商店的商店转发,因为这会破坏单线程代码.
有些POWER CPU实际上可能会这样做; 对于并非所有线程都同意商店的单一全球订单,这似乎是最可能的解释. 是否会有其他线程以相同的顺序看到两个原子写入不同线程中的不同位置?.
正如@BeeOnRope所指出的,这不适用于x86 CPU,仅适用于不保证Total Store Order的ISA ,因为这样可以让SMT兄弟在看到你的商店全局可见之前看到你的商店.其他核心.
TSO可以通过将来自兄弟存储缓冲区的数据视为推测来保存,或者在任何缓存未命中加载之前不能发生(因为在L1D缓存中保持热的行不能包含来自其他核的新存储).IDK,我没有完全想到这一点.它似乎过于复杂,可能无法在保持TSO的同时进行有用的转发,甚至超出了拥有共享存储缓冲区或探测同级存储缓冲区的复杂性.
归档时间: |
|
查看次数: |
721 次 |
最近记录: |