Data Fetching中的多核干扰

在基于强化学习的数据预取中,多核之间的相互干扰是目前急需解决的难题,如何解决多核之间的资源分配是目前比较热门的方向。这篇Blog主要叙述一下分配的资源都有哪些,它们又是如何被干扰的。总而言之,预取带来的收益,必须大于它消耗的共享资源。

LLC缓存干扰

很明显在数据预取的时候,肯定会占用cache缓存。对于多核而言,LLC共用缓存显然是大家需要抢占的资源。如果有一个核心疯狂把数据拉进LLC,显然会将其他核心的cache line挤了出去,结果导致:

  • 其它核心的命中率下降
  • 更多访问走到内存,严重降低效率

DRAM带宽干扰

如果一个核预取很多无用或过早的数据,它会占掉 DRAM 带宽、片上总线带宽、内存控制器队列项。这样另一个核的真实 demand miss(真正需要的数据)就可能被拖慢。其实和LLC干扰有些类似。

也就是说,预取本来是为了“隐藏延迟”,但在多核下可能变成:

  • 自己核的预取请求
  • 挤占别的核的 demand 请求
  • 让整体吞吐下降

抢 MSHR / Fill Buffer / 请求队列

除了缓存容量和带宽,还会争抢很多内部硬件表项,比如:

  • MSHR(miss status holding registers)
  • fill buffer
  • cache miss queue
  • memory controller request queue

这些资源数量都有限。 一个核如果预取很多流,会把这些表项占满,导致另一个核即使发生真正的 cache miss,也没法及时发出去,形成head-of-line blocking 或队列拥塞。

增加一致性流量

如果预取的是共享数据,甚至是会被多个核读写的数据,还可能引发额外的一致性活动。

例如:

  • 一个核预取到某个 cache line

  • 另一个核很快写这个 line

  • 预取进来的副本马上失效

  • 产生额外 snoop / invalidate / coherence traffic

如果程序本来就有false sharing(伪共享),预取器可能把这种无效流量进一步放大。

影响内存调度公平性

多个核一起跑时,内存控制器通常要在不同请求流之间调度。预取请求如果太多,会改变控制器看到的请求分布,可能出现:

  • 某些核更容易“占住”队列

  • 行缓冲命中模式被改变

  • 某个应用延迟被拉高

  • 系统公平性变差

所以在服务器/多程序负载中,经常会看到:单核测得很有效的预取策略,一到多核就收益下降甚至变负。