关于缓存未命中的 x86 超线程说明

Onu*_*mus 2 cpu multithreading cpu-architecture hyperthreading

如果我对 x86 cpu 的理解正确,超线程是有益的,尤其是当我们有 IO 调用时,这样当阻塞线程空闲时,另一个线程可以廉价地在同一个 CPU 上工作。我的问题是缓存未命中是否也会发生同样的事情。那么在等待数百个周期从主内存中获取数据的同时,其他线程可以在同一个物理 CPU 上执行一些代码吗?

Lee*_*eor 6

答案是 - 是的,在一定范围内。

超线程确实允许您对两个程序上下文(操作系统可能会附加软件线程)进行细粒度交错。来自两个线程的指令和缓存数据将同时共存于内核中。

现在,在现代 CPU 中,您不仅仅是拥有一个大管道,您可以在每个周期的开始进行仲裁。相反,每个单元(内存单元、缓存、执行单元、乱序组件等)都有自己的管道和与其他单元的通信通道。其中一些单元被分区以支持 2 个线程,并且可以在每个周期选择从哪里获取下一个任务(假设它们有单独的传入队列可供选择)。其他单元可能会在线程之间复制,或者根据其他指标进行仲裁,当然是特定于实现的确切选择,但是每当有线程仲裁时,硬件将尝试平衡选择(例如执行循环) .

说一个线程被阻塞也不是简单的事情,一个有未决内存请求的线程可能仍然会提前获取,甚至执行非依赖的操作。从分支错误预测中恢复的线程已经可以在正确的路径之前预取 - 事情总是会完成。但是,在任何给定的单元上,您可能会发现一个线程确实卡住了,在这种情况下,仲裁通常会支持另一个线程。因此,当一个线程在 CPU 的某些部分无法进行处理时,另一个线程将有效地获得该资源的更大时间份额。然而,被阻塞的线程可能仍在以一种限制空闲资源的方式使用该资源的一部分,所以说当一个线程被阻塞时,另一个线程可以自由支配核心,甚至某些单元是错误的。它只是获得了更好的份额。

例如,由于您询问了内存访问 - 当线程未命中缓存并退出(到下一级缓存或主内存)时,所需的数据可能会导致数据依赖停顿,从而阻止执行新指令,并且因此可能会减少未来依赖的内存访问(如果你正在遍历一个链表,你会被卡住,但如果你正在遍历一个数组,你甚至不会注意到这一点)。这将为另一个线程提供更多的内存单元(以及那里最重要的资源 - 错过缓冲区以保存需要发送到外部的请求)。从长远来看,结果可能会显示出更好的性能。