linux调度器_第三代cfs(3)_分解代码vruntime的详解

来源:互联网 发布:网络购物车功能 编辑:程序博客网 时间:2024/05/02 00:55

前面讲了排队的关键值,是靠这两个参数确定的se->vruntime - cfs_rq->min_vruntime,后一个参数是为了建立一个标准,像一本线二本线那样的概念,所以今天我们来重点讨论第一个参数的情况。

vruntime的详解:

看到虚拟运行时间,肯定会想到有一个真实的运行时间,事实确实是有的。真实的运行的时间做一些计算,就变成虚拟运行时间了。想想看是不是那些优先级高的进程,同样的实际运行时间,虚拟时间要涨的慢一些,那样它就会更靠近红黑树左边的位置,那么就有更大的机会来运行了呢?

事实上内核就是这么来计算的。见如下代码:

我试了把一堆代码贴出来,但是真不是那么容易让人接受,一大堆代码太容易让人望而生畏了,我选择其中重点了来说吧,哎,其实《深入linux内核架构》这本书里也是这么做的,只放些重点的代码进去,我觉得那本书写的很好,我写这些有可能会是多余,但是对于新手来说,也许更能让人容易理解一些吧。我注释的代码,放在最后有兴趣的可以研究下。

精简版代码:

delta_exec = (now - curr->exec_start);//这个是实际运行时间,就是现在的时间减去执行开始的时间,看来变量名字真的很重要,下次我们自己取变量名字也尽可能让别人一看就知道意思呢,delta 这个应该念代尔塔,是微积分还是什么数学里面的概念吧,很小的一个时间段,now就代表现在的时间,curr是current的缩写,就是当前的意思。exec是execute的缩写,执行的意思,start就是开始的意思。有现在时间减去这个进程开始执行的时间,是不是就是这个进程执行的时间了呢。当然这时是物理时间。

现在要来统计这个进程执行的物理时间跟虚拟运行时间了,这是一个求和的过程,刚才delta也可以看出是一个很短的微积分概念。

curr->sum_exec_runtime += delta_exec; //这个是计算一个执行了多少实际的时间,runtime前面并没有加v(virtual)。把每次运行的实际时间加起来就是当前进程的实际执行时间的总和了。然而排队时候选哪个进程运行时,这个然并卵。然而并没有什么卵用。

关键的要来了,上代码:

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;

基本这几行,就表示计算虚拟运行时间的核心了。一行一行来分解吧。

delta_exec_weighted = delta_exec;//weighted是重量的意思,在这里理解为权值。下面分割线里对权值多扯几句,跳过不影响下文,只需记得优先级越高,权值越大。

---------------------------------------------------我是分割线(权值)------------------------------------------------

这部分不插太多代码,就是原来有140个优先级,100-139个给一般进程使用,然而历史原因搞了个nice值-20到19之间来表示值越大优先级越低。为了拉开差距,二代只有140个优先级,并不能很好的拉开差距,所以这里用权值把粒度拉的很开。对应关系如下:

/*
* 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%.)
*/
static const int 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,
};

以前我英文很差,后来为了学好它,我尽可能的多装b,所以到后来,看到英文就想卖弄下,望体谅。

//此段大意,CPU的nice值下降一级,那么将多获得10%的CPU时间,而这个10%中有一个相对(relative)的概念
//来举个例子吧,只有AB两个进程在运行,nice值原本都是0,知权值load都为1024,
//则A进程1024/(1024+1024)=50%的CPU,想象下若要拉开10%的差距,此消彼长,则A=55%,B=45%;
//若此时A的nice值不变,即权值不变,B的nice值上升一级,权值该便多少呢?这就是我们这个权值表的由来了?
//1024/(1024+B的权值) ≈ 55%;计算出来的1024/0.55 - 1024 = 837左右,可见于820相差并不大。
//而内核直接用1/(1+1.25)≈ 0.4444; 取1.25这个基数,这个约等于放大就是我们上面的情况了。
//应该是从0这个nice值对应1024分别向两边扩展的

---------------------------------------------------我是分割线(权值)------------------------------------------------

if (unlikely(curr->load.weight != NICE_0_LOAD))//如果权值不等于某个”基准“权值,

{

delta_exec_weighted= calc_delta_fair(delta_exec_weighted,
&curr->load);
//那么重新计算。

}

也就是说,若是等于某个基准值,就按前面的实际时间计算,负责就重新计算。

怎么重新计算呢?这个有点绕圈,公式是这样的delta_exec_weighted =delta_exec * NICE_0_LOAD/curr->load.weight;

NICE_0_LOAD/curr->load.weightNICE_0_LOAD是一个标准值,若进程重要性比它大,那么curr->load.weight大于NICE_0_LOAD,所以相除小于1,那么乘以执行时间,相当于实际执行时间缩短了,反之,若进程重要性比它小,那么商大于1,相当于执行时间拉长了,而短的时间会排在前面。

最后求和,curr->vruntime += delta_exec_weighted;得出虚拟运行时间。

整个过程基本就是这样的了。若需要更深入的研究可以去看《深入理解linux内核架构这本书》,然后再结合内核源码来理解。

0 0
原创粉丝点击