numa_balancing代码梳理_二 📅 2026/8/4 1:29:00 1. 内核配置2. 相关数据结构task_structmm_structnuma_group3. 观测工具1. 内核配置| | | | --- | --- | | 1 | CONFIG_ARCH_SUPPORTS_NUMA_BALANCINGy | | 2 | CONFIG_NUMA_BALANCINGy | | 3 | CONFIG_NUMA_BALANCING_DEFAULT_ENABLEDy |另外还可以通过内核启动参数的方式numa_balancingenable/disable或者sysctl接口kernel.numa_balancing来动态控制该功能工作。此外还提供了几个sysctl接口配置参数来控制它的扫描周期和力度| | | | --- | --- | | 1 | kernel.numa_balancing 1 //是否使能自动的numa balance | | 2 | kernel.numa_balancing_scan_delay_ms 1000 //任务启动N ms之后才开启第一次扫描这样可以避免对短生命周期的任务进行扫描 | | 3 | kernel.numa_balancing_scan_period_max_ms 6000 //扫描的最小间隔和最大间隔。 | | 4 | kernel.numa_balancing_scan_period_min_ms 1000 | | 5 | kernel.numa_balancing_scan_size_mb 256 //一次扫描的空间大小它会记录上次扫描的位置下次继续从此次位置扫描 |2. 相关数据结构相关的数据结构主要位于task_struct和mm_struct中先清除需要维护这些状态的用途之后在实现过程中分析他具体的使用。task_struct| | | | --- | --- | | 1 | struct task_struct { | | 2 | int numa_scan_seq; | | 3 | unsigned int numa_scan_period; | | 4 | unsigned int numa_scan_period_max; | | 5 | int numa_preferred_nid; | | 6 | unsigned long numa_migrate_retry; | | 7 | /* Migration stamp: */ | | 8 | u64 node_stamp; | | 9 | u64 last_task_numa_placement; | | 10 | u64 last_sum_exec_runtime; | | 11 | //多个task可能共享同一片内存具体可以是单个进程内多线程共享或者是多个进程间通过共享内存的方式 | | 12 | //将这些共享物理内存的task组织起来统计并为后面的页面迁移和task迁移提供历史依据 */ | | 13 | struct numa_group __rcu *numa_group; | | 14 | //N个节点的状态记录在每个节点上的缺页状态 | | 15 | //每个节点包含2组状态第一组代表当前扫描窗口的平均统计第二组是临时的buffer存储上一个窗口的统计 | | 16 | //每组4个状态:faults_memory, faults_cpu,faults_memory_buffer, faults_cpu_buffer | | 17 | //faults_memory: 记录缺页状态每一个周期结束时会根据当前周期的统计进行衰减类似于load的计算 | | 18 | //faults_cpus:发生缺页时cpu运行在哪个node上 | | 19 | //faults_memory_buffer, faults_cpu_buffer:记录当前窗口的缺页状态 | | 20 | unsigned long *numa_faults; | | 21 | //统计线程因为numa balance标记发生了多少次fault | | 22 | unsigned long total_numa_faults; | | 23 | //[0]: remote,缺页后迁移到其他node; [1]: local,缺页后仍然是本节点; [2]: migrate failed | | 24 | unsigned long numa_faults_locality[3]; | | 25 | //统计线程迁移了多少个页,仅做调试时展示使用 | | 26 | unsigned long numa_pages_migrated; | | 27 | } |mm_struct| | | | --- | --- | | 1 | struct mm_struct { | | 2 | //下一次允许扫描地址空间的时间 | | 3 | unsigned long numa_next_scan; | | 4 | //下一次扫描的起始位置整个扫描是顺序循环的 | | 5 | unsigned long numa_scan_offset; | | 6 | //用来防止同一个进程中多线程并发扫描地址空间 | | 7 | int numa_scan_seq; | | 8 | } |numa_group8c8a743c5087 引入了numa_group缺页异常中将cpu/pid的部分信息放到了page flags中将有共享页行为的线程放到一个group中。接下来如果是不同的PID访问这个page那么这两个任务共享这个页可以尝试将task迁移到这个group中。| | | | --- | --- | | 1 | struct numa_group { | | 2 | //引用计数内核常用方式当refcount为0时进行释放 | | 3 | atomic_t refcount; | | 4 | //保护并发读写操作 | | 5 | spinlock_t lock; /* nr_tasks, tasks */ | | 6 | //当前group中task数量 | | 7 | int nr_tasks; | | 8 | //创建时task的gid,在将多个task组织到一个group中时 | | 9 | pid_t gid; | | 10 | //当group中共享的内存分布在不同节点上时并不认为所有的node都是active的 | | 11 | //只有当前node 缺页访问数量超过max_faults_cpu 1/3时才会认为是active, | | 12 | //对于缺页访问较少的node应该将这些页积极的迁移到active node上达到页面汇聚的目的 | | 13 | int active_nodes; | | 14 | | | 15 | struct rcu_head rcu; | | 16 | //group中发生缺页的历史统计 | | 17 | unsigned long total_faults; | | 18 | //多个节点共享时发生缺页最多的node上的数量 | | 19 | unsigned long max_faults_cpu; | | 20 | //每个节点上有一组统计数据统计数据包括share/private的数量 | | 21 | unsigned long *faults_cpu; | | 22 | //group中所有task-numa_faults之和 | | 23 | unsigned long faults[0]; | | 24 | }; |在缺页统计时从两个角度出发task发生缺页时访问的是否是本节点分为local/remote一个窗口中统计缺页时页的节点和当前运行节点的关系保存在p-numa_faults_locality中。当local占比超过70%时适当延长当前的扫描时间。页面是否被共享分为share/private在page-flags中编码了部分的cpu和pid信息每次缺页时都会将本次的cpu/pid更新到page-flags中比较两次中的pid如果相同则是私有的如果不同则是shared。当私有占比70%时适当延长当前的扫描时间。cpu的share/private的意义一个场景是jvm中的垃圾回收线程它会访问大量的内存但是并不会实际使用它。所以在实际过程中会根据CPU运行时间进行加权运算。3. 观测工具需要打开CONFIG_SCHED_DEBUG宏之后内核才会提供接口应用可以通过proc接口来获取内核的统计数据/proc/vmstat接口# cat /proc/vmstat|grep numa numa_pte_updates 343288 //系统范围内总共被标记PAGE_NONE的页数量 numa_huge_pte_updates 119 //系统范围内总共被标记PAGE_NONE的大页数量加上numa_pte_updates就是全部被标记的页数量 numa_hint_faults 84534 //因为被标记PAGE_NONE而产生的page fault numa_hint_faults_local 78400 //page fault发生在本地的数量。numa_hint_faults_local/numa_hint_faults是有效迁移的比例 numa_pages_migrated 49394 //因为被标记PAGE_NONE而迁移页的数量线程的/proc/…/sched接口#cat /proc/9817/sched cat (9817, #threads: 1) ------------------------------------------------------------------- mm-numa_scan_seq : 0 numa_pages_migrated : 0 numa_preferred_nid : -1 total_numa_faults : 0 current_node0, numa_group_id0 numa_faults node0 task_private0 task_shared0 group_private0 group_shared0 numa_faults node1 task_private0 task_shared0 group_private0 group_shared0 numa_faults node2 task_private0 task_shared0 group_private0 group_shared0 numa_faults node3 task_private0 task_shared0 group_private0 group_shared0 numa_faults node4 task_private0 task_shared0 group_private0 group_shared0 numa_faults node5 task_private0 task_shared0 group_private0 group_shared0 numa_faults node6 task_private0 task_shared0 group_private0 group_shared0 numa_faults node7 task_private0 task_shared0 group_private0 group_shared0