学习和研究中前行,并在分享中提升自己

欢迎订阅阿里内推邮件



linux下cfs 调度器研究:vruntime和时间片

阅读次数: 268| 时间:2018年2月21日 23:08 | 标签:linux

linux cfs调度器研究:vruntime和时间片

前面两篇文章主要介绍了cfs的原理和进程的切换,这篇文章来讲一下vruntime和 cpu slice在cfs中的体现。

先来看一下cfs调度器中cpu slice的计算公式

时间片 = 调度周期 * task权重/该task所在cfs_rq中所有进程权重之和

谈到task的权重,就不得不说一下进程的nice值

进程nice值对其分配到时间片影响

linux中进程的nice值可以反应出进程的权重大小,其取值范围为-20~19,其与进程优先级关系如下

void set_user_nice(struct task_struct *p, long nice)
{
    ...
    p->static_prio = NICE_TO_PRIO(nice);
    ...
}

NICE_TO_PRIO是一个宏定义,其具体表达式如下

#define NICE_TO_PRIO(nice)      (MAX_RT_PRIO + (nice) + 20)

其中MAX_RT_PRIO值为100,那进程的static_prio的取值范围为100~139.而static_prio的大小又会影响task权重的大小

static void set_load_weight(struct task_struct *p)
{
        int prio = p->static_prio - MAX_RT_PRIO; //static_prio - 100
        struct load_weight *load = &p->se.load;

        /*
         * SCHED_IDLE tasks get minimal weight:
         */
        if (p->policy == SCHED_IDLE) {
                load->weight = scale_load(WEIGHT_IDLEPRIO);
                load->inv_weight = WMULT_IDLEPRIO;
                return;
        }

        load->weight = scale_load(prio_to_weight[prio]); //获取相应的weight值
        load->inv_weight = prio_to_wmult[prio];
}

看一下prio_to_weight这个数组值

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,
};      

可以看到prio的值越小其weight值越大。而nice值越小,其prio值就越小。而根据上面的时间片公式,可以得到其权重越大,那么在一个调度周期内其得到的time splice就越大。

于是就有了nice值越小,其权重越大,那么其得到的时间片就越大。其实可以这样理解,进程越nice(值较大),越容易受欺负,那么地位就越低,给的时间就越小。

进程实际运行时间与vruntime之间的换算

我们先看一下换算公式

curr->vruntime+= (运行时间) * NICE_0_LOAD/进程权重

其中NICE_O_LOAD的值为1024,那么从上面的公式可以看出,进程权重越大,其vruntime增加速度越小,那么获取运行的机会就多。

实际测试

为了验证nice值对程序运行时间的影响,我们简单的写个程序

#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>
#include<sys/sysinfo.h>
#include <sys/syscall.h>
#define __USE_GNU  
#include <sched.h>
void test_while()
{
    int n = 0;
    for(n; n < 10000; --n)
    ;
}


int main()
{
    pid_t tid;
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;

    CPU_ZERO(&mask);
    CPU_SET(1, &mask); /* add CPU0 to cpu set */
    time_t t1,t2,t3;
    time(&t1);
    pid_t pid = fork();
    if (pid == 0) {
        int nice = getpriority(PRIO_PROCESS, 0);
        printf("parent nice %d\n", nice);
        tid = syscall(__NR_gettid);
        sched_setaffinity(tid, sizeof(cpu_set_t), &mask);
        test_while();
        time(&t2);
        printf("parent cost %ld sec\n", t2-t1);
    }  else if (pid > 0) {
       tid = syscall(__NR_gettid);
       sched_setaffinity(tid, sizeof(cpu_set_t), &mask);
       setpriority(PRIO_PROCESS, 0, 19);
       int nice = getpriority(PRIO_PROCESS, 0);
       printf("child nice %d\n", nice);
       test_while();
       time(&t3);
       printf("child cost %ld sec\n", t3-t1);
    }
    sleep(20);
    return 0;
}

子进程和父进程做同样的运算,但是不同的优先级,同时,为了效果更明显,把两个进程都绑定在一个核心上,看一下结果如下

child nice 19
parent nice 0
parent cost 8 sec
child cost 16 sec

可以看到,基本上子进程消耗的时间是父进程的一倍,下面再看一下同样nice值的情况下结果

child nice 0
parent nice 0
parent cost 17 sec
child cost 17 sec

可以看到时间是一样的,也就是说分到的时间片是相等的。