我尝试找出 Linux 中中断抖动的值,尤其是在最坏的情况下。考虑了两个测试平台,一个是 Raspberry Pi 4B,另一个是配备 intel i9 CPU 和 ASUS 主板的高端 PC。
+-+ +-+ +-+ Raspberry Pi 4B
| | | | | | -------------+
--+ +-+ +-+ +- 1. GPIO | +--------------+
Signal Generator | | |
+----> +-----+ | Linux |
| CPU | | ------------ |
+----> +-----+ | Kernel |
| | | | |
+-+--+-+ 2. PCIe MSI | +--------------+
--+ FPGA +-- ------------+
+-+--+-+ high-end PC (i9-9900K)
| |
对于Raspberry Pi,使用输出固定频率方波的信号发生器作为中断源。对于高端PC,采用带有PCIe的Xilinx FPGA板作为中断源,中断类型为MSI。信号发生器和 Xilinx FPGA 板都可以生成时间抖动很小(<1us)的中断。
以下是irq_handler
树莓派4B中驱动代码的功能
static irqreturn_t gpio_ts_handler(int irq, void *arg) {
struct timespec64 timestamp;
struct gpio_ts_devinfo *devinfo;
int nwritten;
ktime_get_real_ts64(×tamp); // get the time
// lock the data fifo and insert the timestamp
spin_lock(&devinfo->spinlock);
nwritten = gpio_fifo_write(devinfo->fifo, ×tamp, 1);
spin_unlock(&devinfo->spinlock);
if (nwritten != 1) {
printk(KERN_ERR "GPIOTS: ISR fifo overflow\n");
}
// wake up the waiting thread which then read timestamp from the fifo
wake_up(&devinfo->waitqueue);
return IRQ_HANDLED;
}
以下是irq_handler
高端PC中驱动代码的功能
// IRQ handler
static irqreturn_t fPCI_event_isr (int irq, void *cookie)
{
struct timespec64 tsc_now = {.tsc_high = 0; .tsc_low = 0};
struct fPCI_dev *drv_data = (struct fPCI_dev *) cookie;
int nwritten;
int fifo_size;
// get TSC timestamp
get_tsc_cpuid((tsc_now.tsc_high), (tsc_now.tsc_low));
spin_lock(&(drv_data->spin_lock));
nwritten = fpci_fifo_write(drv_data->fifo, &tsc_now, 1);
spin_unlock(&(drv_data->spin_lock));
if (nwritten != 1)
printk(KERN_INFO, "fPCI_event_isr: fifo overflow!\n");
fifo_size = fpci_fifo_size(drv_data->fifo);
if (fifo_size > FIFO_SIZE/2)
wake_up(&(drv_data->waitqueue));
return IRQ_HANDLED;
}
在IRQ处理程序的代码中,首先将当前时间存储在FIFO中。然后,用户空间线程从 FIFO 读取时间数据,并对中断的抖动进行计数。结果如下两张图所示。
我的问题是:
1 为什么 PCIe MSI 中断比 GPIO 中断具有更大的延迟抖动?
2 现代 PCIe MSI 中断在最坏的情况下有大约 100us 的延迟变化是否正常(有什么我错过的吗)?如何最大限度地减少延迟(抖动)的这种变化。