irqs跟踪器

本文介绍如何通过设置内核追踪参数来追踪中断延迟,并解析追踪结果,包括最大中断延迟、相关进程信息及具体函数调用等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        当中断被关闭(俗称关中断)了,CPU就不能响应其他事件,如果这时有一个鼠标中断,要在下一次开中断时才能响应这个鼠标中断,这段延迟称为中断延迟。向current_tracer文件中写入irqoff字符串即可打开offirq来跟中中断延迟。 

# cd /sys/kernel/debug/tracing/
# echo 0 > options/function-trace             //关闭function-trace 可以减少一些延迟
# echo irqoff > current_tracer
# echo 1 > tracing_on
[....] //停顿一小会
# echo 0 > tracing_on
# cat trace

    下面是irqoff跟踪的一个结果:

# tracer:irqoff
# irqoff latency trace v1.1.5 on 4.0.0
  --------------------------------------
# latency:259 us,#4/4,CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
  -----------------
# | task : ps-6143 (uid:0 nice:0 policy:0 rt_prio:0)
------------------------------------------------------
# =>start at: __lock_task_sighand
# => ended at : _raw_spin_unlock_irqrestore
#
#                _-------------=> CPU
#                /_------------=> irqs-off
#               |/_------------=> need-resched
#              ||/_------------=> hardirq/softirq
#             |||/_------------=> preempt-depth
#            ||||/_------------=> delay
#     
#    cmd pid            time         caller
      |   |              |             |
     ps-6143     2d...  0us!:       tarce_hardirqs_off <-__lock_task_sighand
     ps-6143     2d...1 259us+:     tarce_hardirqs_on  <- _raw_spin_unlock_irqrestore
     ps-6143     2d...1 263us+:     time_hardirqs_on   <- _raw_spin_unlock_irqrestore
     ps-6143     2d...1 360us:      <stack trace>

