LINUX进程调度之CFS算法



LINUX进程调度之CFS算法

.概述

Linux2.6.23以来引入了完全公平调度算法;在调度中通过调度器类sched_class对不同的调度算法做了很好的封装,优先级在0-99的实时进程采用调度器类rt_sched_class,对于优先级在100-139的普通进程采用调度器类fair_sched_class,即为完全公平调度类,即本文重点要阐述的内容,空闲进程使用调度器类idle_sched_class。对于普通进程,O(1)算法中的每个进程都采用时间片的概念来实现调度的判断,当一个进程分配给它的时间片耗尽则产生一次调度时机,以选择新的进程来执行。完全公平调度算法则基本上不依靠时间片来判断,但是它也计算进程的运行时间,但是它是根据由优先级确定的权重来计算可以得到运行时间,与等待队列上等待时间最长的进程比较,来确定进程是否需要调度,调度选择的是等待时间最长的进程。

二.时间的统计

2.1进程权重

在完全公平调度算法中,最重要的是根据优先级确定的权重,以及由权重不同产生的CPU时间。

不同优先级的权重如下:

static constint 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,

};

对应优先级从100-139(也可以说是从nice-20-19),其权重基准是0对应1024,从0提高到1,权重减少10%,从0-1,即优先级提高一个等级,权重增加10%CPU时间。

就绪进程有个权重的总和,当有进程启动或者加入到队列里,系统就会根据每个进程的权重算出总的权重,留待后面使用;反之,当有进程没有就绪则将其权重从总和中减掉,可参考函数inc_nr_running()dec_nr_running()

2.2时钟统计

    在进程创建的时候要初始化几个时间变量:

static void __sched_fork(struct task_struct*p)

{

       p->se.exec_start            = 0; //进程开始运行时间

       p->se.sum_exec_runtime              = 0;//本次总的运行时间

       p->se.prev_sum_exec_runtime      = 0;//上次总的运行时间,该值在调度到另外一个进程时由当前的运行时间赋值,即se->prev_sum_exec_runtime = se->sum_exec_runtime;

}

在时钟中断函数中会周期执行task_tick_fair()函数,里面统计一些时间变量。

static voidupdate_curr(struct cfs_rq *cfs_rq)

{

       struct sched_entity *curr =cfs_rq->curr;

       u64 now = rq_of(cfs_rq)->clock;  //取得当前时间

       unsigned long delta_exec;

    ……

       delta_exec = (unsigned long)(now -curr->exec_start);  //进程执行的时间

    __update_curr(cfs_rq, curr, delta_exec);

       curr->exec_start = now;  //更新进程开始的运行时间

…..

}

 

static inlinevoid

__update_curr(structcfs_rq *cfs_rq, struct sched_entity *curr,

            unsigned long delta_exec)

{

   ……

       curr->sum_exec_runtime += delta_exec;

……

       delta_exec_weighted = delta_exec;//从时钟计算中得出的运行时间

       if (unlikely(curr->load.weight !=NICE_0_LOAD)) {

              delta_exec_weighted =calc_delta_fair(delta_exec_weighted,

                                                 &curr->load);//考虑了权重以后的运行时间

       }

       curr->vruntime += delta_exec_weighted;   //该值判断进程在红黑树中的位置,该值越小,越靠近左边,越容易被重新调度到,反之,越到,越是右移,调度机会变小

}

 

在时钟周期中统计完时间后,就要判断该进程运行时间是否已经到达分配给它的份额:

static void

check_preempt_tick(structcfs_rq *cfs_rq, struct sched_entity *curr)

{

       unsigned long ideal_runtime, delta_exec;

 

       ideal_runtime = sched_slice(cfs_rq,curr);//计算当前进程允许占用的时间。

       delta_exec = curr->sum_exec_runtime -curr->prev_sum_exec_runtime;

       if (delta_exec > ideal_runtime)

              resched_task(rq_of(cfs_rq)->curr);//设立调度标记

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值