在抽象模型中vruntime决定了进程被调度的先后顺序,在真实模型中决定被调度的先后顺序的参数是由函数entity_key决定的。   
static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
    return se->vruntime - cfs_rq->min_vruntime;
}
enqueue_task_fair---->enqueue_entity---->__enqueue_entity---->entity_key决定插入就绪队列的位置。

普通进程分为40个等级,每个等级对应一个权重值,权重值用一个整数来标示。权重值定义在数组prio_to_weight[40]中;普通进程的权重值最大为88761,最小为15。默认情况下,普通进程的权重值为1024(由NICE_0_LOAD指定)。weight是由进程的静态优先级static_prio决定的,静态优先级越高(static_prio值越小)weight值越大。普通进程的默认 nice值为0,即默认静态优先级为120,它的weight值为prio_to_weight[20],即1024。因此NICE_0_LOAD的值就 为1024。

vruntime行走速度:
    系统规定:默认权重值(1024)对应的进程的vruntime行走时间与实际运行时间runtime是1:1的关系。由于vruntime的行走速度和权重值成反比,那么其它进程的vruntime行走速度都通过以下两个参数计算得到:1、该进程的权重值2、默认进程的权重值。
    例如权重为3096的进程的vruntime行走速度为:1024/3096 * (wall clock)。
    “真实时钟速度”即为runtime(即 wall clock)行走的速度。

进程执行执行期间周期性调度器周期性地启动,其负责更新一些相关数据,并不负责进程之间的切换:
    timer_tick()---->update_process_times---->schedule_tick()
    schedule_tick---->task_tick_fair---->entity_tick()---->update_curr()
    update_curr()函数完成相关数据的更新。
        update_curr()---->delta_exec = (unsigned long)(now - curr->exec_start)
                              |-->__update_curr()
                              |-->curr_exec_start = now;
    update_curr()函数只负责计算delta_exec以及更新exec_start。其它工作由__update_curr()函数完成:
        1、更新当前进程的实际运行时间(抽象模型中的runtime)。
        2、更新当前进程的虚拟时间vruntime。
        3、更新cfs_rq->min_vruntime。
           在当前进程和下一个将要被调度的进程中选择vruntime较小的值。然后用该值和cfs_rq->min_vruntime比较,如果比min_vruntime大,则更新cfs_rq为的min_vruntime为所求出的值。

考虑下当创建新进程或者进程唤醒时,vruntime在真实模型中的处理方式:
I、新建进程
    进程的ideal_time长度和weight成正比,vruntime行走速度与weight值成反比。因此当每个进程在period时间内,都执行了自己对应的ideal_time长时间,那么他们的vruntime的增量相等。而nice为0的进程的vruntime行走速度等于runtime行走速度,所以每个进程都运行它自己对应的ideal_runtime时间,其它进程的vruntime增量都等于nice值为0的进程的ideal_runtime。假设初始情况下,它们的所有进程的vruntime值都等于0,那么当一个进程运行完runtime的时间为ideal_time,那么它的vruntime将为最大,只要其它进程的运行总时间没有达到各自对应的ideal_runtime值,那么它始终排在进程队列的末尾。

对于新进程,task_fork_fair()->place_entity(cfs_rq, se, 1),其intial参数为1。新进程的vruntime值被设置为min_vruntime+sched_vslice(cfs_rq, se), sched_vslice()函数可计算出nice值为0的进程的ideal_runtime。其作用是将新加入的进程的标记为“它在period长时间内已经运行它对应的ideal_time长时间”,那么新加入进程在理论上(所有进程都执行它对应的ideal_runtime时间,没有发生睡眠、进程终止等特殊情况)只有等待period之后才能被调度。
    sched_vslice(cfs_rq, se)---->calc_delta_fair(sched_slice(cfs_rq, se), se), sched_slice()计算新建进程的ideal_runtime,calc_delta_fair()将ideal_runtime转换成vruntime。

