本文主要是介绍CFS调度器(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
组调度
前面介绍到的CFS调度器都是以进程为单位进行的调度,实际应用场景中,用户可能会希望系统调度是基于用户组进行的。比如一个服务器上有两个用户同时使用,如果想要两个用户拥有相同的资源分配,那么就可以采用组调度方式。如果依然以进程为单位,那么假如一个用户拥有1个进程,而另一个用户拥有10个进程,这就导致了其中一个用户占用了大部分的CPU资源。
调度器都是基于调度实体sched_entity来作为调度的基本单位,这个实体可能代表的是一个进程,也可能代表着一个进程组。组调度的实现思想就是把一组进程当成一个进程或者说是一个调度实体来进行CPU资源的分配,这样CPU资源就不会因为组内进程数量多而获得更多CPU资源了。
组调度结构体
struct task_struct {
struct sched_entity se;
......
};
每个进程结构体中都定义了一个调度实体结构变量,用于系统调度使用,同样的对应的组调度结构体也会与调度实体相关联。我们在下面进行介绍。
/* task group related information */
struct task_group {struct cgroup_subsys_state css;#ifdef CONFIG_FAIR_GROUP_SCHED/* schedulable entities of this group on each cpu */struct sched_entity **se;/* runqueue "owned" by this group on each cpu */struct cfs_rq **cfs_rq;unsigned long shares;#ifdef CONFIG_SMPatomic_long_t load_avg;atomic_t runnable_avg;
#endif
#endif#ifdef CONFIG_RT_GROUP_SCHEDstruct sched_rt_entity **rt_se;struct rt_rq **rt_rq;struct rt_bandwidth rt_bandwidth;
#endifstruct rcu_head rcu;struct list_head list;struct task_group *parent;struct list_head siblings;struct list_head children;#ifdef CONFIG_SCHED_AUTOGROUPstruct autogroup *autogroup;
#endifstruct cfs_bandwidth cfs_bandwidth;
};
其中定义了 struct sched_entity **se;结构体指针数组,和struct rt_rq **rt_rq;结构体指针数组,数组的大小和CPU个数有关,之所以定义一个数组,是因为组调度相当于接管了该组中的进程的所有调度行为,所以它需要子runqueue来管理放在不同CPU上运行的进程,而实际运行则把sched_entity加入到真正的父runqueue。比如:系统中由8个CPU,那么组调度结构就要创建8个子runquque,8个sched_entity,每个子runqueue用来管理组内在不同CPU上运行的进程,每个sched_entity加入到不同的父runquque中,用来表示一个组。整个拓扑结构相当于级联的关系,这样虽然组中有很多个进程,但是实际上父runqueue中只存在一个sched_entity表示一组进程,这样资源分配时整个组就相当于一个进程来对待了,不会因为组内进程很多就划分更多资源了。
内核中定义的和组调度相关的API如下:
sched_create_group创建以及初始化一个组调度
cpu_cgroup_attach把进程加入到一个组调度
组调度总结
1.创建组调度结构时,为每个CPU创建组调度内部使用的cfs_rq运行队列。
2.组调度中的所有进程作为一个调度实体加入系统运行队列rq->cfs_rq。
3.进程加入组调度后,会脱离系统的rq->cfs_rq的管理,而是加入到组内的cfs_rq管理。
4.在选择下一个进程运行时,从rq->cfs_rq中如果选择到了一个组调度相关的调度实体se,那么需要继续遍历组内的cfs_rq,从组中选择一个进程运行。
这篇关于CFS调度器(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!