调度器的实现基于两个函数:周期性调度器函数 和 主调度器函数
(2)激活负责当前进程的调度器类的调度方法
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
(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