一、概述

  决定何时、如何选择一个新进程运行的这组规则叫做:调度策略(scheduling policy)。

  Linux的调度是基于分时技术(time sharing):多个进程以“时间多路复用”方式运行,因为CPU的时间呗分成“片”(slice),给每个可运行进程分配一片。如果当前运行进程的时间片或时限(quantum)到期时,该进程还没有运行完毕,进程切换就会发生。

  调度策略也是根据进程的优先级对它们进行分类。在Linux中,进程优先级是动态的:在较长时间内没有运行的进程,会动态提升它们的优先级;相反地,对于在CPU上运行较长时间的进程,会降低它们的优先级来惩罚它们。

  所以,实现调度的工具是调度器(scheduler),调度的对象是进程(process),调度的方法是调度策略(包括调度算法)。

二、CPU调度器

这里主要讲了cpu调度器的工作内容和目的:

  1. 多个task会共享CPU资源
  2. 那如何进行任务切换选择呢?
    • 当前运行的task中止
    • 当前运行的task sleep(wait event)
    • 新task创建,或者sleep的task唤醒了
    • 当前运行的task的时间片用完

那调度器的目标是什么?

  1. 公平调度各个task
  2. 基于task的优先级来分配时间片
  3. task的respnse时间短
  4. 高throughput(task执行成功)
  5. 在多个cpu间,负载均衡
  6. 低功耗
  7. 调度器代码运行开销低

调度器会和工作在一些框架、服务器、PC、嵌入式/手机中。

三、O(1)调度器

在2.6.23(2007)以前,Linux调度器使用的是O(1)调度器:

  • 调度器分140个优先级等级:0-99是RT task,100-139是User task
  • 每个cpu的runqueue有2个数组:Active,Expaired
  • 每个数组都有140个entry,对应每个优先级
  • 每个entry是一条FIFO队列结构的链表
  • 140位的bitmap用来检测每个优先级list
  • 时间片会根据task的优先级进行分配
  • 运行时间expaire的task会从Active数组移动到Expaired数组
  • 当Active数组为空时,就交换2个数组。即,将Expaired数组变为Active;Active(此时为空)变为Expaired
  • task的入rq和出rq,以及next task的选择都是在固定时间内完成

最后在O(1)调度器已经被CFS替代。

四、当前调度器架构

  • 在kernel 2.6.23(2007)后,由Ingo Molnar引入
  • 在调度的class中,还存在调度policy
  • 不同的调度class,高优先级的,越早执行
  • task可以在cpu、调度policy、调度class间进行迁移

4.1  调度class

由struce sched_class结构体实现:

struct sched_class {
const struct sched_class *next;
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
...
struct task_struct * (*pick_next_task) (struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
...
};

内核中一共有5中调度class,优先级从高到低:STOP > DL > RT > CFS > IDLE,他们通过链表实现,并链接起来的。

4.2  主调度函数Schedule()

内核中进程调度,最主要的实现是Schedule()函数。它完成如下工作:

  • 选取下一个runnable的task,并将task放在cpu上运行
  • 按class优先级搜索task来运行,最先从STOP class开始
  • 轮询搜索:for_each_class()
  • 实现方式:pick_next_task():
again:
for_each_class(class) {
p = class->pick_next_task(rq, prev, rf);
if (p) {
if (unlikely(p == RETRY_TASK))
goto again;
return p;
}
} /* The idle class should always have a runnable task: */
BUG();

4.3  调度class与policy

在不同的调度class下,可能会有不同的调度policy实现:

● Stop
  ○ No policy
● Deadline
  ○ SCHED_DEADLINE
● Real Time
  ○ SCHED_FIFO
  ○ SCHED_RR
● Fair
  ○ SCHED_NORMAL
  ○ SCHED_BATCH
  ○ SCHED_IDLE
● Idle
  ○ No policy

不同的class代表不同的调度优先级;不同的policy同样也意味着不同的调度方式。

4.4  调度class:STOP

STOP类型的class有如下特点:

