首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用完全公平调度程序(CFS)进行多任务处理(3)CFS 工作原理

使用完全公平调度程序(CFS)进行多任务处理(3)CFS 工作原理

CFS 调度程序使用安抚(appeasement)策略确保公平性。当某个任务进入运行队列后,将记录当前时间,当某个进程等待 CPU 时,将对这个进程的 wait_runtime 值加一个数,这个数取决于运行队列当前的进程数。当执行这些计算时,也将考虑不同任务的优先级值。                                                          将这个任务调度到 CPU 后,它的 wait_runtime 值开始递减,当这个值递减到其他任务成为红黑树的最左侧任务时,当前任务将被抢占。通过这种方式,CFS 努力实现一种理想 状态,即 wait_runtime 值为 0!
CFS 维护任务运行时(相对于运行队列级时钟,称为 fair_clock(cfs_rq->fair_clock)),它在某个实际时间的片段内运行,因此,对于单个任务可以按照理想的速度运行。  
粒度和延迟如何关联?关联粒度和延迟的简单等式为:

gran = (lat/nr) - (lat/nr/nr)
其中 gran = 粒度,
lat = 延迟,而
nr = 运行中的任务数。

例如,如果具有 4 个可运行的任务,那么 fair_clock 将按照实际时间速度的四分之一增加。每个任务将设法跟上这个速度。这是由分时多任务处理的量子化特性决定的。也就是说,在任何一个时间段内只有一个任务可以运行;因此,其他进程在时间上的拖欠将增大(wait_runtime)。因此,一旦某个任务进入调度,它将努力赶上它所欠下的时间(并且要比所欠时间多一点,因为在追赶时间期间,fair_clock 不会停止计时)。
加权任务引入了优先级。假设我们有两个任务:其中一个任务占用 CPU 的时间量是另一个任务的两倍,比例为 2:1。执行数学转换后,对于权重为 0.5 的任务,时间流逝的速度是以前的两倍。
我们根据 fair_clock 对树进行排队。
请注意,CFS 没有使用时间片(time slices),至少,没有优先使用。CFS 中的时间片具有可变的长度并且动态确定。
对于负载平衡程序,调度模块实现了迭代器,使用它遍历由调度模块管理的所有任务,从而进行负载平衡。  
运行时调优选项 引入了重要的 sysctls 来在运行时对调度程序进行调优(以 ns 结尾的名称以纳秒为单位):
  • sched_latency_ns:针对 CPU 密集型任务进行目标抢占延迟(Targeted preemption latency)。
  • sched_batch_wakeup_granularity_ns:针对 SCHED_BATCH 的唤醒(Wake-up)粒度。
  • sched_wakeup_granularity_ns:针对 SCHED_OTHER 的唤醒粒度。
  • sched_compat_yield:由于 CFS 进行了改动,严重依赖 sched_yield() 的行为的应用程序可以要求不同的性能,因此推荐启用 sysctls。
  • sched_child_runs_first:child 在 fork 之后进行调度;此为默认设置。如果设置为 0,那么先调度 parent。
  • sched_min_granularity_ns:针对 CPU 密集型任务执行最低级别抢占粒度。
  • sched_features:包含各种与调试相关的特性的信息。
  • sched_stat_granularity_ns:收集调度程序统计信息的粒度。
下面是系统中运行时参数的典型值:  
清单 5. 典型的运行时参数值
1
2
3
4
5
6
7
8
9
10
11
[root@dodge ~]# sysctl -A|grep "sched" | grep -v "domain"
kernel.sched_min_granularity_ns = 4000000
kernel.sched_latency_ns = 40000000
kernel.sched_wakeup_granularity_ns = 2000000
kernel.sched_batch_wakeup_granularity_ns = 25000000
kernel.sched_stat_granularity_ns = 0
kernel.sched_runtime_limit_ns = 40000000
kernel.sched_child_runs_first = 1
kernel.sched_features = 29
kernel.sched_compat_yield = 0
[root@dodge ~]#




新的调度程序调试接口  新调度程序附带了一个非常棒的调试接口,还提供了运行时统计信息,分别在 kernel/sched_debug.c 和        kernel/sched_stats.h 中实现。要提供调度程序的运行时信息和调试信息,需要将一些文件添加到 proc pseudo 文件系统:
  • /proc/sched_debug:显示运行时调度程序可调优选项的当前值、CFS 统计信息和所有可用 CPU 的运行队列信息。当读取这个 proc 文件时,将调用 sched_debug_show() 函数并在 sched_debug.c 中定义。
  • /proc/schedstat:为所有相关的 CPU 显示特定于运行队列的统计信息以及 SMP 系统中特定于域的统计信息。kernel/sched_stats.h 中定义的 show_schedstat() 函数将处理 proc 条目中的读操作。
  • /proc/[PID]/sched:显示与相关调度实体有关的信息。在读取这个文件时,将调用 kernel/sched_debug.c 中定义的 proc_sched_show_task() 函数
返回列表