CFS调度下带宽控制(Bandwidth Control)


前言

组调度(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的时间超过了限额值,该用户组内的任务将会受到限制,直到下一个周期。


提示:以下是本篇文章正文内容,下面案例可供参考

一、设计原理

先看一下/sys/fs/cgroup/cpu下的内容吧:
在这里插入图片描述
(1) 有两个关键的字段:cfs_period_us和cfs_quota_us,这两个与cfs_bandwidth息息相关;
(2) period表示周期,quota表示限额,也就是在period期间内,用户组的CPU限额为quota值,当超过这个值的时候,用户组将会被限制运行(throttle),等到下一个周期开始被解除限制(unthrottle);

如果使用CPU bandwith control,需要配置CONFIG_FAIR_GROUP_SCHED和CONFIG_CFS_BANDWIDTH选项。该功能是限制一个组的最大使用CPU带宽。通过设置两个变量quota和period,period是指一段周期时间,quota是指在period周期时间内,一个组可以使用的CPU时间限额。当一个组的进程运行时间超过quota后,就会被限制运行,这个动作被称作throttle。直到下一个period周期开始,这个组会被重新调度,这个过程称作unthrottle。

总结一下就是,cfs_bandwidth就像是一个全局时间池(时间池管理时间,类比内存池管理内存)。每个group cfs_rq如果想让其管理的红黑树上的调度实体调度,必须首先向全局时间池中申请固定的时间片,然后供其进程消耗。当时间片消耗完,继续从全局时间池中申请时间片。终有一刻,时间池中已经没有时间可供申请。此时就是throttle cfs_rq的大好时机。

二、数据结构

每个task_group都包含cfs_bandwidth结构体,主要记录和管理时间池的时间信息。

struct cfs_bandwidth {
    #ifdef CONFIG_CFS_BANDWIDTH
    raw_spinlock_t lock;
    ktime_t period;         //周期值;
    u64 quota, runtime;     //quota: 限额值;runtime: 记录限额剩余时间,在每次定时器回调函数中更新值为quota;
    s64 hierarchical_quota; //层级管理任务组的限额比率;
    u64 runtime_expires;    //每个周期的到期时间;

    int idle, period_active; //idle:空闲状态,不需要运行时分配;period_active: 周期性计时已经启动;
    struct hrtimer period_timer, slack_timer; //period_timer: 高精度周期性定时器,用于重新填充运行时间消耗;
    //slack_timer: 延迟定时器,在任务出列时,将剩余的运行时间返回到全局池里;
    struct list_head throttled_cfs_rq; //所有被throttle的cfs_rq挂入此链表,在定时器的回调函数中便利链表执行unthrottle cfs_rq操作;

    /* statistics */
    int nr_periods, nr_throttled; //统计值;
    u64 throttled_time; //统计值;
    #endif
};

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

struct cfs_rq {
#ifdef CONFIG_FAIR_GROUP_SCHED
	struct rq *rq;	              /* cfs_rq依附的cpu runqueue,每个CPU有且仅有一个rq运行队列。 */
	struct task_group *tg;        /* cfs_rq所属的task_group。 */
#ifdef CONFIG_CFS_BANDWIDTH
	int runtime_enabled;          /* 该就绪队列是否已经开启带宽限制,默认带宽限制是关闭的,如果带宽限制使能,runtime_enabled的值为1。 */
	u64 runtime_expires;			/* 周期计时器到期时间 */
	s64 runtime_remaining;        /* cfs_rq从全局时间池申请的时间片剩余时间,当剩余时间小于等于0的时候,就需要重新申请时间片。 */
 
	u64 throttled_clock, throttled_clock_task;     /* 当cfs_rq被throttle的时候,方便统计被throttle的时间,需要记录throttle开始的时间。 */
	u64 throttled_clock_task_time;
	int throttled, throttle_count;                 /* throttled:如果cfs_rq被throttle后,throttled变量置1,unthrottle的时候,throttled变量置0;throttle_count:由于task_group支持嵌套,当parent task_group的cfs_rq被throttle的时候,其chaild task_group对应的cfs_rq的throttle_count成员计数增加。 */
	struct list_head throttled_list;               /* 被throttle的cfs_rq挂入cfs_bandwidth->throttled_cfs_rq链表。 */
#endif /* CONFIG_CFS_BANDWIDTH */
#endif /* CONFIG_FAIR_GROUP_SCHED */
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值