• Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)


      Linux 中采用了两种不同的优先级范围,一种是 nice 值,一种是实时优先级。在上一篇粗略的说了一下 nice 值和实时优先级,仍有不少疑问,本文来详细说明一下进程优先级。linux 内核版本为 linux 2.6.34 。

      进程优先级的相关信息,存放在进程描述符 task_struct 中:

    struct task_struct {
            ...
        int prio, static_prio, normal_prio;
        unsigned int rt_priority;
            ...
    }

      可以看到,有四种进程优先级: prio、static_prio、normal_prio 和 rt_priority,它们的具体定义在 kernel/sched.c 中,在介绍这四种优先级之前,先介绍一下以下宏定义:

    /* linux-kernel 2.6.34 /include/linux/sched.h */
    
    /*
     * Priority of a process goes from 0..MAX_PRIO-1, valid RT
     * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
     * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
     * values are inverted: lower p->prio value means higher priority.
     *
     * The MAX_USER_RT_PRIO value allows the actual maximum
     * RT priority to be separate from the value exported to
     * user-space.  This allows kernel threads to set their
     * priority to a value higher than any user task. Note:
     * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
     */
    
    #define MAX_USER_RT_PRIO     100
    #define MAX_RT_PRIO          MAX_USER_RT_PRIO
    
    #define MAX_PRIO            (MAX_RT_PRIO + 40)
    #define DEFAULT_PRIO        (MAX_RT_PRIO + 20)    // 默认优先级,对应 nice 值为 0 的静态优先级

    1、prio 动态优先级

      prio 的值是调度器最终使用的优先级数值,即调度器选择一个进程时实际选择的值。prio 值越小,表明进程的优先级越高。prio  值的取值范围是 0 ~ MAX_PRIO,即 0 ~ 139(包括 0 和 139),根据调度策略的不同,又可以分为两个区间,其中区间 0 ~ 99 的属于实时进程,区间 100 ~139 的为非实时进程。用语言不好描述,我们通过内核代码来详细描述 prio:

    /* linux-kernel 2.6.34  /kernel/sched.c  */
    
    #include "sched_idletask.c"
    #include "sched_fair.c"
    #include "sched_rt.c"
    #ifdef CONFIG_SCHED_DEBUG
    #include "sched_debug.c"
    #endif
    
    /*
     * __normal_prio - return the priority that is based on the static prio
     */
    static inline int __normal_prio(struct task_struct *p)    // _normal_prio 函数,返回静态优先级值
    {
        return p->static_prio;
    }
    
    /*
     * Calculate the expected normal priority: i.e. priority
     * without taking RT-inheritance into account. Might be
     * boosted by interactivity modifiers. Changes upon fork,
     * setprio syscalls, and whenever the interactivity
     * estimator recalculates.
     */
    static inline int normal_prio(struct task_struct *p)    // normal_prio 函数
    {
        int prio;
    
        if (task_has_rt_policy(p))                 // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0
            prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
        else
            prio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio
        return prio;
    }
    
    /*
     * Calculate the current priority, i.e. the priority
     * taken into account by the scheduler. This value might
     * be boosted by RT tasks, or might be boosted by
     * interactivity modifiers. Will be RT if the task got
     * RT-boosted. If not then it returns p->normal_prio.
     */
    static int effective_prio(struct task_struct *p)       // effective_prio 函数,计算进程的有效优先级,即prio值,这个值是最终调度器所使用的优先级值
    {
        p->normal_prio = normal_prio(p);              // 计算 normal_prio 的值
        /*
         * If we are RT tasks or we were boosted to RT priority,
         * keep the priority unchanged. Otherwise, update priority
         * to the normal priority:
         */
        if (!rt_prio(p->prio))
            return p->normal_prio;                  // 若进程是非实时进程,则返回 normal_prio 值,这时的 normal_prio = static_prio
        return p->prio;                         // 否则,返回值不变,依然为 prio 值,此时 prio = MAX_RT_PRIO -1 - p->rt_priority
    } 
    
    /*********************** 函数 set_user_nice ****************************************/
    void set_user_nice(struct task_struct *p, long nice)
    {
         ....
        p->prio = effective_prio(p);                   // 在函数 set_user_nice 中,调用 effective_prio 函数来设置进程的 prio 值
         ....
    }

      从上面代码中我们知道,当进程为实时进程时, prio 的值由实时优先级值(rt_priority)计算得来;当进程为非实时进程时,prio 的值由静态优先级值(static_prio)得来。即:

    prio = MAX_RT_PRIO - 1 - rt_priority    // 进程为实时进程

    prio = static_prio          // 进程为非实时进程

      简单计算上面的两个式子,可以知道,prio 值的范围是 0 ~ 139 。

    2、static_prio 静态优先级

      静态优先级不会随时间改变,内核不会主动修改它,只能通过系统调用 nice 去修改 static_prio,如下:

    /*
     * Convert user-nice values [ -20 ... 0 ... 19 ]
     * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
     * and back.
     */
    #define NICE_TO_PRIO(nice)    (MAX_RT_PRIO + (nice) + 20)
    #define PRIO_TO_NICE(prio)    ((prio) - MAX_RT_PRIO - 20)
    #define TASK_NICE(p)        PRIO_TO_NICE((p)->static_prio)
    
    /*
     * 'User priority' is the nice value converted to something we
     * can work with better when scaling various scheduler parameters,
     * it's a [ 0 ... 39 ] range.
     */
    #define USER_PRIO(p)        ((p)-MAX_RT_PRIO)
    #define TASK_USER_PRIO(p)    USER_PRIO((p)->static_prio)
    #define MAX_USER_PRIO        (USER_PRIO(MAX_PRIO))
    
    /********************* 函数 set_user_nice *****************************/
    p->static_prio = NICE_TO_PRIO(nice);        // 当有需要时,系统会通过调用 NICE_TO_PRIO() 来修改 static_prio 的值

      由上面代码知道,我们可以通过调用 NICE_TO_PRIO(nice) 来修改 static_prio  的值, static_prio 值的计算方法如下:

    static_prio = MAX_RT_PRIO + nice +20

      MAX_RT_PRIO 的值为100,nice 的范围是 -20 ~ +19,故 static_prio 值的范围是 100 ~ 139。 static_prio 的值越小,表明进程的静态优先级越高

    3、normal_prio 归一化优先级

      normal_prio 的值取决于静态优先级和调度策略,可以通过 _setscheduler 函数来设置 normal_prio 的值 。对于非实时进程,normal_prio 的值就等于静态优先级值 static_prio;对于实时进程,normal_prio = MAX_RT_PRIO-1 - p->rt_priority。代码如下:

    static inline int normal_prio(struct task_struct *p)    // normal_prio 函数
    {
        int prio;
    
        if (task_has_rt_policy(p))                 // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0
            prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
        else
            prio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio
        return prio;
    }

    4、rt_priority 实时优先级

      rt_priority 值的范围是 0 ~ 99,只对实时进程有效。由式子:

    prio = MAX_RT_PRIO-1 - p->rt_priority; 

      知道,rt_priority 值越大,则 prio 值越小,故 实时优先级(rt_priority)的值越大,意味着进程优先级越高

      rt_priority 的值也是取决于调度策略的,可以在 _setscheduler 函数中对 rt_priority 值进行设置。

  • 相关阅读:
    docker 的使用
    WEB应用支持RESTFUL风格方法
    tomcat7 安装 windows 服务
    获取POM.XML依赖的JAR包
    集成 dubbo 微服务
    linux 修改yum 为阿里云源
    poj3904
    2013 ACM/ICPC 长春网络赛E题
    2013 ACM/ICPC 长春网络赛F题
    2013 ACM/ICPC 长沙网络赛J题
  • 原文地址:https://www.cnblogs.com/tongye/p/9615625.html
Copyright © 2020-2023  润新知