首页 > 系统相关 >Linux进程调度-组调度及带宽控制

Linux进程调度-组调度及带宽控制

时间:2023-05-19 18:34:06浏览次数:37  
标签:task group rq 调度 带宽 Linux runtime cfs

1. 概述

组调度(task_group)是使用Linux cgroup(control group)的cpu子系统来实现的,可以将进程进行分组,按组来分配CPU资源等。

比如,看一个实际的例子:

A和B两个用户使用同一台机器,A用户16个进程,B用户2个进程,如果按照进程的个数来分配CPU资源,显然A用户会占据大量的CPU时间,这对于B用户是不公平的。组调度就可以解决这个问题,分别将A、B用户进程划分成组,并将两组的权重设置成占比50%即可。

带宽(bandwidth)控制,是用于控制用户组(task_group)的CPU带宽,通过设置每个用户组的限额值,可以调整CPU的调度分配。在给定周期内,当用户组消耗CPU的时间超过了限额值,该用户组内的任务将会受到限制。

由于组调度和带宽控制紧密联系,因此本文将探讨这两个主题,本文的讨论都基于CFS调度器,开始吧。

2. task_group

  • 组调度,在内核中是通过struct task_group来组织的,task_group本身支持cfs组调度和rt组调度,本文主要分析cfs组调度。

  • CFS调度器管理的是sched_entity调度实体,task_struct(代表进程)和task_group(代表进程组)中分别包含sched_entity,进而来参与调度;

关于组调度的相关数据结构,组织如下:

  • 内核维护了一个全局链表task_groups,创建的task_group会添加到这个链表中;

  • 内核定义了root_task_group全局结构,充当task_group的根节点,以它为根构建树状结构;

  • struct task_group的子节点,会加入到父节点的siblings链表中;

  • 每个struct task_group会分配运行队列数组和调度实体数组(以CFS为例,RT调度类似),其中数组的个数为系统CPU的个数,也就是为每个CPU都分配了运行队列和调度实体;

对应到实际的运行中,如下:

  • struct cfs_rq包含了红黑树结构,sched_entity调度实体参与调度时,都会挂入到红黑树中,task_struct和task_group都属于被调度对象;

  • task_group会为每个CPU再维护一个cfs_rq,这个cfs_rq用于组织挂在这个任务组上的任务以及子任务组,参考图中的Group A;

  • 调度器在调度的时候,比如调用pick_next_task_fair时,会从遍历队列,选择sched_entity,如果发现sched_entity对应的是task_group,则会继续往下选择;

  • 由于sched_entity结构中存在parent指针,指向它的父结构,因此,系统的运行也能从下而上的进行遍历操作,通常使用函数walk_tg_tree_from进行遍历;

2.2 task_group权重

  • 进程或进程组都有权重的概念,调度器会根据权重来分配CPU的时间。

  • 进程组的权重设置,可以通过/sys文件系统进行设置,比如操作/sys/fs/cgoup/cpu/A/shares

调用流程如下图:

  • sched_group_set_shares来完成最终的设置;

  • task_group为每个CPU都分配了一个sched_entity,针对当前sched_entity设置更新完后,往上对sched_entity->parent设置更新,直到根节点;

  • shares的值计算与load相关,因此也需要调用update_load_avg进行更新计算;

看一下实际的效果图吧:

  • 写节点操作可以通过echo XXX > /sys/fs/cgroup/cpu/A/B/cpu.shares;

  • 橙色的线代表传入参数指向的对象;

  • 紫色的线代表每次更新涉及到的对象,包括三个部分;

  • 处理完sched_entity后,继续按同样的流程处理sched_entity->parent

3. cfs_bandwidth

先看一下/sys/fs/cgroup/cpu下的内容吧:

  • 有两个关键的字段:cfs_period_us和cfs_quota_us,这两个与cfs_bandwidth息息相关;

  • period表示周期,quota表示限额,也就是在period期间内,用户组的CPU限额为quota值,当超过这个值的时候,用户组将会被限制运行(throttle),等到下一个周期开始被解除限制(unthrottle);

来一张图直观理解一下:

  • 在每个周期内限制在quota的配额下,超过了就throttle,下一个周期重新开始;

3.1 数据结构

内核中使用struct cfs_bandwidth来描述带宽,该结构包含在struct task_group中。

此外,struct cfs_rq中也有与带宽控制相关的字段。

还是来看一下代码吧:


struct cfs_bandwidth {

#ifdef CONFIG_CFS_BANDWIDTH

