Linux内核架构读书笔记 - 2.5.3 处理优先级

 1 优先级的内核表示

  内核使用 0 - 139 表示内部优先级,值越低,优先级越高.0 -99 实时进程使用 nice
值 [-20,19]映射到范围100 - 139,如下图

  

  内核定义了一系列宏来辅助优先级之间的转换

  sched.h


 1 /*
2 * Priority of a process goes from 0..MAX_PRIO-1, valid RT
3 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
4 * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
5 * values are inverted: lower p->prio value means higher priority.
6 *
7 * The MAX_USER_RT_PRIO value allows the actual maximum
8 * RT priority to be separate from the value exported to
9 * user-space. This allows kernel threads to set their
10 * priority to a value higher than any user task. Note:
11 * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
12 */
13
14 #define MAX_USER_RT_PRIO 100
15 #define MAX_RT_PRIO MAX_USER_RT_PRIO
16
17 #define MAX_PRIO (MAX_RT_PRIO + 40)
18 #define DEFAULT_PRIO (MAX_RT_PRIO + 20)

  sched.c


1 /*
2 * Convert user-nice values [ -20 ... 0 ... 19 ]
3 * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
4 * and back.
5 */
6 #define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
7 #define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
8 #define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio)

  2 优先级计算

  动态优先级 task_struct->prio

  普通优先级 task_struct->normal_prio

  静态优先级   task_struct->static_prio (计算起点,已经设置好)

  sched.c


 1 /*
2 * Calculate the current priority, i.e. the priority
3 * taken into account by the scheduler. This value might
4 * be boosted by RT tasks, or might be boosted by
5 * interactivity modifiers. Will be RT if the task got
6 * RT-boosted. If not then it returns p->normal_prio.
7 */
8 static int effective_prio(struct task_struct *p)
9 {
10 p->normal_prio = normal_prio(p);
11 /*
12 * If we are RT tasks or we were boosted to RT priority,
13 * keep the priority unchanged. Otherwise, update priority
14 * to the normal priority:
15 */
16 if (!rt_prio(p->prio))
17 return p->normal_prio;
18 return p->prio;
19 }

 rt_prio检测普通优先级是否在实时范围中

1 static inline int rt_prio(int prio)
2 {
3 if (unlikely(prio < MAX_RT_PRIO))
4 return 1;
5 return 0;
6 }

 普通优先级计算分为 普通进程 和 实时进程 ,普通进程用__normal_prio,实时进程需要rt_priority设置,rt_priority越高,表示优先级越高的实时进程,内核正好相反,因此内核用

 MAX_RT_PRIO-1 - p->rt_priority 计算


/*
* __normal_prio - return the priority that is based on the static prio
*/
static inline int __normal_prio(struct task_struct *p)
{
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)
{
int prio;

if (task_has_rt_policy(p))
prio = MAX_RT_PRIO-1 - p->rt_priority;
else
prio = __normal_prio(p);
return prio;
}

  下图描述了不同类型上述计算结果

  

  注意以下两点:

  •   新建进程用wake_up_new_task唤醒,或使用nice
    系统调用改变静态优先级,使用上述方法计算nice

  •   进程分支出子进程,子进程静态优先级继承父进程,子进程的动态优先级,子进程的动态优先级(prio)设置为父进程的普通优先级.

 3 计算负载权重

  set_load_weight负责根据进程类型及静态优先级计算负载权重

  sched.h

1 struct load_weight {
2 unsigned long weight, inv_weight;
3 };

  一般来说 降低一个 nice值,多获得10% CPU,反之也一样,为了执行该策略,内核将优先级转换为权重,如下


 1 /*
2 * Nice levels are multiplicative, with a gentle 10% change for every
3 * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
4 * nice 1, it will get ~10% less CPU time than another CPU-bound task
5 * that remained on nice 0.
6 *
7 * The "10% effect" is relative and cumulative: from _any_ nice level,
8 * if you go up 1 level, it‘s -10% CPU usage, if you go down 1 level
9 * it‘s +10% CPU usage. (to achieve that we use a multiplier of 1.25.
10 * If a task goes up by ~10% and another task goes down by ~10% then
11 * the relative distance between them is ~25%.)
12 */
13 static const int prio_to_weight[40] = {
14 /* -20 */ 88761, 71755, 56483, 46273, 36291,
15 /* -15 */ 29154, 23254, 18705, 14949, 11916,
16 /* -10 */ 9548, 7620, 6100, 4904, 3906,
17 /* -5 */ 3121, 2501, 1991, 1586, 1277,
18 /* 0 */ 1024, 820, 655, 526, 423,
19 /* 5 */ 335, 272, 215, 172, 137,
20 /* 10 */ 110, 87, 70, 56, 45,
21 /* 15 */ 36, 29, 23, 18, 15,
22 };

  具体转换代码如下,实时进程的权重是普通进程的2倍,SCHED_IDLE进程权重很小

