// 周期调度器
// 调用路径:update_process_times->scheduler_tick
// 函数任务:
// 1.更新rq的clock
// 2.更新队列负载
// 3.通知调度器类更新进程运行时间
// 4.更新下一次load balance的时间戳
// 5.触发load balance
1.1 void scheduler_tick(void)
{
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
//当前运行的进程
struct task_struct *curr = rq->curr;
raw_spin_lock(&rq->lock);
//更新rq的clock
update_rq_clock(rq);
//更新队列负载
update_cpu_load_active(rq);
//更新进程的运行时间
curr->sched_class->task_tick(rq, curr, 0);
raw_spin_unlock(&rq->lock);
#ifdef CONFIG_SMP
//更新下一次load balance的时间戳
rq->idle_balance = idle_cpu(cpu);
//触发load balance软中断
trigger_load_balance(rq, cpu);
#endif
}
// 更新队列负载(rq->cpu_load[])
// 每scheduler tick(TICK_NSEC)被调用一次
// 函数任务:
// 1.更新rq负载
// 1.1 通过CPU_LOAD_IDX_MAX个项记录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
// 2.如果当前时间到达计算cpu负载的时间点
// 2.1 更新下一次计算cpu负载的时间点
// 2.2 计算cpu负载
// 调用路径:scheduler_tick->update_cpu_load
2.1 static void update_cpu_load(struct rq *this_rq)
{
//rq中所有se负载的总和
unsigned long this_load = this_rq->load.weight;
int i, scale;
this_rq->nr_load_updates++;
//通过CPU_LOAD_IDX_MAX个项记录rq的历史负载信息
for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
unsigned long old_load, new_load;
old_load = this_rq->cpu_load[i];
//rq中所有se的load.weight之和
new_load = this_load;
if (new_load > old_load)
new_load += scale-1;
//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
//....
this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
}
//到达计算cpu负载的时间点
if (time_after_eq(jiffies, this_rq->calc_load_update)) {
//更新下一次计算cpu负载的时间点
this_rq->calc_load_update += LOAD_FREQ;
//计算系统负载
calc_load_account_active(this_rq);
}
}
// 计算系统负载
// 系统负载考虑就绪状态进程和不可中断睡眠的进程(I/O)进程
// 调用路径:update_cpu_load->calc_load_account_active
2.2 static void calc_load_account_active(struct rq *this_rq)
{
long nr_active, delta;
nr_active = this_rq->nr_running; //就绪状态的进程
nr_active += (long) this_rq->nr_uninterruptible; //不可中断睡眠的进程
if (nr_active != this_rq->calc_load_active) {
delta = nr_active - this_rq->calc_load_active;
this_rq->calc_load_active = nr_active;
atomic_long_add(delta, &calc_load_tasks);
}
}