# => trace_hardirqs_on_caller
# => trace_hardirqs_on
# => _raw_spin_unlock_irqrestore
# => do_task_stat
# => proc_tgid_stat
# => proc_single_show
# => seq_read
# => vfs_read
# => sys_read
# => system_call_fastpatch

        文件的开头显示了当前跟踪器位irqoff并且显示当前跟踪器的版本号为v1.1.5 ,内核版本4.0。显示当前最大的中断延迟是259us,跟踪条目和总共跟踪条目为4条(#4/4),另外VP,KP,SP,HP值暂时没用到,#P:4表示系统当前可用的CPU个数。task:ps-6143表示当前发生中断的进程PID为6143的进程,命令名称是ps。

       started at 和ended at显示发生中断的开始函数和结束函数分别为:__lock_task_sighand和 _raw_spin_unlock_irqrestore。接下来ftrace信息表示的内容如下:

cmd:进程的名字为ps
pid:进程的pid号
CPU#:该进程运行在哪个CPU上
irqs-off :"d" 表示中断已关闭
need_resched: "N" 表示进程设置了TIF_NEED_RESCHED和PREEMPT_NEED_RESCHED标志位;
              "n" 表示进程仅设置了TIF_NEED_RESCHED标志位;
              "p" 表示进程仅设置了PREEMPT_NEED_RESCHED标志位;
hardirq/softirq: "H" 表示再一次软中断中发生了一个硬件中断;
                 "h" 表示硬件中断
                 "s" 表示软件中断
                 "." 表示没有发生中断
preempt_depth: 表示抢占中断嵌套等级
time:表示时间戳;如果打开latency-format选项,表示事件从开始跟踪算起,这时一个相对时间,方便开发者观察,否则使用系统绝对时间开始计算
delay: 用一些特殊符号来延迟的时间,方便开发者观察。 
       "$" : 表示大于1s
       "#" : 表示大于1000毫秒
       "!" : 表示大于100毫秒
       "+" : 表示大于10毫秒

最后说明的是,文件最开始显示的中断延迟是259us,但是在<stack trace>里显示的是306us,这时因为在记录最大延迟信息时需要花费一些时间。所以参考文件最开始的时间即可。

<think>我们正在讨论Linux内核中的中断控制相关概念,特别是irq_domain和irq_domain_ops结构体。用户之前询问了关于irq_domain_ops中的.alloc接口的使用和实现方法。根据引用[4],struct irq_domain中有一个成员ops,它指向irq_domain_ops结构体,该结构体包含一系列回调函数,其中.alloc就是其中之一。 引用[1]中提到了irq_domain_create_tree()函数,它创建了一个树形映射的irq domain,并传递了gic_irq_domain_ops作为参数。这个gic_irq_domain_ops应该是一个irq_domain_ops结构体实例,其中包含了.alloc等回调函数。 引用[2]提到irq_domain映射的类型有线性、树等,并且提到了Hierarchy IRQ domain(层次结构中断请求域)。不同的映射类型可能需要不同的回调函数实现。 现在,用户具体询问.alloc接口的使用方法和实现示例。 在Linux内核中,irq_domain_ops结构体中的.alloc函数用于分配中断描述符(irq_desc)并设置硬件中断号(hwirq)到Linux中断号(virq)的映射。这个函数通常在中断控制器驱动初始化irq domain时被注册,并在需要分配中断时由内核调用。 .alloc函数的原型定义(在include/linux/irqdomain.h中)大致如下: ```c int (*alloc)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg); ``` 参数说明: - d:指向irq_domain的指针。 - virq:分配的起始Linux虚拟中断号(virq)。 - nr_irqs:要分配的中断数量。 - arg:传递给分配函数的参数,通常包含硬件中断号等信息。 .alloc函数的主要任务是将硬件中断号(hwirq)与Linux中断号(virq)关联起来,并设置中断处理相关的信息(如设置irq_chip和中断处理函数等)。 下面是一个简化的示例,展示如何实现.alloc函数(以树形映射为例): ```c static int my_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct irq_fwspec *fwspec = arg; irq_hw_number_t hwirq; int i; // 从参数中获取硬件中断号 if (fwspec->param_count != 1) return -EINVAL; hwirq = fwspec->param[0]; // 遍历每一个中断 for (i = 0; i < nr_irqs; i++) { // 设置irq_desc的芯片数据(irq_chip)和中断处理函数 irq_domain_set_info(domain, virq + i, hwirq + i, &my_irq_chip, domain->host_data, handle_level_irq, NULL, NULL); } return 0; } ``` 在这个示例中,我们假设参数arg是一个irq_fwspec结构(设备树中断描述的一种通用表示),从中提取硬件中断号。然后,我们使用irq_domain_set_info()函数来设置每个中断号(从virq到virq+nr_irqs-1)对应的硬件中断号(从hwirq到hwirq+nr_irqs-1),并指定了irq_chip(my_irq_chip)和中断处理函数(handle_level_irq)。 注意:实际实现中,参数arg的类型可能因使用场景而异。例如,在设备树中,通常使用irq_fwspec;在ACPI中,可能使用其他结构。 使用.alloc函数时,通常是在创建irq domain之后,当需要为设备分配中断时,会调用irq_create_of_mapping()或类似函数,这些函数内部会调用irq_domain的.alloc函数。 例如,在设备树解析中断时,会调用irq_create_of_mapping(),该函数会找到设备对应的irq_domain,并调用其.alloc函数(如果映射尚未建立)。 在驱动中,我们通常不会直接调用.alloc函数,而是通过中断请求函数(如request_irq)来触发中断的分配和映射。但是,在初始化irq_domain时,我们需要提供.alloc函数,以便内核在需要时调用。 下面是一个irq_domain_ops结构体的实例,其中包含了.alloc函数: ```c static const struct irq_domain_ops my_domain_ops = { .alloc = my_irq_domain_alloc, .free = irq_domain_free_irqs_top, // 可能还有其他函数,如.translate等 }; ``` 总结: 1. .alloc函数用于建立硬件中断号到Linux中断号的映射,并初始化中断描述符。 2. 在实现.alloc函数时,通常使用irq_domain_set_info()来设置每个中断。 3. .alloc函数由内核在需要分配中断时调用,驱动中只需在irq_domain_ops中注册该函数。 相关问题: 1. irq_domain_ops中的.free函数有什么作用? 2. 在设备树中如何指定一个设备使用特定的irq_domain? 3. 如何实现一个树形映射的irq_domain?</think>### irq_domain_ops .alloc 接口详解 在 Linux 内核中断子系统中,`irq_domain_ops.alloc` 是用于**建立硬件中断号(hwirq)与 Linux 虚拟中断号(virq)映射关系的关键回调函数**。当需要为新的硬件中断分配虚拟中断号时,内核会调用此函数。 #### 函数原型 ```c int (*alloc)(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg); ``` 参数说明: - `domain`:指向所属的 `irq_domain` 结构 - `virq`:分配的起始 Linux 虚拟中断号 - `nr_irqs`:需要分配的中断数量 - `arg`:驱动私有数据(通常包含硬件中断号信息) --- ### 实现方法 #### 核心步骤 1. **解析硬件中断号** 从 `arg` 参数中提取硬件中断号(hwirq),通常使用 `struct irq_fwspec` 结构传递信息: ```c struct irq_fwspec *fwspec = arg; hwirq = fwspec->param[0]; // 获取硬件中断号 ``` 2. **建立映射关系** 调用 `irq_domain_set_info()` 设置映射: ```c irq_domain_set_info(domain, virq, hwirq, &my_irq_chip, domain->host_data, handle_level_irq, NULL, NULL); ``` - `my_irq_chip`:中断控制器操作集 - `handle_level_irq`:电平中断处理函数 3. **初始化中断描述符** 设置中断流控处理函数: ```c irq_set_handler(virq, handle_level_irq); ``` --- ### 实际驱动示例 以 ARM GICv3 中断控制器为例(源码位置:`drivers/irqchip/irq-gic-v3.c`): ```c static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct irq_fwspec *fwspec = arg; irq_hw_number_t hwirq; // 1. 解析硬件中断号 if (fwspec->param_count < 1) return -EINVAL; hwirq = fwspec->param[0]; // 2. 建立映射 for (i = 0; i < nr_irqs; i++) { irq_domain_set_info(domain, virq + i, hwirq + i, &gic_chip, domain->host_data, handle_fasteoi_irq, NULL, NULL); } return 0; } // 注册到 domain_ops static const struct irq_domain_ops gic_irq_domain_ops = { .alloc = gic_irq_domain_alloc, .free = irq_domain_free_irqs_top, ... }; ``` #### 关键操作说明: 1. **参数解析** 通过 `irq_fwspec` 获取设备树或 ACPI 传递的硬件中断信息。 2. **循环分配** 对 `nr_irqs` 个连续中断号批量处理,提高效率。 3. **设置处理函数** `handle_fasteoi_irq` 是 GIC 的快速结束中断处理函数。 4. **绑定中断控制器** `gic_chip` 包含 GIC 特定的 `.irq_mask`/`.irq_unmask` 等操作。 --- ### 使用场景 当以下事件发生时内核会调用 `.alloc`: 1. 设备树节点解析中断时(`of_irq_get()`) 2. ACPI 设备注册中断时 3. 驱动显式调用 `irq_create_mapping()` ```c // 驱动中显式创建映射的示例 int virq = irq_create_mapping(domain, hwirq); ``` --- ### 注意事项 1. **映射类型兼容性** 树形映射(`IRQ_DOMAIN_MAP_TREE`)需使用 `radix_tree` 存储映射关系[^4]。 2. **内存管理** 若在 `.alloc` 中分配资源,需在配套的 `.free` 回调中释放。 3. **层次化中断控制** 层次化 domain 需调用 `irq_domain_set_hwirq_and_chip()` 设置父级关系[^2]。 4. **线程安全** 操作需考虑并发保护(如使用 `domain->lock`)。 --- ### 调试技巧 1. 检查 `/proc/interrupts` 确认中断映射 2. 使用 `irq_domain_debug_show()` 输出 domain 映射表 3. 通过 `ftrace` 跟踪 `irq_domain_alloc_irqs` 调用路径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值