numabalance的本意是让进程和其使用的memory在同一个numa节点上,这样延迟最小。但是这需要
调动器来做大量的工作来迁移进程和memory到同一个node上,这样对某些场景性能会有比较大的损耗。
一般debug时候如果perf top中看到迁移进程的函数则建议观点numabalance试试
numabalance迁移的过程如下:
在每个时钟中断update_process_times->scheduler_tick
void scheduler_tick(void)
{
#这个函数会调用调度器的定义的hook函数,以fair 调度为例
curr->sched_class->task_tick(rq, curr, 0);
}
static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
{
struct cfs_rq *cfs_rq;
struct sched_entity *se = &curr->se;
#调度器选择下一个要执行的函数
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
entity_tick(cfs_rq, se, queued);
}
#只有开了numabalance这个if条件才会成立,可见只有开了numabalance才会迁移进程和memory到同一个node上
if (static_branch_unlikely(&sched_numa_balancing))
task_tick_numa(rq, curr);
}
void task_tick_numa(struct rq *rq, struct task_struct *curr)
{
if (now > curr->node_stamp + period) {
if (!curr->node_stamp)
curr->numa_scan_period = task_scan_start(curr);
curr->node_stamp += period;
#这里每个jiffies扫描一次,这里添加一个work,其回调函数是task_numa_work,这个函数最主要的工作就是调用change_prot_numa把
#所有映射到VMA的PTE页表项该为PAGE_NONE
if (!time_before(jiffies, curr->mm->numa_next_scan)) {
init_task_work(work, task_numa_work); /* TODO: move this into sched_fork() */
task_work_add(curr, work, true);
}
}
}
这样改的目的是当下次访问这个页时就会发生缺页中断,这样我们就可以在缺页中断中迁移进程和其使用的页
static int handle_pte_fault(struct vm_fault *vmf)
{
#由于我们在中断中我们把页的pte改成none了,一次下面这个if条件会成立
if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))
return do_numa_page(vmf);
}
static int do_numa_page(struct vm_fault *vmf)
{
last_cpupid = page_cpupid_last(page);
page_nid = page_to_nid(page);
#需要迁移目的node id target_nid。如果target_nid等于-1,则表示页就在自己的numa节点上不用迁移
target_nid = numa_migrate_prep(page, vma, vmf->address, page_nid,
&flags);
pte_unmap_unlock(vmf->pte, vmf->ptl);
if (target_nid == -1) {
put_page(page);
goto out;
}
/* Migrate to the requested node */
#通过下面函数将页迁移到自己分配的numa 节点上
migrated = migrate_misplaced_page(page, vma, target_nid);
if (migrated) {
page_nid = target_nid;
flags |= TNF_MIGRATED;
} else
flags |= TNF_MIGRATE_FAIL;
out:
#页面迁移完成后,再通过task_numa_fault 来迁移task
if (page_nid != -1)
task_numa_fault(last_cpupid, page_nid, 1, flags);
return 0;
}
从整个过程看numa balance 会做额外很大工作,因此某些场景下严重影响性能,需要关掉.