1 #define WEIGHT_IDLEPRIO                3
2 #define WMULT_IDLEPRIO 1431655765


 1 static void set_load_weight(struct task_struct *p)
2 {
3 if (task_has_rt_policy(p)) {
4 p->se.load.weight = prio_to_weight[0] * 2;
5 p->se.load.inv_weight = prio_to_wmult[0] >> 1;
6 return;
7 }
8
9 /*
10 * SCHED_IDLE tasks get minimal weight:
11 */
12 if (p->policy == SCHED_IDLE) {
13 p->se.load.weight = WEIGHT_IDLEPRIO;
14 p->se.load.inv_weight = WMULT_IDLEPRIO;
15 return;
16 }
17
18 p->se.load.weight = prio_to_weight[p->static_prio - MAX_RT_PRIO];
19 p->se.load.inv_weight = prio_to_wmult[p->static_prio - MAX_RT_PRIO];
20 }

  进程队列也有一个负载权重,每次进程倍加入到内核队列的时候,会调用inc_nr_running,这样可以确保就绪队列跟踪记录有多少进程在运行,而且还将进程的权重添加到就绪队列的权重里面,从就绪队列移除时候也会调用对应的函数


 1 /*
2 * Update delta_exec, delta_fair fields for rq.
3 *
4 * delta_fair clock advances at a rate inversely proportional to
5 * total load (rq->load.weight) on the runqueue, while
6 * delta_exec advances at the same rate as wall-clock (provided
7 * cpu is not idle).
8 *
9 * delta_exec / delta_fair is a measure of the (smoothened) load on this
10 * runqueue over any given interval. This (smoothened) load is used
11 * during load balance.
12 *
13 * This function is called /before/ updating rq->load
14 * and when switching tasks.
15 */
16 static inline void inc_load(struct rq *rq, const struct task_struct *p)
17 {
18 update_load_add(&rq->load, p->se.load.weight);
19 }
20
21 static inline void dec_load(struct rq *rq, const struct task_struct *p)
22 {
23 update_load_sub(&rq->load, p->se.load.weight);
24 }
25
26 static void inc_nr_running(struct task_struct *p, struct rq *rq)
27 {
28 rq->nr_running++;
29 inc_load(rq, p);
30 }

Linux内核架构读书笔记 - 2.5.3 处理优先级,码迷,mamicode.com

时间: 2024-10-14 13:14:18

Linux内核架构读书笔记 - 2.5.3 处理优先级的相关文章

Linux内核架构读书笔记 - 2.5.2 数据结构

