Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34508
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 42
  • 用 户 组: 普通用户
  • 注册时间: 2015-10-30 14:15
文章分类

全部博文(6)

文章存档

2016年(6)

我的朋友

分类: LINUX

2016-01-02 14:32:27

      完全公平调度CFS是一个针对普通进程(linux还有其它类进程,例如实时进程)的调度类,CFS算法实现定义在文件kernel/sched_fair.c中,是在linux 2.6内核中提出的一类进程调度算法。
一、nice 值解析
       在linux中,nice值用来表示进程优先级,其取值范围是 -20~+19;越大的nice值意味着更低的优先级。
二、CFS 解析
       CFS的做法是每个进程运行一段时间、循环轮转、选择运行时间最少的进程作为下一个运行的进程,而不再采用分配给每个进程时间片的做法,CFS在所有可运行进程总数上基础上计算出一个进程应该运行多久,而不是依靠nice值来计算时间片。nice值在CFS中被作为进程获得处理器使用比的权重,nice值越高(优先级更低)的进程获得更低的处理器使用权重;相反,nice值越低(更高的优先级)的进程获得更高的处理器使用权重。

       1> 运行时间片的计算

       进程运行的“时间片”是通过其权重在全部可运行进程中所占比例和“目标延迟”计算来的,这个“目标延迟”可以理解成调度周期。
       prio和weight之间的转换关系,这是个经验公式,如下图所示

      

        我们假设目标延迟是20ms,现在我们具体看看具有不同nice值的两个可运行进程的运行情况------一个具有默认nice值(0),另一个具有的nice值是5;不同的nice值对应不同的权重,由上图我们可以得知,nice值是5的进程的权重将是默认nice进程的1/3,所以nice值是5的进程和默认nice进程获得的处理器时间分别是15ms和5ms。如果两个可运行的进程的nice值分别是10和15,根据上图计算可得,两进程的权重比是仍然是3:1,故两进程获得的处理器时间分别是15ms和5ms。

       2> runtime 虚拟运行时间

       变量vruntime存放进程的虚拟运行时间,该运行时间(花在运行上的时间和)的计算经过了所有可运行进程总数的标准化(或者说是被加权的)。CFS使用vruntime变量来记录一个程序到底运行了多长时间以及它还应该再运行多久。
       
  1. static void update_curr(struct cfs_rq *cfs_rq)
  2. {
  3.         struct sched_entity *curr = cfs_rq->curr;
  4.         u64 now = rq_of(cfs_rq)->clock_task;
  5.         unsigned long delta_exec;

  6.         if (unlikely(!curr))
  7.                 return;

  8.         /*
  9.          * Get the amount of time the current task was running
  10.          * since the last time we changed load (this cannot
  11.          * overflow on 32 bits):
  12.          */
  13.         delta_exec = (unsigned long)(now - curr->exec_start);
  14.         if (!delta_exec)
  15.                 return;

  16.         __update_curr(cfs_rq, curr, delta_exec);
  17.         curr->exec_start = now;

  18.         if (entity_is_task(curr)) {
  19.                 struct task_struct *curtask = task_of(curr);

  20.                 trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime);
  21.                 cpuacct_charge(curtask, delta_exec);
  22.                 account_group_exec_runtime(curtask, delta_exec);
  23.         }
  24. }

     update_curr()计算了当前进程的执行时间,并且将其存放在变量delta_exec中。然后它又将运行时间传递给了__update_curr(),后者再根据当前可运行进程总数对运行时间进行加权计算。最终将上述的权重值与当前运行进程的vruntime相加。

  1. static inline void
  2. __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
  3.               unsigned long delta_exec)
  4. {
  5.         unsigned long delta_exec_weighted;

  6.         schedstat_set(curr->exec_max, max((u64)delta_exec, curr->exec_max));

  7.         curr->sum_exec_runtime += delta_exec;
  8.         schedstat_add(cfs_rq, exec_clock, delta_exec);
  9.         delta_exec_weighted = calc_delta_fair(delta_exec, curr);

  10.         curr->vruntime += delta_exec_weighted;
  11.         update_min_vruntime(cfs_rq);
  12. }
        update_curr()是由系统定时器周期性调用,无论是在进程处于可运行状态,还是被堵塞处于不可运行状态。

        3> 进程的选择

        当CFS需要选择下一个运行进程时,它会挑选一个具有最小vruntime的进程,这其实就是CFS算法的核心。CFS算法采用红黑树来组织可运行进程队列,并利用其迅速找到最小vruntime值的进程。

       知识点不断更新中,欢迎大家指正!
       附:我是一名刚开始学习linux_kernel的新手,从接触linux到现在已经四个月有余,再此期间,为了搞清楚某些知识点,通常会去反复的看书籍、问经验丰富的师兄、阅读文献、看博客等。经过这些努力,遗留的问题大部分通常都会得到解决。在阅读网上贴子的时候,大部分帖子都会使用相关内容的许多专业术语,这对阅读造成了一定抑制;还有有些内容只有被文字详述,缺乏相关的图标来生动解释。这是我决定写技术博客的第一个原因,我想在介绍相关内容的时候,会对相应的专业术语作一个通俗的解释,对晦涩的内容努力配上一个生动的图表。
       四个月虽然时间不长,可是通过上课、看书、实践,学了不少的内容。但随着不断学习新东西,之前已经被熟悉的内容或者工具,已经没有了清楚的知识框架和使用熟练技巧;换句话说,自己学过的东西已经不可追溯,只是能模糊记个大概,也就是以前的一部分努力白费了。这是我决定写技术博客的第二原因,我想让我的学习可追溯。
       当然,写技术博客可以可以扩展圈子,和相关领域的朋友们交流,共同提升,努力为开源贡献一份力量。
       开源万岁!
阅读(2688) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:ELF 重定位表详解

给主人留下些什么吧!~~