Linux CFS调度算法关键知识点

  • Post author:
  • Post category:linux


本文对CFS调度算法关键知识点进行梳理

nice 值和运行时间的关系

nice 值的范围-20 ~ 19,进程默认的nice值为0。这些值类似与级别,可以理解成40个等级,nice 值越高,优先级越低,nice值越低,优先级越高。

为什么这么设定,因为nice表示进程友好程度,值越大,对其他进程越友好,就会让出cpu时间给其他进程。

进程每降低一个nice级别,优先级提高一个等级,响应进程可多获得10%的cpu时间。

进程每提升一个nice级别,优先级则降低一个级别,响应进程少获得10%的cpu时间。

nice值相当于系数1.25。

内核提供的nice值与权重对应关系表

代码路径: kernel/sched/core.c

/*
 * Nice levels are multiplicative, with a gentle 10% change for every
 * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
 * nice 1, it will get ~10% less CPU time than another CPU-bound task
 * that remained on nice 0.
 *
 * The "10% effect" is relative and cumulative: from _any_ nice level,
 * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
 * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
 * If a task goes up by ~10% and another task goes down by ~10% then
 * the relative distance between them is ~25%.)
 */
const int sched_prio_to_weight[40] = {
 /* -20 */     88761,     71755,     56483,     46273,     36291,
 /* -15 */     29154,     23254,     18705,     14949,     11916,
 /* -10 */      9548,      7620,      6100,      4904,      3906,
 /*  -5 */      3121,      2501,      1991,      1586,      1277,
 /*   0 */      1024,       820,       655,       526,       423,
 /*   5 */       335,       272,       215,       172,       137,
 /*  10 */       110,        87,        70,        56,        45,
 /*  15 */        36,        29,        23,        18,        15,
};

举例:

假设进程A和B的nice值都为0,那么理想运行时间计算公式

1024 / (1024 + 1024) = 50%

1024是因为A和B的进程权重值1024

当A 进程nice值增加到1,B依然是0

对于A进程理想运行时间

820 / (820 + 1024) = 44.5%

对于B进程理想运行时间

1024 / (820 + 1024) = 55.5%

vruntime 值怎么来的

vruntime = ( delta_exec * nice_0_weight ) / weight

vruntime 表示进程虚拟的运行时间,delta_exec 表示实际运行时间,nice_0_weight 表示nice值为0的进程的权重值,weight表示该进程的权重值。

sched_period 怎么算的

sched_period 是下面说的调度周期,也就是本次调度周期总的cpu时间,是物理运行时间,通过函数 __sched_period 计算得到

代码路径: kernel/sched/fair.c

/*
 * The idea is to set a period in which each task runs once.
 *
 * When there are too many tasks (sched_nr_latency) we have to stretch
 * this period because otherwise the slices get too small.
 *
 * p = (nr <= nl) ? l : l*nr/nl
 */
static u64 __sched_period(unsigned long nr_running)
{
    if (unlikely(nr_running > sched_nr_latency))
        return nr_running * sysctl_sched_min_granularity;
    else
        return sysctl_sched_latency;
}

当进程的数目小于8时,则调度周期等于调度延迟等于6ms。当系统的进程数目大于8时,则调度器周期等于进程的数目乘以0.75 ms,系统要保证每个进程最小调度时间0.75 ms。

ideal_runtime 值怎么来的

ideal_runtime 表示理想运行时间,也就是分配给进程的时间

分配给进程的真实运行时间 = 本次调度周期总的cpu时间 * ( 当前进程的权重 / 就绪队列(runnable)所有进程权重之和 )

所以得出结论

ideal_runtime = 本次调度周期总的cpu时间 * ( 当前进程的权重 / 就绪队列(runnable)所有进程权重之和 )

根据 sched_period 可知,总时间固定的情况,每个进程理想运行时间也是知道的,如果一个进程是cpu密集型,每次调度会使用整个理想时间,如果是IO密集型的,应该用不完这个时间。

总结

sched_period 的目的是决定每个task在本次调度周期可以运行的最大时间。

如果某个task超过了自身的 ideal_runtime,则会自动让出调度的机会,CFS选择 vruntime 最小的task运行,并在下次得到调度的时候,重置 sched_period 和 ideal_runtime。

vruntime 决定的是哪个进程先调度,sched_period 决定的是每个进程在当前调度周期的最大执行时间。



版权声明:本文为lizhijun_buaa原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。