	raw_spinlock_t lock;

	ktime_t period;

	u64 quota, runtime;

	s64 hierarchical_quota;

	u64 runtime_expires;

 

	int idle, period_active;

	struct hrtimer period_timer, slack_timer;

	struct list_head throttled_cfs_rq;

 

	/* statistics */

	int nr_periods, nr_throttled;

	u64 throttled_time;

#endif

};

  • period:周期值;

  • quota:限额值;

  • runtime:记录限额剩余时间,会使用quota值来周期性赋值;

  • hierarchical_quota:层级管理任务组的限额比率;

  • runtime_expires:每个周期的到期时间;

  • idle:空闲状态,不需要运行时分配;

  • period_active:周期性计时已经启动;

  • period_timer:高精度周期性定时器,用于重新填充运行时间消耗;

  • slack_timer:延迟定时器,在任务出列时,将剩余的运行时间返回到全局池里;

  • throttled_cfs_rq:限流运行队列列表;

  • nr_periods/nr_throttled/throttled_time:统计值;

struct cfs_rq结构中相关字段如下:


struct cfs_rq {

...

#ifdef CONFIG_CFS_BANDWIDTH

	int runtime_enabled;

	u64 runtime_expires;

	s64 runtime_remaining;

 

	u64 throttled_clock, throttled_clock_task;

	u64 throttled_clock_task_time;

	int throttled, throttle_count;

	struct list_head throttled_list;

#endif /* CONFIG_CFS_BANDWIDTH */

...

}

  • runtime_enabled:周期计时器使能;

  • runtime_expires:周期计时器到期时间;

  • runtime_remaining:剩余的运行时间;

3.2 流程分析

3.2.1 初始化流程

先看一下初始化的操作,初始化函数init_cfs_bandwidth本身比较简单,完成的工作就是将struct cfs_bandwidth结构体进程初始化。

  • 注册两个高精度定时器:period_timer和slack_timer;

  • period_timer定时器,用于在时间到期时重新填充关联的任务组的限额,并在适当的时候unthrottlecfs运行队列;

    slack_timer定时器,slack_period周期默认为5ms,在该定时器函数中也会调用distribute_cfs_runtime从全局运行时间中分配runtime;

  • start_cfs_bandwidth和start_cfs_slack_bandwidth分别用于启动定时器运行,其中可以看出在dequeue_entity的时候会去利用slack_timer,将运行队列的剩余时间返回给tg->cfs_b这个runtime pool;

  • unthrottle_cfs_rq函数,会将throttled_list中的对应cfs_rq删除,并且从下往上遍历任务组,针对每个任务组调用tg_unthrottle_up处理,最后也会根据cfs_rq对应的sched_entity从下往上遍历处理,如果sched_entity不在运行队列上,那就重新enqueue_entity以便参与调度运行,这个也就完成了解除限制的操作;

do_sched_cfs_period_timer函数与do_sched_cfs_slack_timer()函数都调用了distrbute_cfs_runtime(),该函数用于分发tg->cfs_b的全局运行时间runtime,用于在该task_group中平衡各个CPU上的cfs_rq的运行时间runtime,来一张示意图:

  • 系统中两个CPU,因此task_group针对每个cpu都维护了一个cfs_rq,这些cfs_rq来共享该task_group的限额运行时间;

  • CPU0上的运行时间,浅黄色模块表示超额了,那么在下一个周期的定时器点上会进行弥补处理;

3.2.2 用户设置流程

用户可以通过操作/sys中的节点来进行设置:

  • 操作/sys/fs/cgroup/cpu/下的cfs_quota_us/cfs_period_us节点,最终会调用到tg_set_cfs_bandwidth函数tg_set_cfs_bandwidth会从root_task_group根节点开始,遍历组调度树,并逐个设置限额比率 ;

  • 更新cfs_bandwidth的runtime信息;

  • 如果使能了cfs_bandwidth功能,则启动带宽定时器;

  • 遍历task_group中的每个cfs_rq队列,设置runtime_remaining值,如果cfs_rq队列限流了,则需要进行解除限流操作;

3.2.3 throttle限流操作

cfs_rq运行队列被限制,是在throttle_cfs_rq函数中实现的,其中调用关系如下图:

  • 调度实体sched_entity入列时,进行检测是否运行时间已经达到限额,达到则进行限制处理;

  • pick_next_task_fair/put_prev_task_fair在选择任务调度时,也需要进行检测判断;

3.2.4 总结

