performance - 生产者-消费者在超同级与非超同级之间共享内存位置的延迟和吞吐量成本是多少?

标签 performance concurrency x86 hyperthreading

单个进程中的两个不同线程可以通过读取和/或写入共享一个公共(public)内存位置。

通常,这种(有意的)共享是通过使用 lock 的原子操作来实现的。 x86 上的前缀,对于 lock前缀本身(即非竞争成本)以及缓存行实际共享时的额外一致性成本(true 或 false 共享)。

在这里,我对单线程 P 的生产消费者成本感兴趣。写入内存位置,另一个线程`C从内存位置读取,都使用普通读取和写入。

当在同一插槽上的不同内核上执行此类操作时,以及在最近的 x86 内核上在同一物理内核上的兄弟超线程上执行时,此类操作的延迟和吞吐量是多少。

在标题中,我使用术语“超 sibling ”来指代在同一内核的两个逻辑线程上运行的两个线程,而内核间 sibling 是指在不同物理内核上运行的两个线程的更常见情况.

最佳答案

杀手问题是内核进行推测性读取,这意味着每次写入推测性读取地址(或更正确地写入同一高速缓存行)在“完成”之前意味着 CPU 必须撤消读取(至少如果您是 x86),这实际上意味着它会取消该指令及以后的所有推测指令。

在读取退出之前的某个时刻,它会“完成”,即。以前的任何指令都不会失败,也没有任何理由重新发出,CPU 可以像以前执行过所有指令一样行事。

其他核心示例

除了取消指令之外,它们还在播放缓存乒乓球,所以这应该比 HT 版本更糟。

让我们从流程中的某个点开始,其中包含共享数据的缓存行刚刚被标记为共享,因为消费者要求读取它。

  • 生产者现在想要写入共享数据,并发送缓存行的独占所有权请求。
  • 消费者收到仍处于共享状态的缓存行并愉快地读取该值。
  • 消费者继续读取共享值,直到独占请求到达。
  • 此时,消费者发送缓存行的共享请求。
  • 此时,消费者从共享值的第一个未完成的加载指令中清除其指令。
  • 当消费者等待数据时,它会投机地运行。

  • 因此,消费者可以在它获得共享缓存行之间的时间段内前进,直到它再次失效。不清楚可以同时完成多少次读取,很可能是 2 次,因为 CPU 有 2 个读取端口。只要 CPU 的内部状态得到满足,它就不需要重新运行它们,它们不能在每个之间都不会失败。

    同核HT

    这里两个HT共享核心,必须共享资源。

    缓存行应该始终保持独占状态,因为它们共享缓存,因此不需要缓存协议(protocol)。

    现在为什么在 HT 核心上需要这么多周期?让我们从刚刚读取共享值的消费者开始。
  • 下一个周期发生来自 Produces 的写入。
  • 消费者线程检测到写入并取消其第一次未完成读取的所有指令。
  • 消费者重新发出指令,需要大约 5-14 个周期才能再次运行。
  • 最后,第一条指令(即读取)被发出并执行,因为它没有读取推测值,而是读取了队列前面的正确值。

  • 因此,对于每次读取共享值,消费者都会重置。

    结论

    不同的核心显然每次在每个缓存乒乓之间进步如此之多,以至于它的性能比 HT 更好。

    如果 CPU 等着看这个值是否真的改变了,会发生什么?

    对于测试代码,HT 版本的运行速度会快得多,甚至可能与私有(private)写入版本一样快。由于缓存未命中覆盖了重新发布延迟,因此不同的核心不会运行得更快。

    但是如果数据不同,就会出现同样的问题,除了不同的核心版本会更糟,因为它还必须等待缓存行,然后重新发布。

    因此,如果 OP 可以更改一些角色,让时间戳生产者从共享中读取并承受性能损失,那就更好了。

    阅读更多 here

    关于performance - 生产者-消费者在超同级与非超同级之间共享内存位置的延迟和吞吐量成本是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45602699/

    相关文章:

    Python 与 MATLAB 在算法上的性能

    Python 线程不适用于 pygobject?

    c++ - std::atomic bool 变量的访问顺序

    c++ - 如何在 Visual C++ 内联汇编程序中通过引用获取值?

    assembly - .code16 和 .code32 有什么区别

    assembly - 跳入保护模式时出现三重故障

    c++ - 使用缓冲在 C++ 中逐行读取巨大的文本文件

    c# - 重载或可选参数之间的性能差异?

    javascript - Firefox 中屏幕外 Canvas 的性能问题

    java - CountDownLatch.await/countDown 与 Thread.join/interrupt 等待单个 Runnable