中断亲和性使用cpumask_t来表示。
具体定义在/include/linux/cpumask.h:
/* Don't assign or return these: may not be this big! */
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
本质上就是一个long 类型的数组,数组多少和cpu数量相关。
//include/linux/types.h
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
打印可阅读的方式如下:比如在128核的cpu下面,有四个long类型,总共128
[root@greatdb-m 518]# cat /proc/irq/518/
affinity_hint effective_affinity_list nvme0q2/ smp_affinity_list
effective_affinity node smp_affinity spurious
[root@greatdb-m 518]# cat /proc/irq/518/smp_affinity
00000000,00000000,00000000,ffff0000
[root@greatdb-m 518]# cat /proc/irq/518/smp_affinity_list
16-31
[root@greatdb-m 518]#
demo:
[root@phytium mod]# cat test.c
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/sched/task.h>
#include <linux/arm-smccc.h>
#include <linux/cpumask.h>
static int __init test_init(void)
{
cpumask_t mask = {0};
printk("%*pbl\n", cpumask_pr_args(&mask));
printk("%*pb\n", cpumask_pr_args(&mask));
cpumask_set_cpu(16,&mask);
cpumask_set_cpu(127,&mask);
printk("%*pbl\n", cpumask_pr_args(&mask));
printk("%*pb\n", cpumask_pr_args(&mask));
return 0;
}
static void __exit test_exit(void)
{
printk(KERN_INFO "test_exit\n");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
内核printk打印格式Documentation/core-api/printk-formats.rst:
bitmap and its derivatives such as cpumask and nodemask
-------------------------------------------------------
::
%*pb 0779
%*pbl 0,3-6,8-10
通过16进制显示:
[1651531.706196] 00000000,00000000,00000000,00000000
[1651531.706202] 16,127
[1651531.706207] 80000000,00000000,00000000,00010000
bit位 从低位到高位来代表某个cpu。比如16号cpu。0x10000对应二进制00010000000000000000。
设置中断亲和内核kernel/irq/proc.c:irq_affinity_list_proc_write。可以用ftrace来跟踪一下:
设置irq亲和性,脚本步骤:
[root@localhost ~]# cat ftrace.sh
#!/bin/bash
debugfs=/sys/kernel/debug
echo nop > $debugfs/tracing/current_tracer
echo 0 > $debugfs/tracing/tracing_on
echo $$ > $debugfs/tracing/set_ftrace_pid
echo function_graph > $debugfs/tracing/current_tracer
#replace test_proc_show by your function name
echo irq_affinity_list_proc_write > $debugfs/tracing/set_graph_function
echo 1 > $debugfs/tracing/tracing_on
exec "$@"
[root@localhost ~]# ./ftrace.sh echo "1,3,6" > /proc/irq/57/smp_affinity_list
查看trace:
[root@localhost 57]# cat /sys/kernel/tracing/trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
0) | irq_affinity_list_proc_write() {
0) | write_irq_affinity.constprop.0.isra.0() {
0) 0.687 us | PDE_DATA();
0) | irq_can_set_affinity_usr() {
0) 0.771 us | irq_to_desc();
0) 2.146 us | }
0) | memdup_user_nul() {
0) | __kmalloc_track_caller() {
0) 0.646 us | kmalloc_slab();
0) 0.396 us | should_failslab();
0) 2.604 us | }
0) 3.479 us | }
0) 0.667 us | kfree();
0) | __irq_set_affinity() {
0) 0.438 us | irq_to_desc();
0) 0.667 us | _raw_spin_lock_irqsave();
0) | irq_set_affinity_locked() {
0) | irq_do_set_affinity() {
0) | msi_domain_set_affinity() {
0) | its_set_affinity() {
0) 0.625 us | its_dec_lpi_count.isra.0();
0) | its_select_cpu() {
0) 0.812 us | cpumask_pick_least_loaded();
0) 1.875 us | }
0) 0.375 us | its_inc_lpi_count.isra.0();
0) 4.750 us | }
0) 5.938 us | }
0) 0.521 us | irq_set_thread_affinity();
0) 7.687 us | }
0) 8.541 us | }
0) 0.375 us | _raw_spin_unlock_irqrestore();
0) + 11.855 us | }
0) + 22.895 us | }
0) + 26.584 us | }
its_set_affinity函数在irq-gic-v3-its.c:还会调用irq_data_update_effective_affinity设置活动affinity。代表当前是那个核来接受中断。
[root@localhost ~]# cat /proc/irq/57/smp_affinity_list
1,3,6
[root@localhost ~]# cat /proc/irq/57/effective_affinity_list
3