  • 是最高优先级的class(但是这个class不开放给系统user使用的)
  • 只能在smp系统上可用(stop_machine()在单核处理器下不可用)------括号内的具体没怎么理解
  • 可以抢占所有task,并任何事件都不能抢占它
  • 实现方式是:停止运行的其他所有task,而在cpu上运行一个特定的函数
  • 没有调度policy
  • 属于stop class的per cpu内核线程:migration/N ------“N”为cpu core number
  • 在以下情况下使用:task迁移、CPU hotplug、RCU、ftrace、cloclevents等

4.5  调度class:Deadline(DL)

Deadline类型的class有如下特点:

  • 在kernel 3.14(2013),由Dario Faggioli & Juri Lelli引入
  • 在系统中,属于可以使用的最高优先级的class
  • 调度policy为SCHED_DEADLINE
  • 由红黑树结构实现(自平衡树)
  • 在以下情况下使用:周期性的实时task,例如:视频编解码

4.6  调度Real-time(RT)

Real-time类型的class有如下特点:

  • 符合POSIX标准要求
  • task优先级范围:0-99
  • 优先级在kernel和userspace中相反:0在kernel中,代表最高优先级;而在userspace中代表最低优先级
  • 相同优先级下的调度policy:
    • SCHED_FIFO
    • SCHED_RR,默认时间片长度为100ms
  • 由链表实现
  • 在以下情况下使用:latency敏感的task,例如:IRQ threads

4.7  调度CFS(Completely Fair Scheduler)

CFS类型的class有如下特点:

  • 由Ingo Molnar引入
  • 调度policy:
    • SCHED_NORMAL:普通task
    • SCHED_BATCH:批处理 task(batch task,非交互型)
    • SCHED_IDLE:低优先级task
  • 由红黑树结构实现
  • 跟踪task的虚拟运行时间(vruntime,task拥有的运行时间)
  • 虚拟运行时间(vruntime)最短的task,最优先运行
  • task的优先级作为权重,会影响虚拟运行时间的计算(vruntime)
  • 权重越大,虚拟运行时间(vruntime)计算时的增量就越小
  • task的优先级计算:120+nice值(nice范围:-20 ~ +19)
  • 用于所有其他类型的task,例如:shell

4.7  调度Idle

Idle类型的class有如下特点:

  • 最低优先级的调度class
  • 没有调度policy
  • 属于idle class的per cpu内核线程(idle):swapper/N ------“N”为cpu core number
  • idle线程仅会在没有其他task的情况下,在cpu上运行
  • idle线程可以让cpu进入低功耗状态

五、Runqueue

  • 每个CPU都由一个struct rq的实例
  • 每个”rq“包含了DL、RT、CFS的runqueue
  • Runnable的task会被压入上面提到的那些runqueue中
  • 在struct rq中由很多其他的信息和状态
struct rq {
...
struct cfs_rq cfs;
struct rt_rq rt;
struct dl_rq dl;
...
}

Linux内核进程调度overview(1)的更多相关文章

  1. linux内核 进程调度

    概念: 进程调度决定那个进程投入运行,运行多长时间. 进程调度没有太复杂的原理,最大限度的利用处理器时间的原则是:只要有可执行的程序,那么总会有进程在执行,如果可运行的进程比处理器数目要多,那么注定要 ...

  2. Linux内核分析:实验八--Linux进程调度与切换

    刘畅 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这篇文章主要分析Li ...

  3. 第3章(1) Linux内核相关概念

    Linux内核的组成 1. Linux内核源代码的目录结构 arch:包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如 i386.arm. arm64.powerpc.mips 等.Linu ...

  4. 《Linux内核设计与实现》读书笔记 第四章 进程调度

