IRQ(中断请求)是一种在计算机硬件和软件之间进行通信的机制。在Linux操作系统中,IRQ由硬件设备(如网卡、声卡等)发送给CPU,
用于表示该设备需要CPU的处理。IRQ的分配和控制是操作系统的一个重要任务,以保证硬件设备能够正常工作,并且不会造成CPU资源的浪费。
一、 中断的 CPU 亲和性是指接收处理某个中断信号的 CPU 集合。
Linux 下的 IRQ 中断,有一个默认的亲和性设置:
start_kernel()
early_irq_init()
init_irq_default_affinity()
static void __init init_irq_default_affinity(void)
{
if (!cpumask_available(irq_default_affinity))
zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
if (cpumask_empty(irq_default_affinity))
cpumask_setall(irq_default_affinity); /* IRQ 中断 的 CPU 亲和性默认值 为 【系统中所有 CPU】 */
}
#ifdef CONFIG_CPUMASK_OFFSTACK
/* Assuming NR_CPUS is huge, a runtime limit is more efficient. Also,
* not all bits may be allocated. */
#define nr_cpumask_bits nr_cpu_ids
#else
#define nr_cpumask_bits ((unsigned int)NR_CPUS)
#endif
static inline void cpumask_setall(struct cpumask *dstp)
{
bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
}
二、 系统运行过程中,在中断 CPU 亲和性初始化后,也可以通过系统提供的接口对中断 CPU 亲和性进行修改。
修改单个 IRQ 中断的 CPU 亲和性:
Linux 内核提供下面两个文件节点,允许用户空间修改某个 IRQ 中断的 CPU 亲和性:
/proc/irq/<N>/smp_affinity # IRQ N 的 CPU 亲和性,以十六进制掩码形式配置接口,如 f
/proc/irq/<N>/smp_affinity_list # smp_affinity 列表形式配置接口,如 0-3
其中 <N> 为 Linux 中断号(非硬件中断号),通过对 smp_affinity 的写入来修改中断的 CPU 亲和性。如:
# echo 3 > /proc/irq/<N>/smp_affinity ## 将中断 N 的亲和性设置为 CPU 0,1
三、 中断线程化
中断处理通常分为上半部和下半部。上半部负责快速处理硬件相关的紧急事务,如读取硬件寄存器状态、确认中断源等,以尽快释放中断线,让其他中断能够及时得到响应。下半部则负责处理相对耗时的任务,如数据处理、设备状态更新等。
中断线程化就是将下半部的处理工作放到内核线程中执行。这样,在处理中断时,上半部可以快速完成关键操作后返回,将耗时的任务交给内核线程异步处理,avoid因下半部处理时间过长而阻塞其他中断,提高系统的整体响应能力。
中断 CPU 亲和性的设置,其实也分软件和硬件两个层次。软件上,更新了中断的两个掩码 desc->irq_common_data.affinity 和 desc->irq_common_data.effective_affinity,
同时如果中断线程化的话,还会设置中断的 IRQTF_AFFINITY 标志位,以指示中断线程自身设置其 CPU 亲和性;而硬件层次是设置中断在中断芯片(GIC v2)上的 CPU 亲和性。
对于中断的 CPU 亲和性设置,还剩下最后一个片段,那就是在中断线程化场景,将中断的 CPU 亲和性设置为中断线程的 CPU 亲和性:
中断线程化场景,响应中断的 CPU 和 调度中断线程的 CPU 可能不是同一个。/proc/interrupts 文件中,统计的是 CPU 响应中断的计数,中断线程化场景下,调度中断线程的 CPU 可能是另一个。
让我们看看这个接口:
int request_threaded_irq(
unsigned int irq,
irq_handler_t handler,
irq_handler_t thread_fn,
unsigned long irqflags,
const char *devname,
void *dev_id)
其中,irq 是中断号,handler 是在发生中断时首先要执行的处理程序,非常类似于顶半部,该函数最后会返回 IRQ_WAKE_THREAD 来唤醒中断线程。handler 一般设为NULL,用系统提供的默认处理。
thread_fn 是要在线程里执行的处理程序,非常类似于底半部。后三个参数基本和request_irq相同。
四、 IRQbalance是一个在Linux系统上用于分配和管理IRQ的工具,它可以帮助优化系统的性能,减少CPUload。它可以自动检测系统中的硬件设备及其中断请求,
并通过重新分配IRQ,来平衡系统中各个设备的load。以下是IRQbalance命令的详细说明:
1. 安装IRQbalance:在大多数Linux发行版中,IRQbalance已经预装了,可以通过命令“sudo apt-get install irqbalance”进行安装。
2. 启动IRQbalance:安装完成后,可以使用命令“sudo systemctl start irqbalance”来启动IRQbalance服务。可以使用“sudo systemctl enable irqbalance”命令来设置IRQbalance服务开机启动。
3. 检查IRQbalance状态:使用命令“sudo systemctl status irqbalance”可以查看IRQbalance的运行状态,确认是否正常启动。
4. 修改IRQbalance配置文件:默认情况下,IRQbalance的配置文件位于“/etc/default/irqbalance”。可以使用文本编辑器打开该文件,对IRQbalance的一些配置进行修改。例如,可以通过修改“IRQBALANCE_ONESHOT”参数的值,来设置IRQbalance是否仅执行一次IRQ分配。
5. 手动重新分配IRQ:可以使用命令“sudo irqbalance -d”来手动执行IRQ的重新分配。使用该命令时,系统会检测当前的IRQ分配情况,并进行优化分配。通过添加“-d”参数,可以打开调试模式,显示详细的IRQ分配信息。
总结:IRQbalance是一个用于优化Linux系统性能的工具,通过自动分配和管理IRQ,可以减少CPU load,提高系统的响应速度。安装、启动、配置和手动执行IRQ分配都可以通过简单的命令完成。以上是对IRQbalance命令的详细解释。