8

我今天正在分析一个程序,它执行大量缓冲网络活动,该程序大部分时间都在 memcpy 中,只是在库管理的网络缓冲区和它自己的内部缓冲区之间来回移动数据。

这让我想到,为什么英特尔没有“memcpy”指令允许 RAM 本身(或非 CPU 内存硬件)在不接触 CPU 的情况下移动数据?因为每个字都必须一直传送到 CPU,然后再推回,此时整个事情都可以由内存本身异步完成。

是否有一些架构上的原因导致这不切实际?显然,有时副本会介于物理内存和虚拟内存之间,但如今这些情况随着 RAM 的成本而减少。有时处理器最终会等待复制完成,以便它可以使用结果,但肯定并非总是如此。

4

3 回答 3

3

这是一个包括网络堆栈效率在内的大问题,但我会坚持你对指令的具体问题。您建议的是异步非阻塞复制指令,而不是现在使用“rep mov”可用的同步阻塞 memcpy。

一些架构和实际问题:

1) 非阻塞 memcpy 必须消耗一些物理资源,如复制引擎,其生命周期可能与相应的操作系统进程不同。这对操作系统来说是相当讨厌的。假设线程 A 在上下文切换到线程 B 之前启动了 memcpy。线程 B 也想做一个 memcpy,并且优先级比 A 高得多。它必须等待线程 A 的 memcpy 完成吗?如果 A 的 memcpy 是 1000GB 长怎么办?在核心中提供更多的复制引擎会延迟但不能解决问题。基本上,这打破了传统的操作系统时间量子和调度机制。

2)为了像大多数指令一样通用,任何代码都可以随时发出 memcpy 指令,而不考虑其他进程已经完成或将要做什么。内核在任何时候都必须对运行中的异步 memcpy 操作的数量有一定的限制,因此当下一个进程出现时,它的 memcpy 可能处于任意长的 backlog 的末尾。异步副本缺乏任何确定性,开发人员只会退回到老式的同步副本。

3) 缓存局部性对性能具有一阶影响。已经在 L1 缓存中的缓冲区的传统副本非常快且相对节能,因为至少目标缓冲区仍然位于内核的 L1 本地。在网络复制的情况下,从内核到用户缓冲区的复制发生在将用户缓冲区交给应用程序之前。因此,该应用程序享有 L1 命中率和出色的效率。如果异步 memcpy 引擎存在于核心以外的任何地方,则复制操作会将行从核心中拉出(窥探),从而导致应用程序缓存未命中。净系统效率可能会比今天差得多。

4) asynch memcpy 指令必须返回某种标识副本的令牌,以便稍后使用以询问副本是否完成(需要另一条指令)。给定令牌,核心将需要对特定的待处理或正在运行的副本执行某种复杂的上下文查找——与核心微码相比,这些操作由软件更好地处理。如果操作系统需要终止进程并清除所有正在进行的和挂起的 memcpy 操作怎么办?操作系统如何知道一个进程使用该指令的次数以及哪些相应的令牌属于哪个进程?

- - 编辑 - -

5)另一个问题:核心之外的任何复制引擎都必须与核心的缓存带宽竞争原始复制性能,这非常高——远高于外部内存带宽。对于缓存未命中,内存子系统同样会成为同步和异步 memcpy 的瓶颈。对于至少有一些数据在缓存中的任何情况,这是一个不错的选择,核心将比外部复制引擎更快地完成复制。

于 2011-08-14T03:45:17.560 回答
1

净胜?

目前尚不清楚实现异步复制引擎是否会有所帮助。这种事情的复杂性会增加可能会抵消好处的开销,并且仅对于少数几个受 memcpy() 绑定的程序来说是不值得的。

更重的用户上下文?

实现将涉及用户上下文或每个核心资源。一个迫在眉睫的问题是,由于这是一项可能需要长时间运行的操作,它必须允许中断并自动恢复。

这意味着如果实现是用户上下文的一部分,它代表了更多必须在每次上下文切换时保存的状态,或者它必须覆盖现有状态。

覆盖现有状态正是字符串移动指令的工作方式:它们将参数保存在通用寄存器中。但是如果现有状态被消耗,那么这个状态在操作过程中就没有用了,那么最好只使用字符串移动指令,这就是内存复制功能的实际工作方式。

还是遥远的内核资源?

如果它使用某种每核状态,那么它必须是内核管理的资源。随之而来的环交叉开销(内核陷阱和返回)非常昂贵,并且会进一步限制收益或将其变成惩罚。

主意!让那个超快的 CPU 来做吧!

另一种看待这个问题的方式是,在所有这些高速缓存存储器环的中心已经有一个高度调整和非常快速的内存移动引擎,必须与移动结果保持一致。那件事:CPU。如果程序需要这样做,那么为什么不将快速而精细的硬件应用到问题上呢?

于 2011-08-14T06:29:13.233 回答
1

以前的 PC 架构中的DMA 控制器曾经支持内存到内存的传输。今天的其他架构中也存在类似的支持(例如 TI 达芬奇或OMAP处理器)。

问题是它会占用您的内存带宽,这可能是许多系统的瓶颈。正如 srking 的回答所暗示的那样,将数据读取到 CPU 的缓存中,然后将其复制到那里可以比内存到内存 DMA 更有效。即使 DMA 似乎在后台工作,也会与 CPU 发生总线争用。没有免费的午餐。

更好的解决方案是某种零复制架构,其中缓冲区在应用程序和驱动程序/硬件之间共享。也就是说,传入的网络数据直接读取到预分配的缓冲区中,不需要复制,而传出的数据直接从应用程序的缓冲区中读取到网络硬件。我已经在嵌入式/实时网络堆栈中看到了这一点。

于 2011-08-14T06:07:06.440 回答