Linux中的调度参数之公平调度中的轮转周期与时间片

基于Linux-5.4

当前的Linux中有公平调度、实时(rt)调度、deadline调度等等调度算法;其中公平调度是目前最主要的调度算法之一。

公平调度,顾名思义就是要保证公平性,要照顾到所有任务都能够有机会得到CPU调度资源。Linux中有几个参数和"公平性"息息相关。

 

sysctl_sched_min_granularity:公平调度中一个轮转周期内每个任务可运行的最小时间粒度(最小时间片),这样可避免任务运行时间太短导致优先级低的任务受到不公平待遇以及避免任务切换太过频繁的情况。 期默认值为750000ULL,单位nanoseconds;
sysctl_sched_latency:默认的轮转周期。公平调度中处于就绪状态的所有任务运行一轮所需要的时间称为轮转周期;当CPU上就绪任务的数量nr_running满足nr_running < (sysctl_sched_latency/sysctl_sched_min_granularity),轮转周期等于默认轮转周期sysctl_sched_latency,否则轮转周期等于(nr_running * sysctl_sched_min_granularity)。注意轮转周期并不是均分给任务的,而是根据各个任务(准确说是调度实体se)的权重来分配的。该参数的值在linux-5.4中为默认值为6000000ULL,单位nanoseconds。
sched_nr_latency:默认轮转周期内可确保所有任务都能够得到调度的任务数量,即(sysctl_sched_latency/sysctl_sched_min_granularity)。这个参数不是sysctl接口。
这三个参数用在主要由sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)函数用于计算se的时间片。伪代码如下:

【1】根据sysctl_sched_min_granularity、cfs_rq->nr_running以及se在调度组的权重来计算任务(调度实体se)的时间片

static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
    //根据sysctl_sched_min_granularity和cfs_rq->nr_running来决定se的轮转周期slice,
    //要么是sysctl_sched_latency,要么是nr_running * sysctl_sched_min_granularity
        u64 slice = __sched_period(cfs_rq->nr_running + !se->on_rq);

        for_each_sched_entity(se) {
        //计算se在整个层级树中的slice的加权平均值
        }
        return slice;
}

 

【2】在一个调度时钟中断中如果当前cpu上的就绪任务大于1,则check_preempt_tick()函数会被调用来计算当前任务的时间片是否到期,以及决定是否要让其他任务抢占当前任务。伪代码如下:

static void check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
        ideal_runtime = sched_slice(cfs_rq, curr);            //计算curr在一个轮转周期的时间片
        delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;    //计算curr已运行的时间
        if (delta_exec > ideal_runtime) {                    //如果curr的时间片已经用完,则触发抢占
                resched_curr(rq_of(cfs_rq));
          ....
                return;
        }

    //如果curr运行时间不足最小粒度,则不允许抢占
        if (delta_exec < sysctl_sched_min_granularity)
                return;
    //如果curr比下一个任务的的虚拟时间多出一个时间片则触发抢占
        se = __pick_first_entity(cfs_rq);
        delta = curr->vruntime - se->vruntime;

        if (delta < 0)
                return;

        if (delta > ideal_runtime)
                resched_curr(rq_of(cfs_rq));
}

 总结一下:三个参数共同作用起来确保任务在就绪状态的情况下至少运行一个属于自己的时间片,而不会因为优先级、权重原因被频繁抢占。

上一篇:CFS三层内网环境 渗透流程


下一篇:了解了下啥叫cfs/bfs