进程调度子系统(2)核心调度器

本文深入探讨Linux内核的进程调度子系统,重点关注周期调度器函数`scheduler_tick`,详细阐述了时钟中断处理流程,如何更新CFS运行队列。同时介绍了主调度器函数`schedule`,它在进程间切换时起关键作用,并解释了上下文切换的过程。
摘要由CSDN通过智能技术生成
调度器的实现基于两个函数:周期性调度器函数 和 主调度器函数

1.周期调度器函数(scheduler_tick)

内核按照频率(HZ)自动调用该函数

时钟中断在time_init_hook中初始化,中断函数为timer_interrupt
按照如下路径
   timer_interrupt
-->do_timer_interrupt_hook
-->这里有一个回调函数,调用的是tick_handle_oneshot_broadcast
-->从tick_handle_oneshot_broadcast
-->反正最后是到了tick_handle_periodic
-->tick_periodic
-->update_process_times
-->scheduler_tick 这里面跟CFS相关的主要就是更新了cfs_rq的时钟
-->通过回调函数调到task_tick_fair,没作什么事,直接进入了entity_tick

(1)管理整个系统和各个进程的调度相关的统计量

(2)激活负责当前进程的调度器类的调度方法
sched/core.c

//	周期调度器
//	调用路径:update_process_times->scheduler_tick
//	函数任务:
//		1.更新rq的clock
//		2.更新队列负载
//		3.通知调度器类更新进程运行时间
//		4.更新下一次load balance的时间戳
//		5.触发load balance
1.1 void scheduler_tick(void)
{

2156         int cpu = smp_processor_id();
2157         struct rq *rq = cpu_rq(cpu);
2158         struct task_struct *curr = rq->curr;
2159 
2160         sched_clock_tick();
2161 
2162         raw_spin_lock(&rq->lock);
2163         update_rq_clock(rq);//1.更新rq的clock
2164         curr->sched_class->task_tick(rq, curr, 0);//3.调用当前进程调度器类的调度方法,更新进程的运行时间
2165         update_cpu_load_active(rq);//2.更新队列负载
2166         raw_spin_unlock(&rq->lock);
2167 
2168         perf_event_task_tick();
2169 
2170 #ifdef CONFIG_SMP
2171         rq->idle_balance = idle_cpu(cpu);//4.更新下一次load balance的时间戳
2172         trigger_load_balance(rq, cpu);//5.触发load balance软中断
2173 #endif
2174         rq_last_tick_reset(rq);

}

//	更新队列负载(rq->cpu_load[])
//		每scheduler tick(TICK_NSEC)被调用一次
//	调用路径:scheduler_tick->update_cpu_load_active
2.1 void update_cpu_load_active(struct rq *this_rq)
582 {          

            //rq中所有se负载的总和

583         unsigned long load = this_rq->load.weight;
            //上次修改负载的时间戳
587         this_rq->last_load_update_tick = jiffies;
            //修改rq负载
588         __update_cpu_load(this_rq, load, 1);
589         //计算系统负载
590         calc_load_account_active(this_rq);
591 }
592 

//	更新队列负载(rq->cpu_load[])
//		每scheduler tick(TICK_NSEC)被调用一次
//	函数任务:
//		1.更新rq负载
//			1.1 通过CPU_LOAD_IDX_MAX = 5个项记录rq的历史负载信息
//			1.2 更新方法(本质上就是把上一个)
//				cpu_load[0] = load.weight
//				cpu_load[1] = (cpu_load[1]   + load.weight)/2
//				cpu_load[2] = (cpu_load[2]*3 + load.weight)/4
//				cpu_load[3] = (cpu_load[2]*7 + load.weight)/8

473 static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
474                               unsigned long pending_updates)
475 {
476         int i, scale;
477 
478         this_rq->nr_load_updates++;
479 
480         //通过CPU_LOAD_IDX_MAX个项记录rq的历史负载信息 */
481         this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
482         for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
483                 unsigned long old_load, new_load;
484 
485                 /* scale is effectively 1 << i now, and >> i divides by scale */
486 
487                 old_load = this_rq->cpu_load[i];
488                 old_load = decay_load_missed(old_load, pending_updates - 1, i);
489                 new_load = this_load;
490                 /*
491                  * Round up the averaging division if load is increasing. This
492                  * prevents us from getting stuck on 9 if the load 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值