进程调度的数据结构和优先级

1 进程的优先级


每个普通进程都有它自己的静态优先级,位于task_struct的static_prio字段,调度程序使用静态优先级来估价系统中这个进程与其它普通进程之间调度强度。但是,注意,调度程序不是根据静态优先级来决定调度哪个进程的,而是动态优先级,后面会详细谈到。内核用100(最高优先级)到139(最低优先级)的整数表示普通进程的静态优先级 。注意,值越大静态优先级就越低。

新进程总是继承其父进程的静态优先级。不过,通过系统调用nice()和setprioritry(),用户可以改变自己拥有的进程的静态优先级。

进程静态优先级本质上决定了进程的基本时间片,即进程用完了以前的时间片,系统分配给进程的时间片长度 。静态优先级和基本时间片的关系用下列公式确定:

 

进程的基本时间片实现函数为task_timeslice:
static inline unsigned int task_timeslice(struct task_struct *p)
{
    return static_prio_timeslice(p->static_prio);
}
static unsigned int static_prio_timeslice(int static_prio)
{
    if (static_prio < NICE_TO_PRIO(0)) //静态优先级小于120
        return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio); //(140-static_prio)*20
    else
        return SCALE_PRIO(DEF_TIMESLICE, static_prio);//(140-static_prio)*5
}
#define NICE_TO_PRIO(nice)    (MAX_RT_PRIO + (nice) + 20)
#define MAX_USER_RT_PRIO    100
#define MAX_RT_PRIO        MAX_USER_RT_PRIO

 

我们看到,静态优先级越高,其基本时间片就越长。最后的结果是,与优先级低的进程相比,通常优先级较高的进程获得更长的CPU时间片。

普通进程除了静态优先级,还有动态优先级,其值的范围也是是100(最高优先级MAX_RT_PRIO,低于100就成了实时进程了 )到139(最低优先级MAX_PRIO)。动态优先级是调度程序选择新进程来运行的时候使用的数。它与静态优先级的关系用下面的所谓经验公式(empirical formula)表示:

动态优先级 = max (100, min (静态优先级 - bonus + 5, 139))   (2)

 

动态优先级的计算主要由 effect_prio() 函数完成,该函数实现相当简单,从中可见非实时进程的优先级仅决定于静态优先级(static_prio)和进程的平均睡眠时间(sleep_avg)两个因素,而实时进程的优先级实际上是在sched_setscheduler() 中设置的(详见"实时进程调度系统"博文,以下仅考虑非实时进程),且一经设定就不再改变。

动态优先级的计算函数是effective_prio,函数effective_prio()读current的static_prio和sleep_avg字段,并根据前面的公式计算出进程的动态优先级:

    static int effective_prio(struct task_struct *p)
    {
        p->normal_prio = normal_prio(p);//首先计算出普通进程的优先级,存放在task_struct的normal_prio字段
        if (!rt_prio(p->prio))
            return p->normal_prio;
        return p->prio; //如果是实时进程,优先级不变
    }

    static inline int normal_prio(struct task_struct *p)
    {
        int prio;
        if (has_rt_policy(p))
            prio = MAX_RT_PRIO-1 - p->rt_priority;
        else
            prio = __normal_prio(p);
        return prio;
    }
    #define rt_prio(prio)        unlikely((prio) < MAX_RT_PRIO) //prio小于100就是实时进程
    static inline int __normal_prio(struct task_struct *p)
    {//执行该函数的前提是非实时进程
        int bonus, prio;
        bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;
        prio = p->static_prio - bonus;
        if (prio < MAX_RT_PRIO)  // MAX_RT_PRIO的值为100
            prio = MAX_RT_PRIO;  // 不能让你普通进程的优先级高于实时进程
        if (prio > MAX_PRIO-1)   // MAX_PRIO的值为140
            prio = MAX_PRIO-1;   // 不能超过最大优先级139
        return prio;
    }

动态优先级算法的实现关键在 sleep_avg 变量上,在effective_prio() 中,sleep_avg 的范围是 0~MAX_SLEEP_AVG,经过以下公式转换后变成-MAX_BONUS/2~MAX_BONUS/2 之间的 bonus:
bonus = (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / MAX_SLEEP_AVG) - MAX_BONUS/2
#define MAX_BONUS        (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100)
#define MAX_USER_PRIO        (USER_PRIO(MAX_PRIO))
#define USER_PRIO(p)        ((p) - MAX_RT_PRIO)
#define MAX_RT_PRIO        MAX_USER_RT_PRIO
#define MAX_USER_RT_PRIO    100
.........弄得那么复杂,其实MAX_BONUS是定值10,MAX_SLEEP_AVG也是定值:
#define MAX_SLEEP_AVG        (DEF_TIMESLICE * MAX_BONUS)
#define DEF_TIMESLICE        (100 * HZ / 1000)

#define CURRENT_BONUS(p) (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / MAX_SLEEP_AVG)
#define NS_TO_JIFFIES(TIME)    ((TIME) / (1000000000 / HZ))

所以bonus与平均睡眠时间sleep_avg成正比。 不管怎么说,sleep_avg 反映了调度系统的两个策略:交互式进程优先和分时系统的公平共享。

 

bonus(奖赏)是从范围0~10的值,值小于5表示降低动态优先级以惩戒,值大于5表示增加动态优先级以使奖赏。bonus的值依赖于进程的过去情况,与进程的平均睡眠时间有关,也就是说,平均睡眠时间越久,bonus值越大。

那么,什么是平均睡眠时间呢?粗略地讲,平均睡眠时间就是进程在睡眠状态中所消耗的平均纳秒数,其存放在task_struck的sleep_avg字段中。注意,这绝对不是对过去时间的求平均值操作 ,因为TASK_INTERRUPTIBLE 状态和TASK_UNINTERRUPTIBLE状态所计算出的平均睡眠时间是不同的,而且,进程在运行的过程中平均睡眠时间递减。最后,平均睡眠时间永远不会大于1s。

 

根据CURRENT_BONUS宏

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值