以低延迟访问 PCI 内存条 (Linux)
Posted
技术标签:
【中文标题】以低延迟访问 PCI 内存条 (Linux)【英文标题】:Access PCI memory BAR with low latency (Linux) 【发布时间】:2018-07-14 09:22:36 【问题描述】:背景:
我有一个 PCI 卡,它基本上是一个时钟。它通过 GPS 获取时间并将当前时间保存在某个寄存器中。
目标:
我想以尽可能低的延迟一遍又一遍地读取有限数量的寄存器/字节(例如当前时间)。 (时钟提供了非常高的精度,我认为延迟越高,精度就越低。)。操作系统是红帽。编程语言是 C/C++。我还想写入设备内存,因此延迟不是问题。
可能的方法:
我看到了这些方式。如果你看到另一个,请告诉我:
-
编写 Linux 内核模块驱动程序,该驱动程序创建一个字符设备(或一个字符设备供每个寄存器读取)。然后用户空间应用程序可以对 /dev/ 文件进行“读取”。
DMA
通过用户空间应用程序(系统调用)将 sysfs resourceX 文件映射到用户空间。 (例如here)
编写实现 mmap 文件操作的 Linux 内核模块驱动程序。
问题:
-
在实际读取寄存器时,哪种方式延迟最低?我知道 mmap 会在内核中造成大量开销,但据我所知,这仅用于初始化。
方式 3 是否合法?对我来说,这看起来像是一个黑客。如何从应用程序中自动确定 /sys/ 路径?
方式 3 和方式 4 有区别吗?我是 PCI 驱动程序编程的新手,我想我并不真正了解 4 的工作方式。我读过this(以及那本书的其他章节),但也许你可以给我一个提示或一个例子。我将不胜感激。
【问题讨论】:
在Linux中有一种VDSO机制,其目的之一是提供gettimeofday()
的最快方式。如果您的时钟驱动程序可以更新 VDSO 中的变量,那将是有史以来最快的方式。
【参考方案1】:
方法 3 或 4 应该可以正常工作。它们在延迟方面没有区别。延迟大约为 100 ns。
如果您需要初始化设备,或控制允许哪些应用程序访问它,或一次强制使用一个读取器等,则需要方法 4。方法 3 确实有点像 hack,因为它跳过了所有这个的。但是如果你不需要这些东西就更简单了。
字符设备的延迟肯定更高,因为每次读取设备时都需要内核转换。
DMA 方法的延迟完全取决于设备将时间写入内存的频率。 CPU 访问内存的延迟比 MMIO 低,但如果设备每毫秒只执行一次 DMA,那么这就是您的延迟。此外,该方法会产生大量无用的 DMA 流量,因为 CPU 读取值的频率远低于写入值。
【讨论】:
我没有解决问题 2 的第二部分。也许其他人可以提供帮助。 感谢您的回答。您的最后一句话:“此外,该方法会产生大量无用的 DMA 流量,因为 CPU 读取值的频率远低于写入值。”只是为了确保我理解正确:流量是由设备的写入引起的,其中大部分是无用的,因为 CPU 只读取这些写入的一部分。正确的?您是否有提示或示例如何实施方式 4?我没有找到任何可以帮助我理解的东西。 我将从您链接的同一本书开始;这是我过去使用的。【参考方案2】:添加到@prl 的答案...
方法 3 对我来说似乎完全合法。这就是它的用途。你可能想看看内核文档文件:https://www.kernel.org/doc/Documentation/filesystems/sysfs-pci.txt
您还可以使用/sys
文件系统来查找您的设备。首先,记下时钟卡的供应商 ID 和设备 ID(以及子系统供应商/设备,如有必要),然后您可以轻松遍历 /sys/devices
层次结构,寻找匹配的设备(使用 vendor
、device
、等特殊文件)。找到它后,您大概知道要从设备的数据表中打开哪个 resourceN
文件,然后在适当的偏移处打开 mmap
文件,您就完成了。
所有这些都假定您的设备已经配置并启用。通常,当系统启动时,PCI 设备无法执行任何操作。一些驱动程序需要声明设备,并初始化/配置它。完成此操作后,如果仅通过读取一两个寄存器即可访问时间,则可以使用方法 3。(我不确定:PCI 设备 可能自初始化,但我从未见过。我认为可能至少需要启用其内存空间。如果设置足够小/足够简单,可能可以从用户空间完成。)
与方法 4 的主要区别在于,控制设备的驱动程序将支持允许该区域被明确地mmap
'd。对于用户空间应用程序,除了使用的设备名称外,这两种方法几乎没有区别。对于方法 4,驱动程序可能会提供一个符号设备名称 /dev/clock0
或类似的名称供用户空间应用程序使用(并且可能应用程序不需要去查找设备,它只需 知道要打开的设备文件名)。
在用户空间中,您将以与任一方法大致相同的方式执行mmap
操作。在方法 4 中,驱动程序在内部提供要映射的物理地址——可能还有偏移量——而不是通用 PCI 子系统这样做,但无论哪种方式,它都只是 open
+ mmap
。
Linux 驱动程序编程并不是非常困难,但是如果你以前没有做过的话,那里的学习曲线很长,所以我绝对不会使用方法 4,除非真的需要这样做。
【讨论】:
以上是关于以低延迟访问 PCI 内存条 (Linux)的主要内容,如果未能解决你的问题,请参考以下文章