我正在将设备驱动程序从 QNX 移植到 Linux。在 QNX 中,旧驱动程序使用带有无限循环的 pthread 来监视中断的发生,而不是注册真正的中断处理程序。为了尝试证明使用 register_irq() 而不是专用轮询线程的功效,我在 Linux 中编写了两个驱动程序。每个的相关代码如下所示,问题在底部。
中断请求
编写处理程序
irqreturn_t timing_interrupt_handler(int irq, void *dev_id) {
u32 test;
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if ( test & (1 << 2) ) {
/* clear interrupt status */
iowrite32( 0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if ( test & 0x01 )
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
return IRQ_HANDLED;
}
注册处理程序
rc = request_irq(irq_line, timing_interrupt_handler,
IRQF_SHARED, "timing", timing_card);
if ( rc ) {
printk(KERN_ALERT "Failed to register irq %d\n", irq_line);
return rc;
}
轮询线程
编写线程函数
int poll_irq(void *data) {
u32 test;
/* until module unload */
while ( !kthread_should_stop() ) {
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if ( test & (1 << 2) ) {
/* clear interrupt status */
iowrite32( 0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if ( test & 0x01 )
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
else
usleep_range(9, 11);
}
return 0;
}
开始讨论
kthread = kthread_create(poll_irq, 0x0, "poll_IRQ_test");
wake_up_process(kthread);
问题
当我在示波器上放置两条轨迹时——一条监测卡的数字输入(这会触发中断),另一条监测卡的数字输出(这会对中断使用react),我可以测量对事件的 react 时间。
第一个“正确”的方法是注册一个 IRQ,大约需要 80 微秒。
第二种方法是运行无限线程,大约需要 15-30 微秒。
什么给了?第一个的好处是它不会浪费那么多的处理能力,但为什么响应时间会受到如此大的影响呢?拥有这个投票线程真的有多糟糕?如何着手调查并最终证明轮询线程对 CPU 造成的额外影响?
感谢您的宝贵时间!
最佳
斯科特
最佳答案
中断响应时间受您的系统(无论是什么)需要传递中断的时间以及您的 CPU(无论是什么)需要从某种节能 sleep 模式唤醒的时间的影响。
轮询线程消耗 CPU 时间和功率。
要测量它们,请使用 top
或 powertop
之类的东西,或者直接在硬件上测量功耗。
关于Linux 外部事件处理 - IRQ 与轮询 kthread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17373284/