暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

聊聊Linux内核进程调度下篇

428


作者时间QQ技术交流群
perrynzhou@gmail.com2022/05/22672152841




进程优先级



  • Linux内核中进程优先级一般分为动态优先级和静态优先级,动态优先级是内核根据进程的nice值、IO密集行为或者计算密集行为以及等待时间等因素,设置给普通的进程;静态优先级是用户态应用设置给实时进程。在调度中静态优先级的进程优先级更高。



  • 一般应用分为IO密集型和计算密集型;I/O密集型
    是进程执行I/O操作时候等待资源或者事件时候,数据读取到后恢复进程的运行,这样基本出于等待IO和运行之间进行交替,由于具有这样的特性,进程调度器通常会将短的CPU时间片分配给I/O密集型进程。计算密集型
    是进程保持在CPU时间片上,需要最大限度的利用处理器的计算能力。任何普通进程
    的nice值在-20~19
    之间,0
    是默认,较高的nice值表示较低的进程优先级;实时进程
    的优先级范围是在0~99

  • 从内核的优先级角度,所有的进程都处于0~139
    ,其中的0~99
    是分配实时进程;100~139
    是分配普通进程,代表的nice值为-20~19
    .


实际调度器




调度器通用元素


CFS(完全公平)调度器

  • Linux内核中所有动态优先级的进程都是有CFS
    调度器处理,通常Linux内核中大部分都是非实时进程,所以CFS
    进程调度器也是最繁忙的调度器。CFS
    调度器不依赖于传统的时间片来分配CPU的时间,而是通过虚拟时间,这个虚拟时间是进程获取CPU时间的时间单位。CFS
    调度器根据虚拟时间值,CFS
    决定进程的最终运行时间,同时也会涉及使用nice来衡量一个进程和其他进程的竞争关系。

  • 优先级是根据进程等待时间、进程运行时间、进程的历史行为、进程的nice值等因素动态设置。在计算进程优先级的时候,CFS
    不仅依赖于进程的nice值,同时还要考虑进程的负载,内核中维护了进程的负载权重数组(prio_to_weight
    ),每个nice值对应一个负载权重;对于进程来说,nice值减一,CPU时间片就会减少10%;nice值加一,CPU时间片会增加10%。

  • CFS
    调度器采用了红黑树来作为运行队列,红黑树保存了所有的竞争进程,根据红黑树的特性,执行插入和搜索效率非常高。高优先级的进程在树的最左边节点,通过pick_next_task()
    从红黑树中选择最左边的节点来进行调度。


// CFS完全公平调度器
const struct sched_class fair_sched_class = {
.next = &idle_sched_class,
.enqueue_task = enqueue_task_fair,
.dequeue_task = dequeue_task_fair,
.yield_task = yield_task_fair,
.yield_to_task = yield_to_task_fair,

.check_preempt_curr = check_preempt_wakeup,

.pick_next_task = pick_next_task_fair,
.put_prev_task = put_prev_task_fair,

#ifdef CONFIG_SMP
.select_task_rq = select_task_rq_fair,
.migrate_task_rq = migrate_task_rq_fair,

.rq_online = rq_online_fair,
.rq_offline = rq_offline_fair,

.task_dead = task_dead_fair,
.set_cpus_allowed = set_cpus_allowed_common,
#endif

.set_curr_task = set_curr_task_fair,
.task_tick = task_tick_fair,
.task_fork = task_fork_fair,

.prio_changed = prio_changed_fair,
.switched_from = switched_from_fair,
.switched_to = switched_to_fair,

.get_rr_interval = get_rr_interval_fair,

.update_curr = update_curr_fair,

#ifdef CONFIG_FAIR_GROUP_SCHED
.task_change_group = task_change_group_fair,
#endif
};


实时调度器

  • Linux内核中支持实时进程,它们是由实时调度器来进行调度。rt进程
    被分配了静态优先级,并且在内核中保持不变。于CFS
    不同,实时调度器
    采用了每个优先级1~99
    的单链表,并非采红黑树作为运行队列。实时调度器
    采用了fifo
    rr
    调度策略.

  • fifo
    调度策略采用先进先出的方法来调度实时进程。在该策略下进程是没有任何时间片下运行的,一直在运行。当调度器遇到优先级更高的可执行的fifo
    rr
    deadline
    任务时候,fifo
    进程会被抢占;

  • rr
    调度策略是采用轮询的方法来调度实时进程,这个策略和fifo
    类型类似,不同的是rr
    调度策略是给进程分配了时间片来运行。进程的时间片过期后,进程会被添加到链表的尾部,具有相同优先级的进程会以轮询的方式运行,直到高优先级进程抢占。


// fifo和rt的实时进程调度器
const struct sched_class rt_sched_class = {
.next = &fair_sched_class,
.enqueue_task = enqueue_task_rt,
.dequeue_task = dequeue_task_rt,
.yield_task = yield_task_rt,

.check_preempt_curr = check_preempt_curr_rt,

.pick_next_task = pick_next_task_rt,
.put_prev_task = put_prev_task_rt,

#ifdef CONFIG_SMP
.select_task_rq = select_task_rq_rt,

.set_cpus_allowed = set_cpus_allowed_common,
.rq_online = rq_online_rt,
.rq_offline = rq_offline_rt,
.task_woken = task_woken_rt,
.switched_from = switched_from_rt,
#endif

.set_curr_task = set_curr_task_rt,
.task_tick = task_tick_rt,

.get_rr_interval = get_rr_interval_rt,

.prio_changed = prio_changed_rt,
.switched_to = switched_to_rt,

.update_curr = update_curr_rt,
};

  • deadline
    调度策略,在Linux内核的3.14开始引入了,deadline
    调度器基于全局最早的截止期优先和固定带宽服务器算法,于预先确定其运行时的需求。一个进程内运行多个任务,每个任务都会有一个截止期(在截止期内必须完成执行)和一个计算时间,该时间定义ICPU完成进程执行所需要的时间。


// 实时进程的新的调度器deadline
const struct sched_class dl_sched_class = {
.next = &rt_sched_class,
.enqueue_task = enqueue_task_dl,
.dequeue_task = dequeue_task_dl,
.yield_task = yield_task_dl,

.check_preempt_curr = check_preempt_curr_dl,

.pick_next_task = pick_next_task_dl,
.put_prev_task = put_prev_task_dl,

#ifdef CONFIG_SMP
.select_task_rq = select_task_rq_dl,
.migrate_task_rq = migrate_task_rq_dl,
.set_cpus_allowed = set_cpus_allowed_dl,
.rq_online = rq_online_dl,
.rq_offline = rq_offline_dl,
.task_woken = task_woken_dl,
#endif

.set_curr_task = set_curr_task_dl,
.task_tick = task_tick_dl,
.task_fork = task_fork_dl,

.prio_changed = prio_changed_dl,
.switched_from = switched_from_dl,
.switched_to = switched_to_dl,

.update_curr = update_curr_dl,
};



文章转载自存储内核技术交流,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论