    第四章进程调度 进程调度程序可看做在可运行太进程之间分配有限的处理器时间资源的内核子系统.调度程序是多任务操作系统的基础.通过调度程序的合理调度,系统资源才能最大限度地发挥作用,多进程才会有并发执行的 ...

  5. linux 内核学习之八 进程调度过程分析

    一  关于进程的补充 进程调度的时机 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule() ...

  6. Linux内核分析——理解进程调度时机跟踪分析进程调度与进程切换的过程

    20135125陈智威 +原创作品转载请注明出处 +<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验 ...

  7. Linux内核分析之理解进程调度时机跟踪分析进程调度与进程切换的过程

    一.原理分析 1.调度时机 背景不同类型的进程有不同的调度需求第一种分类I/O-bond:频繁的进行I/O:通常会花费很多时间等待I/O操作的完成CPU-bound:计算密集型:需要大量的CPU时间进 ...

  8. Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

    ID:fuchen1994 姓名:江军 作业要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否 ...

  9. 【读书笔记】《Linux内核设计与实现》进程管理与进程调度

    大学跟老师做嵌入式项目,写过I2C的设备驱动,但对Linux内核的了解也仅限于此.Android系统许多导致root的漏洞都是内核中的,研究起来很有趣,但看相关的分析文章总感觉隔着一层窗户纸,不能完全 ...

随机推荐

  1. linux下在用python向文件写入数据时'\n'不起作用

    网上翻看一圈,大家都说利用write写数据换行,在linux下用'\n',windows下利用'\r\n',可是尝试了一下,'\n'在windows底下可换行,在linux底下居然不起作用,最后利用' ...

  2. Linux文件操作命令并举例说明其作用

    ls ,常用于查看当前文件下有工作中需要的文件 cd, 常用于进行切换文件的位置 vim,常用于编辑软件系统相关的配置文件 ps –ef|grep jdk,常用语显示跟jdk有关的进程   |:表示 ...

  3. javascript实现checkbox提交submit请求

    javascript实现checkbox提交submit请求 背景:使用django模板中for来形成多个checkbox,需要点击单个checkbox并查询数据触发submit请求到后台,djang ...

  4. Mysql常用sql语句(20)- 子查询重点知识

    测试必备的Mysql常用sql语句系列 https://www.cnblogs.com/poloyy/category/1683347.html 子查询语句可以嵌套在 sql 语句中任何表达式出现的位 ...

  5. .NET Core接入ElasticSearch 7.5

    写在前面 最近一段时间,团队在升级ElasticSearch(以下简称ES),从ES 2.2升级到ES 7.5.也是这段时间,我从零开始,逐步的了解了ES,中间也踩了不少坑,所以特地梳理和总结一下相关 ...

  6. Python之sys.arg[]的用法解释

    转载自:https://www.cnblogs.com/liangmingshen/p/8906148.html sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个“外部”很关键,所以那 ...

  7. 笨办法学习python之hashmap

    #!/user/bin/env python #-*-coding:utf-8 -*- #Author: qinjiaxi #初始化aMap列表,把列表num_buckets添加到aMap中,num_ ...

  8. redis 主从哨兵02

    一.为什么要复制 1.实现数据的多副本存储,从而可以实现服务的高可用 2.提供更好的读性能,分担读请求 二.复制技术的关键点及难点 1.如何指定被复制对象 2.增量还是全量,以及如何实现增量 3.复制 ...

  9. jQuery根据元素值删除数组元素的方法

    http://www.jb51.net/article/68349.htm 本文实例讲述了jQuery根据元素值删除数组元素的方法.分享给大家供大家参考.具体如下: 例如删除C这个元素 ,前提不知道C ...

  10. Alink漫谈(四) : 模型的来龙去脉

    Alink漫谈(四) : 模型的来龙去脉 目录 Alink漫谈(四) : 模型的来龙去脉 0x00 摘要 0x01 模型 1.1 模型包含内容 1.2 Alink的模型文件 0x02 流程图 0x03 ...