II、睡眠进程被唤醒
    将进程的vruntime值设置为cfs_rq->min_vruntime值,然后再进行一下补偿:将vruntime减去与sysctl_sched_latencyd相关的一个数值。进程进入睡眠状态时cfs_rq->min_vruntime就大于或等于该进程的vruntime值,它在睡眠过程中vruntime值是不改变的,但是cfs_rq->min_vruntime的值却是单调增加的,进程醒来后补偿的量由sysctl_sched_latency给出,不管进程受到的不公平待遇大还是小,一律只补偿这么多。

真实模型总结:
    a)进程在就绪队列中用键值key来排序,它没有保存在任何变量中,而是在需要时由函数entity_key()计算得出。它等于
        key = task->vruntime - cfs_rq->min_vruntime
    b)各个进程有不同的重要性(优先等级),越重要的进程权重值weight(task.se.load.weight)越大。
    c)每个进程vruntime行走的速度和weight值成反比。权重值为1024(NICE_0_LOAD)的进程vruntime行走速度和runtime相同。
    d)每个进程每次获得CPU使用权最多执行与该进程对应的ideal_runtime长时间。该时间长度和weight值成正比,它没有用变量来保存,而是需要使用sched_slice()函数计算得出。
    e)ideal_runtime计算的基准是period,它也没有用变量来保存,而是由__sched_period()计算得出。

进程的优先等级决定了其权重值,task_struct中与优先级相关数据成员:
    a)static_prio,指普通进程的静态优先级(实时进程没用该参数),值越小则优先级越高。静态优先级是进程启动时分配的优先级。它可以用nice()或者sched_setscheduler()系统调用更改,否则在运行期间一直保持恒定。

注意:关于a),注意本文的结尾添加的注释。

b)rt_priority,表示实时进程的优先级(普通进程没用该参数),它的值介于[0~99]之间。rt_priority的值越大其优先级越高。
    c)normal_prio,由于static_prio和rt_priority与优先级的关联性不相同,因此用normal_prio统一下“单位”,统一成:normal_prio值越小则进程优先级越高。因此,normal_prio也可以理解为:统一了单位的“静态”优先级。
    d)prio,在系统中使用prio判断进程优先级,prio是进程的动态优先级,其表示进程的有效优先级。对于实时进程来说,有效优先级prio就等于它的normal_prio。普通进程可以临时提高优先级,通过改变prio实现,动态优先级的提高不影响进程的静态优先级。父进程的动态优先级不会遗传给子进程,子进程的动态优先级prio初始化为父进程的静态优先级。

注:

由于在某些情况下需要暂时提高进程的优先级,因此不仅需要静态优先级和普通优先级,还需要动态优先级prio;

参考《深入Linux内核架构》p70-76、 p_288-290;

linux内核的优先级继承协议(pip)http://www.verydemo.com/demo_c167_i123862.html

进程优先级逆转问题的解决   http://blog.chinaunix.net/uid-28279855-id-3376827.html

为了在Linux中使用Priority Inheritance Protocol协议来解决优先级反转问题,Linux中引入实时互斥量rt_mutex,在task_struc结构体中也引入了pi_waiters链表,需要注意的流程为:

rt_mutex_slowlock() ----> __rt_mutex_slowlock() ---->

task_blocks_on_rt_mutex() ---->  __rt_mutex_adjust_prio()

|--> rt_mutex_adjust_prio_chain()

__rt_mutex_adjust_prio调整了当前持有锁的进程的动态优先级(继承自等待队列中所有进程的最高优先级),rt_mutex_adjust_prio_chain()如果被调整的动态优先级的进程也在等待某个资源,那么也要链式地调整相应进程的动态优先级。

关于Priority Inversion可以参考《Operating System Concepts》9_ed p217-218

