A
多核 ARM64 板上,中断没有落到你指定的那颗核,是挺常见的一类“看起来像随机延迟”的问题。网卡、PCIe 外设、甚至核间 IPI,都可能出现:你在 /proc/irq/N/smp_affinity 里写了掩码,实际处理函数却在另一颗核上跑;或者绑到大核想降低尾延迟,结果小核还在进中断。GICv3 把中断分成好几种:PPI/SGI 跟核绑定,SPI 可以路由到某一组核,LPI 则走 ITS(Interrupt Translation Service),靠设备 ID 和事件号翻译成中断号。亲和性设在哪一层,决定了你改的那份掩码到底管不管用。
先确认中断类型。cat /proc/interrupts 看该中号在各列的计数;如果计数只在某个 CPU 上涨,说明硬件或软件已经把它钉死了。SPI 一般可以直接改 smp_affinity 或 smp_affinity_list。LPI 要看 ITS 和设备的 DeviceID 是否配进了 ITS 表,以及内核是否用了 irqbalance 或驱动自己的 set_affinity。驱动如果在请求中断时设了 IRQF_NO_BALANCING,用户态再改亲和性会被悄悄忽略。隔离核(isolcpus、nohz_full)也常让人误会:核被隔离出调度器,不等于自动不再收中断,必须再把相应 IRQ 从这些核上挪走。
GICv3 的中断路由还受 GICD/GICR 和 redistributor 的影响。核休眠、热插拔或 cpuidle 进得太深时,redistributor 没唤醒,新中断可能被改投到仍醒着的核上,看起来像亲和性“自己变了”。开机早期,ITS 表还没建完,PCIe 设备的 MSI-X 可能先落到默认 CPU0,等驱动后期再迁走;如果你在探测阶段就算延迟,会得到偏高的数字。调试时同时看 /proc/irq/N/effective_affinity 和实际 ISR 里的 smp_processor_id(),两者不一致就去查是不是有 irqbalancer、驱动回调或 GIC 驱动把亲和性改回去了。
工程上我习惯按外设类型分策略:硬盘和网卡的收包中断跟处理线程放同一组核,避免跨核打缓存;控制面和实时任务占用的核尽量清空 IRQ;不要把所有 MSI-X 向量都挤到 CPU0。改完用一次大流量或一次 PCIe 压力,再对一下 /proc/interrupts 的增量,比只看配置文件靠谱。GICv3 的手册很长,但现场问题多半就是:改错了层、驱动锁死了亲和性,或者隔离核只隔了进程没隔中断。
先确认中断类型。cat /proc/interrupts 看该中号在各列的计数;如果计数只在某个 CPU 上涨,说明硬件或软件已经把它钉死了。SPI 一般可以直接改 smp_affinity 或 smp_affinity_list。LPI 要看 ITS 和设备的 DeviceID 是否配进了 ITS 表,以及内核是否用了 irqbalance 或驱动自己的 set_affinity。驱动如果在请求中断时设了 IRQF_NO_BALANCING,用户态再改亲和性会被悄悄忽略。隔离核(isolcpus、nohz_full)也常让人误会:核被隔离出调度器,不等于自动不再收中断,必须再把相应 IRQ 从这些核上挪走。
GICv3 的中断路由还受 GICD/GICR 和 redistributor 的影响。核休眠、热插拔或 cpuidle 进得太深时,redistributor 没唤醒,新中断可能被改投到仍醒着的核上,看起来像亲和性“自己变了”。开机早期,ITS 表还没建完,PCIe 设备的 MSI-X 可能先落到默认 CPU0,等驱动后期再迁走;如果你在探测阶段就算延迟,会得到偏高的数字。调试时同时看 /proc/irq/N/effective_affinity 和实际 ISR 里的 smp_processor_id(),两者不一致就去查是不是有 irqbalancer、驱动回调或 GIC 驱动把亲和性改回去了。
工程上我习惯按外设类型分策略:硬盘和网卡的收包中断跟处理线程放同一组核,避免跨核打缓存;控制面和实时任务占用的核尽量清空 IRQ;不要把所有 MSI-X 向量都挤到 CPU0。改完用一次大流量或一次 PCIe 压力,再对一下 /proc/interrupts 的增量,比只看配置文件靠谱。GICv3 的手册很长,但现场问题多半就是:改错了层、驱动锁死了亲和性,或者隔离核只隔了进程没隔中断。

