C 在Linux中跟踪硬IRQ

C 在Linux中跟踪硬IRQ,c,linux-kernel,perf,kprobe,jprobe,C,Linux Kernel,Perf,Kprobe,Jprobe,我对Linux内核的经验非常少。我最近才开始玩弄它 为了我的研究目的,我一直在努力追踪包裹到达的最早时间。我可以通过修改设备驱动程序并在设备驱动程序的中断处理程序函数中记录时间戳,在设备驱动程序级别实现这一点。很抱歉,这篇文章可能会长一点 例如,我修改了这个函数()来跟踪调用这个函数的时间戳 进一步深入并遵循此调用的堆栈跟踪,我们将发现一个堆栈跟踪,如下所示: i40e_msix_clean_rings()-i40e驱动程序的i40e_main.c位于上面提供的链接中 __handle\u i

我对Linux内核的经验非常少。我最近才开始玩弄它

为了我的研究目的,我一直在努力追踪包裹到达的最早时间。我可以通过修改设备驱动程序并在设备驱动程序的中断处理程序函数中记录时间戳,在设备驱动程序级别实现这一点。很抱歉,这篇文章可能会长一点

例如,我修改了这个函数()来跟踪调用这个函数的时间戳

进一步深入并遵循此调用的堆栈跟踪,我们将发现一个堆栈跟踪,如下所示:

  • i40e_msix_clean_rings()-i40e驱动程序的i40e_main.c位于上面提供的链接中
  • __handle\u irq\u event\u perpu()-kernel/irq/handle.c
  • handle\u irq\u event\u perpu()-kernel/irq/handle.c
  • handle\u irq\u event()-kernel/irq/handle.c
  • handle\u edge\u irq()-kernel/irq/chip.c
  • handle_irq()-arch/x86/kernel/irq_64.c
  • do_IRQ()-arch/x86/kernel/IRQ.c
  • common_interrupt()-不太确定,但实现应该类似于arch/x86/kernel/head_32.s中早期的_idt_handler_common()
我试图在函数do_IRQ()中跟踪数据包到达的时间戳(上面堆栈跟踪中的黑体)。作为参考,do_IRQ函数如下所示:

__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);
    struct irq_desc * desc;
    /* high bit used in ret_from_ code  */
    unsigned vector = ~regs->orig_ax;
    **int int_number;**

    entering_irq();

    /* entering_irq() tells RCU that we're not quiescent.  Check it. */
    RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU");

    desc = __this_cpu_read(vector_irq[vector]);
    **int_number = desc->irq_data.irq;**

    **printk(KERN_INFO "IRQ Number=%d; Vector=%d \n", int_number, vector);**

    if (!handle_irq(desc, regs)) {
        ack_APIC_irq();

        if (desc != VECTOR_RETRIGGERED) {
            pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n",
                         __func__, smp_processor_id(),
                         vector);
        } else {
            __this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
        }
    }

    exiting_irq();

    set_irq_regs(old_regs);
    return 1;
}
为了让我的意图更清楚一点,我已经用“**”表示了我在这个函数中所做的更改

例如,在我的测试机器上,我的NIC绑定到IRQ编号19。int\u number变量表示该数字。因此,这使我能够跟踪特定IRQ编号的IRQ

这听起来可能与单个队列NIC适配器无关,但它将适用于多队列适配器,因为我可以使用flow director将数据包定向到固定队列,并且每个队列都绑定到特定的IRQ号。因此,这将帮助我轻松地跟踪数据包

我的做法:

  • 在该函数中添加手动实现;我认为这不是正确的方法
  • 使用kprobe。但它是否允许我根据变量或参数内部的内容过滤跟踪
  • 使用jprobe。我想,通过这种方法,我们将能够处理这些论点。不过我还是能处理好这件事。我只是简单地遵循了jprobe的例子。()还有几个
  • 在使用上述方法的过程中,我还遇到了其他工具。像perf、perf工具、eBPF。但是,我不确定哪种方法对我来说是最好的
  • 为了澄清我的最后一项任务:我正在尝试捕获我的数据包最早到达的时间戳,如:

    t1
    t2
    t3
    t4 
    
    如果您能就此提供任何意见,我将不胜感激


    谢谢大家!

    首先,您是否确保您的硬件NIC不支持时间戳?硬件时间戳可能比任何软件时间戳都要精确得多。其次,您是只想要新数据包的到达时间(如您文章末尾的示例列表所示),还是想要相应数据包的到达时间?如果是第二种情况,该如何识别数据包?谢谢您的回复。是的,这将是一个棘手的部分。否则,我就可以使用perf或类似的东西来跟踪irq事件。如果没有内核补丁,我目前在设备驱动程序中的做法是:1。在irq处理程序函数(i40e_msix_clean_rings)2记录时间t1。获取此数据包时(在i40e_poll函数内),如果是UDP端口XX,则确认t1为数据包的到达时间;否则就忽略它。我不确定,如何跟踪IRQ事件并确认IRQ事件确实是我想要的数据包。我在跟踪时发现了:ethtool-T off(HWTSTAMP_TX_off)on(HWTSTAMP_TX_on)您是说您当前仅基于UDP端口识别数据包吗?老实说,我不知道如何解释
    ethtool-T
    的输出。嗨!刚刚通过英特尔的论坛和文档进行了检查。我的NIC不支持硬件时间戳。回到关于识别数据包类型的第一个问题。对我正在从主机A向B发送端口XX上的这些特定UDP数据包。这只是分析同步数据包到达时间抖动的概念证明。我在这里依赖一种乐观的方法(这个特定端口上的所有Rx数据包都是我想要的数据包)。稍后,我可以通过一些额外的验证(如内容、标题等)来遵循这一点