【内核调度、负载均衡】【entity_tick】

本文详细剖析了CFS调度器中的关键函数task_tick_fair和entity_tick的工作原理,包括如何进行周期性调度、更新运行时间和负载平均值,以及如何在适当时候进行进程抢占决策。

在scheduler_tick函数中会调用task_tick函数,具体到fair class,他的入口函数为

task_tick_fair

/*
 * scheduler tick hitting a task of our scheduling class:
 */
 /*  获取到当前进程curr所在的调度实体  */
static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
{
	struct cfs_rq *cfs_rq;
	/*  获取到当前进程curr所在的调度实体  */
	struct sched_entity *se = &curr->se;
	/* for_each_sched_entity
     * 在不支持组调度条件下, 只循环一次
     * 在组调度的条件下, 调度实体存在层次关系,
     * 更新子调度实体的同时必须更新父调度实体  */
	for_each_sched_entity(se) {
		/*  获取当当前运行的进程所在的CFS就绪队列  */
		cfs_rq = cfs_rq_of(se);
		/*  完成周期性调度  */
		entity_tick(cfs_rq, se, queued);
	}

	if (static_branch_unlikely(&sched_numa_balancing))
		task_tick_numa(rq, curr);

	update_misfit_status(curr, rq);

	update_overutilized_status(rq);
}

我们可以看到, CFS周期性调度的功能实际上是委托给entity_tick函数来完成的

entity_tick

static void
entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
{
	/*
	 * Update run-time statistics of the 'current'.
	 */
	update_curr(cfs_rq);

	/*
	 * Ensure that runnable average is periodically updated.
	 */
	update_load_avg(curr, UPDATE_TG);
	update_cfs_shares(curr);

	//接下来是hrtimer的更新, 这些由内核通过参数CONFIG_SCHED_HRTICK开启
#ifdef CONFIG_SCHED_HRTICK
	/*
	 * queued ticks are scheduled to match the slice, so don't bother
	 * validating it and just reschedule.
	 */
	if (queued) {
		resched_curr(rq_of(cfs_rq));
		return;
	}
	/*
	 * don't let the period tick interfere with the hrtick preemption
	 */
	if (!sched_feat(DOUBLE_TICK) &&
			hrtimer_active(&rq_of(cfs_rq)->hrtick_timer))
		return;
#endif
	//如果进程的数目不少于两个, 则由check_preempt_tick作出决策
	if (cfs_rq->nr_running > 1)
		check_preempt_tick(cfs_rq, curr);
}

update_curr主要是更新vruntime和min_vruntime

https://blog.youkuaiyun.com/feifei_csdn/article/details/107200966

update_load_avg主要是更新entity和cpu的负载

https://blog.youkuaiyun.com/feifei_csdn/article/details/107381373

check_preempt_tick

/*
 * Preempt the current task with a newly woken task if needed:
 */
static void
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
	unsigned long ideal_runtime, delta_exec;
	struct sched_entity *se;
	s64 delta;
	/*  计算curr的理论上应该运行的时间  */
	ideal_runtime = sched_slice(cfs_rq, curr);
	 /*  计算curr的实际运行时间
     *  sum_exec_runtime: 进程执行的总时间
     *  prev_sum_exec_runtime:进程在切换进CPU时的sum_exec_runtime值  */
	delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
	 /*  如果实际运行时间比理论上应该运行的时间长
     *  说明curr进程已经运行了足够长的时间
     *  应该调度新的进程抢占CPU了  */
	if (delta_exec > ideal_runtime) {
		//resched_curr(rq_of(cfs_rq))设置重调度标识, 从而触发延迟调度
		resched_curr(rq_of(cfs_rq));
		/*
		 * The current task ran long enough, ensure it doesn't get
		 * re-elected due to buddy favours.
		 */
		clear_buddies(cfs_rq, curr);
		return;
	}

	/*
	 * Ensure that a task that missed wakeup preemption by a
	 * narrow margin doesn't have to wait for a full slice.
	 * This also mitigates buddy induced latencies under load.
	 */
	if (delta_exec < sysctl_sched_min_granularity)
		return;

	se = __pick_first_entity(cfs_rq);
	delta = curr->vruntime - se->vruntime;

	if (delta < 0)
		return;
//curr进程与红黑树中最左进程left虚拟运行时间的差值大于curr的期望运行时间ideal_runtime
	if (delta > ideal_runtime)
		resched_curr(rq_of(cfs_rq));
}
// 选择最左边的entity
struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
{
	struct rb_node *left = rb_first_cached(&cfs_rq->tasks_timeline);

	if (!left)
		return NULL;

	return rb_entry(left, struct sched_entity, run_node);
}

 

-exception_panic_reason:Oops - Undefined instruction: Fatal exception -exception_file_infoi:not-bugon -exception_task_id:18051 -exception_task_family:[ptz-bgd-1-IMAGE, 18051][main, 585] -exception_pc_symbol:[<ffffffc0082310f4>] propagate_entity_load_avg+0xf8/0x35c -exception_stack_info:[<ffffffc001806994>] get_exception_stack_info+0x150/0x2d8 [sysdump] [<ffffffc0018067ec>] prepare_exception_info+0x16c/0x1c4 [sysdump] [<ffffffc0018099c4>] sysdump_panic_event+0x76c/0x8ec [sysdump] [<ffffffc0082044fc>] atomic_notifier_call_chain+0x8c/0x138 [<ffffffc0081b4d64>] panic+0x1b8/0x44c [<ffffffc0081137bc>] die+0x5a0/0x67c [<ffffffc008114748>] do_el1_undef+0x68/0x98 [<ffffffc00977cd60>] el1_undef+0x34/0x54 [<ffffffc00977cc04>] el1h_64_sync_handler+0x54/0xb4 [<ffffffc008091310>] el1h_64_sync+0x7c/0x80 [<ffffffc0082310f4>] propagate_entity_load_avg+0xf8/0x35c [<ffffffc008230da4>] update_load_avg+0x1b4/0x40c [<ffffffc008231b74>] propagate_entity_cfs_rq+0x88/0x1f4 [<ffffffc0082341f8>] detach_entity_cfs_rq+0x84/0xb4 [<ffffffc0082331d4>] migrate_task_rq_fair+0x64/0x1c0 [<ffffffc0082182d8>] set_task_cpu+0xd8/0x2ac [<ffffffc0018d6c20>] lb_pull_tasks+0x1b8/0x278 [unisoc_sched] [<ffffffc0018d3028>] android_rvh_sched_newidle_balance+0x298/0x344 [unisoc_sched] [<ffffffc008238b48>] newidle_balance+0x88/0x79c [<ffffffc00823d21c>] pick_next_task_fair+0x5c/0x3dc [<ffffffc0091ef33c>] binder_wait_for_work+0x178/0x48c [<ffffffc0091ec080>] binder_thread_read+0x270/0x2bc4 [<ffffffc0091e7e98>] binder_ioctl_write_read+0x120/0x588 [<ffffffc0091e2bbc>] binder_ioctl+0x1c4/0xfd8 [<ffffffc0085eff20>] __arm64_sys_ioctl+0x184/0x20c [<ffffffc00811fb68>] invoke_syscall+0x60/0x150 [<ffffffc00811fa9c>] el0_svc_common+0x8c/0xf8 [<ffffffc00811f9a0>] do_el0_svc+0x28/0x98 [<ffffffc00977d248>] el0_svc+0x24/0x84 [<ffffffc00977d1c0>] el0t_64_sync_handler+0x88/0xec [<ffffffc00809164c>] el0t_64_sync+0x1b8/0x1bc
06-20
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值