调度系统各个组建关系如下 激活调度器两种方法:进程睡眠或其他原因放弃CPU,周期性检测 上述两个组件统称为通用调度器或核心调度器. 调度器用于判断接下来运行那个进程,内核支持不同的调度策略( 完全公平调度 实时调度 无事可做的空闲调度进程) 调度器被调用时候 需要执行体系相关的进程上下文切换 每个进程属于某个调度器类,各个调度器负责管理所属进程,通用调度器不涉及进程管理,都由调度器来 下面分别讲述: task_struct 成员 sched.h 1 struct task_struct { 2

Linux内核架构读书笔记 - 2.5.4 核心调度器

什么是核心调度器? 参考前面的博文http://www.cnblogs.com/songbingyu/p/3696414.html 1 周期性调度器 作用: 管理内核中与整个系统和各个进程的调度相关的统计量 负责当前调度类的周期性调度方法 kernel/sched.c 1 /* 2 * This function gets called by the timer code, with HZ frequency. 3 * We call it with interrupts disabled. 4

20135239 益西拉姆 linux内核分析 读书笔记之第四章

chapter 4 进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统可以划分为两类: - 非抢占式多任务: - 进程会一直执行直到自己主动停止运行(这一步骤称为让步) - 抢占式多任务: - Linux/Unix使用的是抢占式的方式:强制的挂起进程的动作就叫做抢占.进程在被抢占之前能够运行的时间是预先设置好的(也就是进程的时间片) 4.2 linux的进程调度 O(1)调度器:对大服务器的工作负载很理想,但是缺少交互进程. 反转楼梯最后期限调度算法

《深入Linux内核架构》笔记 --- 第一章 简介和概述

Linux将虚拟地址空间划分为两个部分,分别称为内核空间和用户空间 各个系统进程的用户空间是完全彼此分离的,而虚拟地址空间顶部的内核空间总是同样的,无论当前执行的是哪个进程. 尽管Intel处理器区分4中特权级别,当Linux只使用两种不同的状态:核心态和用户态.两种状态的关键差别在于对高于TASK_SIZE的内存区域的访问. 在中断上下文中运行不能访问虚拟地址空间中的用户空间部分.CPU大多数时间都在执行用户空间的代码,当应用程序执行系统调用时,则切换到核心态,内核将完成其请求.在此期间,内核

《深入Linux内核架构》附录A&lt;体系结构相关知识&gt;笔记

A.1 概述 为便于扩展到新的体系结构,内核严格隔离了体系结构相关和体系结构无关的代码.内核中特定于处理器的部分,包含定义和原型的头文件保存在include/asm-arch/(例如,include/asm-arm/)目录下,而C语言和汇编程序源代码实现则保存在arch/arch/(例如,arch/arm/)目录下. 联编系统也考虑到一般代码可能需要借助于特定于体系结构的机制.所有特定于处理器的头文件都位于include/asm-arch/.在内核配置为特定的体系结构之后,则建立符号链接incl

《Linux程序设计》&mdash;&mdash;读书笔记(2)

Linux环境: 无论操作系统何时启动一个新程序,参数argc和argv都会被设置并传递给main(即使main函数未声明参数,此时只是不能使用这些参数).这些参数通常由另一个程序提供,一般是shell,它要求操作系统启动该新程序.shell会接受用户输入的命令行,将命令行分解成单词,然后把这些单词放入argv数组. 命令行参数在向程序传递信息方面很有用,很多工具程序使用命令行参数来改变程序的行为或设置选项(这一点我们很熟悉,但是可能很少会联想到正是argc.argv参数在这里发挥作用). 尽管

《Linux程序设计》&mdash;&mdash;读书笔记

UNIX是一套计算机操作系统应遵循的特定规范(定义了所有必需的操作系统函数的名称.接口和行为),完全符合该规范的操作系统才允许使用"UNIX"的商标,否则就是"类UNIX操作系统". 许多类UNIX系统都是商业性质的,如IBM的AIX,HP的HP-UX和Sun的Solaris:也有一些免费的,如FreeBSD和Linux. Linux是一个可以自由发布的类UNIX内核实现.发展之路:UNIX->Minix->Linux. Linux程序: Linux应用

搭建《深入Linux内核架构》的Linux环境

作者 彭东林 [email protected] 软件 Host: Ubuntu14.04 64 Qemu 2.8.0 Linux 2.6.24 busybox 1.24.2 gcc 4.4.7 概述 为了尽量还原<深入Linux内核架构>这本书的环境,我下载了Linux 2.6.24,由于这个内核版本比较老,所以用最新的gcc编译会有问题,所以需要安装一个比较老的gcc,从该内核的README得知,gcc的版本最少应该是3.2. 正文 一.安装GCC 使用apt-cache search g

Linux内核架构与底层--读书笔记

linux中管道符"|"的作用 命令格式:命令A|命令B,即命令1的正确输出作为命令B的操作对象(下图应用别人的图片) 1. 例如: ps aux | grep "test"  在 ps aux中的結果中查找test. 2. 例如:   find . -name "*.txt" | xargs grep "good" -n --color=auto   把find的结果当成参数传入到grep中,即在那些文件内部查找good关键