linux cfs调度器
在抽象模型中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调度器的更多相关文章
- linux cfs调度器_理论模型
参考资料:<调度器笔记>Kevin.Liu <Linux kernel development> <深入Linux内核架构> version: 2.6.32.9 下 ...
- linux cfs调度器_模型实现
调度器真实模型的主要成员变量及与抽象模型的对应关系 I.cfs_rq结构体 a) struct sched_entity *curr 指向当前正在执行的可调度实体.调度器的调度单位 ...
- Linux内核——进程管理之CFS调度器(基于版本4.x)
<奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...
- Linux进程管理 (2)CFS调度器
关键词: 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 Linux进程管理 ( ...
- 【原创】(五)Linux进程调度-CFS调度器
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- CFS调度器(1)-基本原理
首先需要思考的问题是:什么是调度器(scheduler)?调度器的作用是什么?调度器是一个操作系统的核心部分.可以比作是CPU时间的管理员.调度器主要负责选择某些就绪的进程来执行.不同的调度器根据不同 ...
- Linux CFS调度器之pick_next_task_fair选择下一个被调度的进程--Linux进程的管理与调度(二十八)
1. CFS如何选择最合适的进程 每个调度器类sched_class都必须提供一个pick_next_task函数用以在就绪队列中选择一个最优的进程来等待调度, 而我们的CFS调度器类中, 选择下一个 ...
- Linux CFS调度器之虚拟时钟vruntime与调度延迟--Linux进程的管理与调度(二十六)
1 虚拟运行时间(今日内容提醒) 1.1 虚拟运行时间的引入 CFS为了实现公平,必须惩罚当前正在运行的进程,以使那些正在等待的进程下次被调度. 具体实现时,CFS通过每个进程的虚拟运行时间(vrun ...
- Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)
1. 负荷权重 1.1 负荷权重结构struct load_weight 负荷权重用struct load_weight数据结构来表示, 保存着进程权重值weight.其定义在/include/lin ...
随机推荐
- WPF学习笔记(3)——style
http://www.cnblogs.com/Zhouyongh/archive/2011/08/01/2123610.html Style 用来在类型的不同实例之间共享属性.资源和事件处理程序,您可 ...
- Android MediaScanner 总纲
1. MediaScanner HEAD 2. 应用层 MediaProvider packages\providers\MediaProvider (1) MediaProvider package ...
- 未能加载文件或程序集“System.Web.Mvc, Version=3.0.0.0,
直接下载安装 ASP.NET MVC 3.0就可以了
- am335x Lan8710a 双网口配置
一. 经过调试, LAN8710A在 am335x 上面需要使用 GMII的模式,设备树 pin mux配置如下: // 下面是工作模式的配置,在睡眠模式下是配成GPIO模式 162 cpsw_def ...
- [设备]Linux设备是否可以被多个进程或者线程同时Open?
当然可以 只要底层driver没有对重复打开做特殊处理,一般都可以被两个进程open 那当两个进程同时打开一个设备,当此设备收到数据时,怎么能保证每个进程都能收到数据?
- IBatis批量插入数据
IBatis插入注意,数据量比较多的花,需要分批插入,策略是dao里面控制插入批次,mapper里面批量插入即可 @Override public Long insertBatch(List<W ...
- JMeter (3) —— JMeter录制脚本并压力测试用户登陆场景以CAS SSO为例(101 Tutorial)
JMeter (3) -- JMeter录制脚本并压力测试用户登陆场景以CAS SSO为例(101 Tutorial) 主要内容 JMeter录制脚本并进行压力测试用户登陆场景,并以CAS SSO单点 ...
- jQuery(十二);事件绑定
一.bind() bing()用来绑定事件,例如: 二.unbind() unbind()用来解除事件的绑定.例如: 三.on() on()方法用来绑定事件,例如: 四.off() off()方法用来 ...
- 关于Unity中GrabPass截屏的使用和Shader的组织优化
GrabPass截屏 可以用来截屏,截屏后把纹理传给下一个通道使用. 1:使用抓屏通道, GrabPass {} 或 GrabPass { “ 纹理名称”}; 使用GrabPass {}后,可以用_G ...
- Python之从numpy.array保存图片
1.用scipy import scipy scipy.misc.imsave('test.jpg', img) 2.用PIL from PIL import Image im = Image.fro ...