linux cfs调度器的更多相关文章

  1. linux cfs调度器_理论模型

    参考资料:<调度器笔记>Kevin.Liu <Linux kernel development> <深入Linux内核架构> version: 2.6.32.9 下 ...

  2. linux cfs调度器_模型实现

    调度器真实模型的主要成员变量及与抽象模型的对应关系 I.cfs_rq结构体    a) struct sched_entity *curr        指向当前正在执行的可调度实体.调度器的调度单位 ...

  3. Linux内核——进程管理之CFS调度器(基于版本4.x)

    <奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...

  4. Linux进程管理 (2)CFS调度器

    关键词: 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 Linux进程管理 ( ...

  5. 【原创】(五)Linux进程调度-CFS调度器

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  6. CFS调度器(1)-基本原理

    首先需要思考的问题是:什么是调度器(scheduler)?调度器的作用是什么?调度器是一个操作系统的核心部分.可以比作是CPU时间的管理员.调度器主要负责选择某些就绪的进程来执行.不同的调度器根据不同 ...

  7. Linux CFS调度器之pick_next_task_fair选择下一个被调度的进程--Linux进程的管理与调度(二十八)

    1. CFS如何选择最合适的进程 每个调度器类sched_class都必须提供一个pick_next_task函数用以在就绪队列中选择一个最优的进程来等待调度, 而我们的CFS调度器类中, 选择下一个 ...

  8. Linux CFS调度器之虚拟时钟vruntime与调度延迟--Linux进程的管理与调度(二十六)

    1 虚拟运行时间(今日内容提醒) 1.1 虚拟运行时间的引入 CFS为了实现公平,必须惩罚当前正在运行的进程,以使那些正在等待的进程下次被调度. 具体实现时,CFS通过每个进程的虚拟运行时间(vrun ...

  9. Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)

    1. 负荷权重 1.1 负荷权重结构struct load_weight 负荷权重用struct load_weight数据结构来表示, 保存着进程权重值weight.其定义在/include/lin ...

随机推荐

  1. 解析Delphi 窗口置顶,及非主窗口置顶

    方法一: procedure TForm1.Button2Click(Sender: TObject);begin Form2.Show; Application.NormalizeTopMosts; ...

  2. JAVA-JSP内置对象之request获得封装所有参数值的Map

    相关资料:<21天学通Java Web开发> 获得封装所有参数值的Map1.通过request对象的getParameterMap()方法来获得封装所有的参数值的Map对象.2.通过该Ma ...

  3. Android 底部按钮BottomNavigationView + Fragment + viewPager 的使用(一)

    实现的效果,左右滑动,底部栏跟着滑动,中间加的是分帧的页面        上代码:主页面activity_main.xml <?xml version="1.0" encod ...

  4. THEOS的第一个TWeak的成功创建

    THEOS的第一个TWeak的成功创建html, body {overflow-x: initial !important;}.CodeMirror { height: auto; } .CodeMi ...

  5. Badboy+Jmeter进行性能测试

    摸索了两天,终于搞定! 目的:使用Badboy和Jmeter添加5000个系统用户 一开始用Badboy进行批量添加,想先在excel中准备好5000个用户名,再导入到Badboy中.但是一直不成功, ...

  6. if 语句练习 身高体重问题

    public class d { /** * @param args */ public static void main(String[] args) { // TODO 自动生成的方法存根 int ...

  7. USB入门

    简述 USB(Universal Serial Bus)全称通用串口总线,USB为解决即插即用需求而诞生,支持热插拔.USB协议版本有USB1.0.USB1.1.USB2.0.USB3.1等,USB2 ...

  8. 一、安装MYSQL

    数据库就是数据的仓库.MYSQL数据库软件它也是一个独立的软件.它是和PHP配合最好的一种数据库.MYSQL数据库也可以作为其它编程语言的数据源. MYSQL的官方网站:http://www.mysq ...

  9. 【异常】IOException parsing XML document from class path resource [xxx.xml]

    1.IDEA导入项目运行出现异常 org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing ...

  10. Excel相同内容如何设置相同的背景色

    有这样一个需求就是实现EXCEL的相同内容的背景色相同.并且内容不同的时候达到隔行变色的效果,记录下实现的效果,如果大家有什么更好的办法请给我指点一下.具体操作如下: 首先将是比较的列"20 ...