Bootstrap

numabalance

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 会做额外很大工作,因此某些场景下严重影响性能,需要关掉.

;