【问题标题】:DMA cache coherence managementDMA 缓存一致性管理
【发布时间】:2011-10-31 05:30:56
【问题描述】:

我的问题是:当我在设备驱动程序中正确使用[pci_]dma_sync_single_for_{cpu,device} 时,如何确定何时可以安全地禁用缓存侦听?

我正在为通过 PCI Express (DMA) 直接写入 RAM 的设备开发设备驱动程序,并且担心管理缓存一致性。我可以在启动 DMA 时设置一个控制位,以在 DMA 期间启用或禁用缓存侦听,显然为了提高性能,我希望尽可能禁用缓存侦听。

在中断例程中,当切换 DMA 缓冲区时,我酌情调用 pci_dma_sync_single_for_cpu()..._for_device(),但在 32 位 Linux 2.6.18 (RHEL 5) 上,事实证明这些命令是扩展为空的宏。 .. 这解释了为什么我的设备在此内核上禁用缓存侦听时返回垃圾!

我浏览了内核源代码的历史,似乎在 2.6.25 之前只有 64 位 x86 具有用于 DMA 同步的挂钩。从 2.6.26 开始,似乎有一个通用的统一间接机制,用于通过 dma_map_ops 的字段 sync_single_for_{cpu,device} 进行 DMA 同步(目前在 include/asm-generic/dma-mapping-common.h),但到目前为止我还没有找到这些操作的任何定义。

【问题讨论】:

  • 有一些关于 DMA 和缓存一致性的 lwn 文章,您可能想在 lwn.net 上查看
  • 您是否衡量了通过禁用缓存侦听获得的性能提升,不仅在传输本身上,而且在整个应用程序上? DMA 相干性非常方便,并且让我更容易考虑与硬件交互,因此我会在关闭它之前仔细测量。

标签: linux linux-kernel kernel dma


【解决方案1】:

也许有点过期了,但是:

如果您禁用缓存侦听,硬件将不再负责缓存一致性。因此,内核需要自己做这件事。在过去的几天里,我花了一些时间审查 [pci_]dma_sync_single_for_{cpu,device} 的 X86 变体。我没有发现任何迹象表明他们会做出任何努力来保持一致性。这似乎与 PCI(e) 规范中默认开启缓存侦听这一事实一致。

因此,如果您要关闭缓存侦听,您必须自己在驱动程序中保持一致性。可能通过调用 clflush_cache_range() (X86) 或类似方法?

参考:

【讨论】:

    【解决方案2】:

    我真的很惊讶没有人回答这个问题,所以这里我们继续一个非 Linux 特定的答案(我对 Linux 内核本身的了解不够具体)...

    缓存侦听只是告诉 DMA 控制器向所有 CPU 发送缓存失效请求,以获取 DMA 进入的内存。这显然增加了高速缓存一致性总线的负载,并且随着处理器的增加,它的扩展性特别差,因为并非所有 CPU 都会与发出窥探的 DMA 控制器具有单跳连接。因此,“何时可以安全地禁用缓存侦听”的简单答案是,当被 DMA 写入的内存在任何 CPU 缓存中都不存在,或者其缓存行被标记为无效时。换句话说,任何从 DMA 区域读取的尝试都将总是导致从主内存读取。

    那么,如何确保从 DMA 区域读取的内容始终会进入主内存?

    在我们拥有 DMA 缓存侦听等花哨功能之前的一天,我们过去所做的是将 DMA 内存流水线化,方法是通过以下一系列分解阶段对其进行馈送:

    第 1 阶段:将“脏”DMA 内存区域添加到“脏且需要清理”的 DMA 内存列表。

    第 2 阶段:下次设备以新的 DMA 数据中断时,为所有可能访问这些块的 CPU(通常每个CPU 运行自己的由本地内存块组成的列表)。将所述段移动到“干净”列表中。

    第 3 阶段:下一个 DMA 中断(当然,您确定在上一个缓存失效完成之前不会发生),从“干净”列表中获取一个新区域并告诉设备它的下一个 DMA 应该进入那。回收任何脏块。

    第 4 阶段:重复。

    尽管这是更多的工作,但它有几个主要优点。首先,您可以将 DMA 处理固定到单个 CPU(通常是主 CPU0)或单个 SMP 节点,这意味着只有单个 CPU/节点需要担心缓存失效。其次,您可以让内存子系统有更多机会为您隐藏内存延迟,方法是随着时间的推移分散操作并分散缓存一致性总线上的负载。性能的关键通常是尝试使任何 DMA 发生在尽可能靠近相关 DMA 控制器的 CPU 上,并尽可能靠近该 CPU 进入内存。

    如果您总是将新进入内存的 DMA 移交给用户空间和/或其他 CPU,只需在异步缓存无效管道的前端注入新获取的内存即可。一些操作系统(不确定Linux)有一个优化的例程用于预置零内存,因此操作系统基本上在后台将内存清零并保持快速满足缓存 - 将新内存请求保持在该缓存量以下是值得的,因为清零内存非常慢。我不知道过去十年中生产的任何平台使用硬件卸载内存归零,因此您必须假设所有新内存可能包含需要失效的有效缓存行。

    我很感激这只回答了你问题的一半,但总比没有好。祝你好运!

    尼尔

    【讨论】:

      猜你喜欢
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-20
      • 2011-10-22
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多