总体来说,带宽控制的原理就是通过task_group中的cfs_bandwidth来管理一个全局的时间池,分配给属于这个任务组的运行队列,当超过限额的时候则限制队列的调度。同时,cfs_bandwidth维护两个定时器,一个用于周期性的填充限额并进行时间分发处理,一个用于将未用完的时间再返回到时间池中,大抵如此。

标签:task,group,rq,调度,带宽,Linux,runtime,cfs
From: https://www.cnblogs.com/linhaostudy/p/17416002.html

相关文章

  • linux中使用jenkins自动部署前端工程
    1、去年在自己的服务器上安装了jenkins,说用来自己研究一下jenkins自动化部署前端项目,jenkins安装好了,可是一直没管,最近终于研究了一下使用jenkins自动化部署,以此记录下来。一、jenkins的安装由于安装已经过去大半年时间了,具体步骤没有记录,可以到网上自行百度。大致流程:1、安装......
  • Linux基础22 进程的优先级nice, 后台进程管理, 系统平均负载, 系统启动流程
    进程的优先级:nice值越高:表示优先级越低,例如19,该进程容易将CPU使用量让给其他进程。nice值越低:表示优先级越高,例如-20,该进程更不倾向于让出CPU。#以设定的优先级启动nice-n-10tail-f/var/log/messages#重新设置一个进程的优先级(调整sshd的优先级)[root@oldboyedu~]#......
  • disk-linux磁盘问题 unexpected output in sfdisk
    linux-disk磁盘问题unexpectedoutputinsfdisk问题:运行growpart/dev/vda1unexpectedoutputinsfdisk--version[sfdisk,来自util-linux2.23.2]解决方案:#运行以下命令切换ECS实例的字符编码类型,可能需要重启LANG=en_US.UTF-8#如果重启ECS实例后仍未......
  • Linux防止误删文件rm命令删除文件到回收站
    全局配置:/etc/profile当前用户:~/.bashrc 一、配置:方式一:1.建立一个存放rm后的目录: sudomkdir/Recycle_Bin注意:目录名、目录路径都可以随意,就是注意目录所在磁盘的空间即可 2.根据需要全局配置或局部配置 里,添加rm 删除文件到回收站aliasrm='mv......
  • 【Linux】详解六种配置Linux环境变量的方法(以centos为例)
    本文时间2023-05-19作者:sugerqube漆瓷本文重理解,!!忽略环境变量加载原理!!本文目标:理解六大环境变量配置,选择合适的配置文件进行配置配置环境的理由以shell编程为例现在我们想要运行名为"sugerqube.sh"的脚本需要运行的命令是./sugerqube.sh即在命令行输入脚本的地址注:.......
  • linux 添加系统服务(zookeeper举例)
    zookeeper添加系统服务1、vi /etc/systemd/system/zookeeper.service 添加服务[Unit]Description=zookeeperAfter=network.target[Service]Type=forkingEnvironment=JAVA_HOME=/var/local/jdk1.8.0_371ExecStart=/data/apache-zookeeper-3.7.1-bin/bin/zkServer.shs......
  • linux 各种trace工具
    1、bpf2、bpftrace3、strace  可以查看进程程序的IO调用情况,比如进程有哪些IO调用,花费了多长时间等等。可以定位进程慢、驱动慢等问题   Outputformat:      -acolumnalignmentCOLUMNforprintingsyscallresults(default40)   ......
  • linux(RK3308)添加CH9434(SPI串口扩展)驱动
    linux(RK3308)添加CH9434(SPI串口扩展)驱动1、CH9434驱动下载https://www.wch.cn/downloads/CH9434EVT_ZIP.html2、驱动移植2.1、移植准备1、查看系统是否支持DTS设备树支持,若支持DTS可以直接在DTS文件中定义SPI节点。如下所示:&spi2{status="okay";max-freq=<500......
  • linux开机自启动设置
    https://blog.csdn.net/WUFUSHANLI/article/details/124419411?ops_request_misc=&request_id=&biz_id=102&utm_term=linux%E8%AE%BE%E7%BD%AEredis%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF%E5%8A%A8&utm_medium=distribute.pc_search_result.none-task-blog-2~......
  • 分布式系统关键技术:流量与数据调度
    1、流量调度与服务治理的关系服务治理时内部系统的事,流量调度可以是内部的,更是外部接入层的事。服务治理时数据中心的事,而流量调度要做的好,应该是数据中心之外的事,也就是我们常说的边缘计算或者CDN。 2、流量调度的主要功能和关键技术流量调度系统应该主要具备的功能:依据系......