我正在将一个设备驱动程序从QNX移植到Linux。 在QNX中,旧驱动程序使用带有无限循环的pthread来监视中断的发生,而不是注册真正的中断处理程序。 为了演示使用register_irq()而不是专用的轮询线程的功效,我在Linux中编写了两个驱动程序。 每个相关的代码如下所示,问题在底部。
IRQ
写处理程序
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);
问题
当我在示波器上放置两条迹线时,一条监测卡的数字input(这将触发中断),另一条监测卡的数字输出(这将对中断做出反应),我可以测量一个事件的反应时间。
注册IRQ的第一个“正确”方法大约需要80微秒。
第二种方法,运行一个无限的线程,大约需要15-30微秒。
是什么赋予了? 第一个好处是不会浪费太多的处理能力,但为什么响应时间会如此剧烈呢? 真的有这个轮询线程有多糟糕? 如何才能调查并最终certificate轮询线程对CPU的额外收费?
谢谢你的时间!
最好
斯科特
中断响应时间受到系统(不管是什么)发送中断所需的时间的影响,以及您的CPU(无论是什么)需要从某种省电休眠模式中唤醒的时间。
轮询线程同时消耗CPU时间和功耗。 要测量它们,请使用top
或powertop
类的东西,或直接在硬件上测量功耗。