调度器统计
版本 15 的 schedstats 删除了一些 sched_yield 的计数器:yld_exp_empty、yld_act_empty 和 yld_both_empty。除此之外,它与版本 14 完全相同。
版本 14 的 schedstats 包括对 sched_domains 的支持,这在 2.6.20 的主线内核中实现,尽管它与内核 2.6.13-2.6.19 中的版本 12 的统计信息完全相同(版本 13 从未发布过内核)。一些计数器更适合每个运行队列,另一些适合每个域。请注意,域(及其相关信息)只对使用 CONFIG_SMP 的机器相关和可用。
在版本 14 的 schedstat 中,每个列出的 CPU 至少有一个域统计信息,可能会有多个域。在此实现中,域没有特定的名称,但通常编号最高的域会在机器上所有 CPU 之间进行平衡,而 domain0 是最专注的域,有时只在 CPU 对之间进行平衡。目前没有架构需要超过三个域级别。域统计信息中的第一个字段是一个位图,指示受该域影响的 CPU。
这些字段是计数器,只会递增。使用这些字段的程序需要从基线观察开始,然后计算每个后续观察中计数器的变化。一个 Perl 脚本可以对许多字段执行此操作,该脚本可在以下网址找到:
http://eaglet.pdxhosts.com/rick/linux/schedstat/
请注意,任何此类脚本必然是特定于版本的,因为更改版本的主要原因是输出格式的更改。对于希望编写自己脚本的人,这里描述了这些字段。
CPU 统计信息
cpu<N> 1 2 3 4 5 6 7 8 9
第一个字段是 sched_yield() 统计信息:
- 调用 sched_yield() 的次数
接下来的三个字段是 schedule() 统计信息:
- 这个字段是 O(1) 调度器中使用的遗留数组过期计数字段。我们保留它是为了 ABI 兼容性,但它总是被设置为零。
- 调用 schedule() 的次数
- schedule() 将处理器空闲的次数
接下来的两个字段是 try_to_wake_up() 统计信息:
- 调用 try_to_wake_up() 的次数
- 调用 try_to_wake_up() 唤醒本地 CPU 的次数
接下来的三个字段是描述调度延迟的统计信息:
- 该处理器上所有任务运行所花费的时间总和(以纳秒为单位)
- 该处理器上所有任务等待运行所花费的时间总和(以纳秒为单位)
- 在该 CPU 上运行的时间片数
域统计信息
对于描述的每个 CPU,每个域会产生一个这样的统计信息。(请注意,如果未定义 CONFIG_SMP,则不会使用任何域,并且这些行将不会出现在输出中。)
domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
第一个字段是一个位掩码,指示该域操作的 CPU。
接下来的 24 个字段是各种 load_balance() 统计信息,分为空闲(idle)、繁忙(busy)和新空闲(newly idle)的类型:
- 在该域中调用 load_balance() 时 CPU 空闲的次数
- 在该域中检查但发现负载不需要在 CPU 空闲时平衡的次数
- 在该域中尝试移动一个或多个任务但失败的 load_balance() 调用次数,当 CPU 空闲时
- 在该域中每次调用 load_balance() 时发现的不平衡总和(如果有的话),当 CPU 空闲时
- 在该域中调用 pull_task() 时 CPU 空闲的次数
- 在该域中即使在 CPU 空闲时也调用 pull_task(),因为目标任务在空闲时是缓存热的次数
- 在该域中调用 load_balance() 但在 CPU 空闲时未找到更繁忙的队列的次数
- 在该域中发现更繁忙的队列但未找到更繁忙的组的次数,当 CPU 空闲时
- 在该域中调用 load_balance() 时 CPU 繁忙的次数
- 在该域中检查但发现负载不需要在 CPU 繁忙时平衡的次数
- 在该域中尝试移动一个或多个任务但失败的 load_balance() 调用次数,当 CPU 繁忙时
- 在该域中每次调用 load_balance() 时发现的不平衡总和(如果有的话),当 CPU 繁忙时
- 在该域中调用 pull_task() 时 CPU 繁忙的次数
- 在该域中即使在 CPU 繁忙时也调用 pull_task(),因为目标任务在繁忙时是缓存热的次数
- 在该域中调用 load_balance() 但在 CPU 繁忙时未找到更繁忙的队列的次数
- 在该域中发现更繁忙的队列但未找到更繁忙的组的次数,当 CPU 繁忙时
- 在该域中调用 load_balance() 但在 CPU 刚刚变为空闲时未找到更繁忙的队列的次数
- 在该域中检查但发现负载不需要在 CPU 刚刚变为空闲时平衡的次数
- 在该域中尝试移动一个或多个任务但失败的 load_balance() 调用次数,当 CPU 刚刚变为空闲时
- 在该域中每次调用 load_balance() 时发现的不平衡总和(如果有的话),当 CPU 刚刚变为空闲时
- 在该域中调用 pull_task() 时 CPU 刚刚变为空闲的次数
- 在该域中即使在 CPU 刚刚变为空闲时也调用 pull_task(),因为目标任务在刚刚变为空闲时是缓存热的次数
- 在该域中调用 load_balance() 但在 CPU 刚刚变为空闲时未找到更繁忙的队列的次数
- 在该域中发现更繁忙的队列但未找到更繁忙的组的次数,当 CPU 刚刚变为空闲时
接下来的三个字段是 active_load_balance() 统计信息:
- 调用 active_load_balance() 的次数
- 尝试移动任务但失败的 active_load_balance() 的次数
- 成功移动任务的 active_load_balance() 的次数
接下来的三个字段是 sched_balance_exec() 统计信息:
- sbe_cnt 未使用
- sbe_balanced 未使用
- sbe_pushed 未使用
接下来的三个字段是 sched_balance_fork() 统计信息:
- sbf_cnt 未使用
- sbf_balanced 未使用
- sbf_pushed 未使用
接下来的三个字段是 try_to_wake_up() 统计信息:
- 在该域中调用 try_to_wake_up() 唤醒上次在该域中的不同 CPU 上运行的任务的次数
- 在该域中调用 try_to_wake_up() 将任务移动到唤醒 CPU,因为它在自己的 CPU 上无论如何都是缓存冷的次数
- 在该域中调用 try_to_wake_up() 开始被动平衡的次数
/proc/<pid>/schedstat
schedstats 还添加了一个新的 /proc/<pid>/schedstat
文件,以在每个进程级别上包含一些相同的信息。该文件中有三个字段,与该进程相关联:
- 在 CPU 上花费的时间(以纳秒为单位)
- 在运行队列上等待的时间(以纳秒为单位)
- 在该 CPU 上运行的时间片数
可以轻松编写一个程序来利用这些额外字段,以报告特定进程或一组进程在调度器策略下的表现如何。这样的程序的简单版本可在以下网址找到:
http://eaglet.pdxhosts.com/rick/linux/schedstat/v12/latency.c