gpt4 book ai didi

multithreading - 使用 HT 在一个 Core 上执行的线程之间的数据交换将使用什么?

转载 作者:行者123 更新时间:2023-12-04 06:43:08 25 4
gpt4 key购买 nike

Hyper-Threading Technology is a form of simultaneous multithreadingtechnology introduced by Intel.

These resources include the execution engine, caches, and system businterface; the sharing of resources allows two logical processors towork with each other more efficiently, and allows a stalled logicalprocessor to borrow resources from the other one.


在具有超线程的 Intel CPU 中,一个 CPU-Core(带有多个 ALU)可以在同一时钟下执行来自 2 个线程的指令。并且两个线程共享:存储缓冲区、缓存 L1/L2 和系统总线。
但是如果两个线程在一个 Core 上同时执行,线程 1 存储原子值,线程 2 加载这个值,那么这个交换将使用什么:共享存储缓冲区、共享缓存 L1/L2 或像往常一样缓存 L3?
如果两个线程来自同一个进程(相同的虚拟地址空间),如果来自两个不同的进程(不同的虚拟地址空间),会发生什么?
Sandy Bridge Intel CPU - 缓存 L1:
  • 32 KB - 缓存大小
  • 64 B - 缓存行大小
  • 512 - 行 (512 = 32 KB/64 B)
  • 8路
  • 64 - 路数组(64 = 512 行/8 路)
  • 6 位 [11:6] - 虚拟地址(索引)定义当前集编号 (这是标签)
  • 4 K - 每个相同(虚拟地址/4 K)竞争同一组(32 KB/8路)
  • 低 12 位 - 对确定当前集合编号很重要
  • 4 KB - 标准页面大小
  • 低 12 位 - 虚拟地址和物理地址相同 每个地址

  • enter image description here

    最佳答案

    我想你会得到一个到 L1 的往返。 (与单线程中的 store->load forwarding 不同,它甚至比这更快。)

    Intel's optimization manual says that store and load buffers are statically partitioned between threads ,它告诉我们很多关于这将如何工作的信息。我还没有测试过大部分内容,所以如果我的预测与实验不符,请告诉我。

    更新:有关吞吐量和延迟的一些实验性测试,请参阅 this Q&A

    存储必须在写入线程中退出,然后在一段时间后从 store buffer/queue 提交到 L1。那时它对另一个线程是可见的,并且从任一线程加载到该地址应该在 L1 中命中。在此之前,另一个线程应该使用旧数据获得 L1 命中,存储线程应该通过 store->load forwarding 获得存储的数据。

    当存储 uop 执行时,存储数据进入存储缓冲区,但它不能提交到 L1,直到知道它是非推测性的,即它退休。但是存储缓冲区也将退出从 ROB(乱序核心中的重新排序缓冲区)与对 L1 的 promise 分离,这对于缓存中未命中的存储非常有用。乱序核心可以继续工作,直到存储缓冲区填满。

    如果两个线程使用超线程在同一个内核上运行,则它们可以看到 StoreLoad 重新排序,如果它们不使用内存栅栏,因为存储转发不会在线程之间发生。 Jeff Preshing's Memory Reordering Caught in the Act 代码可用于在实践中对其进行测试,使用 CPU 亲和性在同一物理内核的不同逻辑 CPU 上运行线程。

    作为执行的一部分,atomic read-modify-write operation 必须使其存储全局可见(提交到 L1),否则它不会是原子的。只要数据不跨越缓存行之间的边界,它就可以锁定该缓存行。 (AFAIK 这就是 CPU 通常如何实现原子 RMW 操作,如 lock add [mem], 1lock cmpxchg [mem], rax 。)

    无论哪种方式,一旦完成,数据将在核心的 L1 缓存中很热,其中任何一个线程都可以通过加载它来获得缓存命中。

    我怀疑对共享计数器(或任何其他 lock ed 操作,如 xchg [mem], eax )执行原子增量的两个超线程将实现与单个线程大致相同的吞吐量。这比运行在单独物理内核上的两个线程要高得多,其中缓存线必须在两个内核的 L1 缓存之间(通过 L3)反弹。
    movNT(非临时)弱排序存储绕过缓存,并将其数据放入行填充缓冲区。如果开始时缓存中的行很热,他们还会从 L1 中驱逐该行。在数据进入填充缓冲区之前,它们可能必须退出,因此来自其他线程的加载可能根本看不到它,直到它进入填充缓冲区。那么它可能与 movnt 存储相同,然后是单个线程内的负载。 (即到 DRAM 的往返,几百个周期的延迟)。不要将 NT 存储用于您希望另一个线程立即读取的一小段数据。

    由于 Intel CPU 共享 L1 缓存的方式,L1 命中是可能的。 英特尔在其大部分(全部?)设计中使用 virtually indexed, physically tagged (VIPT) L1 缓存。 (例如 the Sandybridge family 。)但是由于索引位(选择一组 8 个标签)低于页面偏移量,它的行为与 PIPT 缓存完全一样(将其视为低 12 位的转换是无操作) ,但具有 VIPT 缓存的速度优势:它可以与 TLB 查找并行地从集合中提取标签以转换高位。请参阅 this answer 中的“L1 也使用了如果它更大就不起作用的速度技巧”段落。

    由于 L1d 缓存的行为类似于 PIPT,并且相同的物理地址实际上意味着相同的内存,因此无论是同一进程的 2 个线程具有相同的缓存行虚拟地址,还是两个独立的进程映射一个块都无关紧要共享内存分配到每个进程中的不同地址。这就是为什么 L1d 可以(并且现在)被两个超线程竞争而没有误报缓存命中的风险。与需要使用核心 ID 标记其条目的 dTLB 不同。

    此答案的先前版本基于 Skylake 降低了 L1 关联性的错误想法,在此处有一段。 Skylake 的 L2 是 4 路,而 Broadwell 和更早版本是 8 路。不过,discussion on a more recent answer 可能会引起人们的兴趣。

    英特尔的 x86 manual vol3, chapter 11.5.6 文件表明 Netburst (P4) 可以选择不以这种方式工作 。默认值为“自适应模式”,它允许核心内的逻辑处理器共享数据。

    有一种“共享模式”:

    In shared mode, the L1 data cache is competitively shared between logical processors. This is true even if the logical processors use identical CR3 registers and paging modes.

    In shared mode, linear addresses in the L1 data cache can be aliased, meaning that one linear address in the cache can point to different physical locations. The mechanism for resolving aliasing can lead to thrashing. For this reason, IA32_MISC_ENABLE[bit 24] = 0 is the preferred configuration for processors based on the Intel NetBurst microarchitecture that support Intel Hyper-Threading Technology



    对于 Nehalem/SnB uarches 中的超线程,它没有说明任何事情,所以我假设他们在另一个 uarch 中引入 HT 支持时没有包含“慢速模式”支持,因为他们知道他们已经获得了“快速模式”以在 netburst 中正常工作。我有点想知道这个模式位是否只存在,以防他们发现错误并且不得不通过微码更新禁用它。

    本答案的其余部分仅针对 P4 的正常设置,我很确定这也是 Nehalem 和 SnB 系列 CPU 的工作方式。

    理论上有可能构建一个 OOO SMT CPU 内核,使一个线程中的存储在退出后立即对另一个线程可见,但在它们离开存储缓冲区并提交到 L1d 之前 (即在它们变得全局可见之前) .这不是英特尔的设计工作方式,因为它们静态地划分存储队列而不是竞争性地共享它。

    即使线程共享一个存储缓冲区,也不允许在线程之间为尚未退休的存储进行存储转发,因为在这一点上它们仍然是推测性的。这会将两个线程联系在一起以防止分支错误预测和其他回滚。

    为多个硬件线程使用共享存储队列将需要额外的逻辑来始终转发到来自同一线程的加载,但仅将停用的存储转发到来自其他线程的加载。除了晶体管数量外,这可能会产生巨大的电力成本。对于非退休商店,您不能完全省略商店转发,因为这会破坏单线程代码。

    一些 POWER CPU 实际上可能会这样做;对于并非所有线程都同意单一的全局商店订单,这似乎是最可能的解释。 Will two atomic writes to different locations in different threads always be seen in the same order by other threads?

    As @BeeOnRope points out ,这不适用于 x86 CPU,仅适用于不保证 Total Store Order 的 ISA,因为这会让 SMT 兄弟在它变得对其他核心全局可见之前看到您的商店。

    TSO 可以通过将来自同级存储缓冲区的数据视为推测来保留,或者无法在任何缓存未命中加载之前发生(因为在 L1D 缓存中保持热线的行不能包含来自其他内核的新存储)。 IDK,我还没有完全考虑清楚。这似乎过于复杂,可能无法在维护 TSO 的同时进行有用的转发,甚至超出共享存储缓冲区或探测同级存储缓冲区的复杂性。

    关于multithreading - 使用 HT 在一个 Core 上执行的线程之间的数据交换将使用什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32979067/

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