现在的位置: 首页 > 操作系统 > 正文

linux调度器(十)——调度器/proc信息解读

2018年04月16日 操作系统 ⁄ 共 11995字 ⁄ 字号 评论关闭

注下面的时间或时刻都是从rq->clock中获得的,而这个值是由update_rq_clock底层cpu来更新的。并且很多信息是需要内核配置CONFIG_SCHEDSTATS才有。
/proc/<pid>/sched

$cat /proc/28733/sched    

cpu_test (28733, #threads: 1)

---------------------------------------------------------

se.exec_start       :    2781299327.397282  //此进程最近被调度到的开始执行时刻(这个值是每次update_curr都进行更新)

se.vruntime        :       3144603.079903  //虚拟运行时间

se.sum_exec_runtime:       2843625.998498  //累计运行的物理时间时间

se.wait_start       :             0.000000  //最近一次当前进程被入队的时刻

se.sleep_start      :             0.000000  //此进程最近一次被从队列里取出,并被置S状态的时刻

se.block_start      :             0.000000  //此进程最近一次被从队列里取出,并被置D状态的时刻

se.sleep_max      :             0.000000  //最长处于S状态时间

se.block_max      :             0.000000  //最长处于D状态时间

se.exec_max       :             1.004266  //最长单次执行时间

se.slice_max       :           998.456300  //曾经获得时间片的最长时间

se.wait_max       :             0.455235  //最长在就绪队列里的等待时间

se.wait_sum       :            15.615407  //累计在就绪队列里的等待时间

se.wait_count      :                 3147  //累计等待次数

se.iowait_sum      :           215.825267  //io等待时间

se.iowait_count     :                   67 //io等待次数  io_schedule调用次数

sched_info.bkl_count:                    0  //此进程大内核锁调用次数

se.nr_migrations    :                    0 //需要迁移当前进程到其他cpu时累加此字段

se.nr_migrations_cold:                    0

se.nr_failed_migrations_affine:           194  //进程设置了cpu亲和,进程迁移时检查失败的次数

se.nr_failed_migrations_running:           0 

se.nr_failed_migrations_hot:               0  //当前进程因为是cache hot导致迁移失败的次数

se.nr_forced_migrations :                  0  //在当前进程cache hot下,由于负载均衡尝试多次失败,强行进行迁移的次数

se.nr_wakeups         :                 0  //被唤醒的累计次数(从不可运行到可运行)

se.nr_wakeups_sync     :                0  //同步唤醒次数,即a唤醒b,a立刻睡眠,b被唤醒的次数

se.nr_wakeups_migrate  :                 0 //被唤醒得到调度的当前cpu,不是之前睡眠的cpu的次数

se.nr_wakeups_local     :                0 //被本地唤醒的次数(唤醒后在当前cpu上执行)

se.nr_wakeups_remote   :                0 //非本地唤醒累计次数

se.nr_wakeups_affine    :                0 //考虑了任务的cache亲和性的唤醒次数

se.nr_wakeups_affine_attempts:            0

se.nr_wakeups_passive  :                    0

se.nr_wakeups_idle     :                    0

avg_atom            :           903.886204 //本进程平均耗时sum_exec_runtime/ nr_switches

avg_per_cpu           :             0.000001

nr_switches            :                 3146 //主动切换和被动切换的累计次数

nr_voluntary_switches   :                    0 //主动切换次数(由于prev->state为不可运行状态引起的切换)

nr_involuntary_switches  :                 3146 //被动切换次数

se.load.weight          :                 1024  //seload

policy                 :                    0  //调度策略 normal

prio                   :                  120  //优先级(nice=0)

clock-delta             :                   51

大多数字段的计算在sched.c及sched_fair.c里,在这两个文件里搜索相应的字段就能得到相应的计算方法。

/proc/<pid>/schedstat

$cat /proc/28733/schedstat

5726055470233 30451531 6336
First: time spent on the cpu, task->se.sum_exec_runtime,这个值与上面的se.sum_exec_runtime一样只是上面的除于1,000,000
Second:time spent waiting on a runqueue,这个值与上面的se.wait_sum一样
Third: of times run on this cpu, task->sched_info.pcount,这个值跟上面的se->nr_switches一样

该信息的入口在fs/proc/base.c的proc_pid_schedstat函数里。

/proc/<pid>/status

$cat /proc/28733/status

Name:   cpu_test

State:  R (running)

Tgid:   28733

Pid:    28733

PPid:   5573

TracerPid:      0

Uid:    52170   52170   52170   52170 // uid euid suid fsuid

Gid:    100     100     100     100  // gid egid sgid fsgid

Utrace: 0

FDSize: 256

Groups: 100 19051 //启动该进程的用户所属的组的id,并不是组调度的组

VmPeak:     3976 kB

VmSize:     3912 kB //任务虚拟地址空间的大小 (total_vm-reserved_vm),其中total_vm为进程的地址空间的大小,reserved_vm:进程在预留或特殊的内存间的物理页,该值也是top的VIRT字段

VmLck:         0 kB //任务已经锁住的物理内存的大小。锁住的物理内存不能交换到硬盘 (locked_vm)

VmHWM:       328 kB  //文件内存映射和匿名内存映射的大小

VmRSS:       328 kB //应用程序正在使用的物理内存的大小,就是用top的res字段

VmData:       44 kB //程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据; (total_vm-shared_vm-stack_vm)

VmStk:        88 kB //任务在用户态的栈的大小 (stack_vm)

VmExe:         4 kB //程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 (end_code-start_code)

VmLib:      1700 kB //被映像到任务的虚拟内存空间的库的大小 (exec_lib)

VmPTE:        32 kB //该进程的所有页表的大小,单位:kb

VmSwap:        0 kB

Threads:        1  //线程数

SigQ:   1/193060  //待处理信号的个数

SigPnd: 0000000000000000  //屏蔽位,存储了该线程的待处理信号

ShdPnd: 0000000000000000  //屏蔽位,存储了该线程组的待处理信号

SigBlk: 0000000000000000  //存放被阻塞的信号

SigIgn: 0000000000000000  //存放被忽略的信号

SigCgt: 0000000000000000  //存放被捕捉到的信号

CapInh: 0000000000000000

CapPrm: 0000000000000000

CapEff: 0000000000000000

CapBnd: ffffffffffffffff

Cpus_allowed:   000008  //可以使用的cpu bit

Cpus_allowed_list:      3 //可以使用的cpu id list

Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001  //可使用的mem

Mems_allowed_list:      0  //可使用的mem list

voluntary_ctxt_switches:        0   //主动的切换

nonvoluntary_ctxt_switches:     8310  //被动的切换

入口在fs/proc/array.c的proc_pid_status函数里,参考http://www.kerneltravel.net/?p=294

/proc/<pid>/stat

在内核中,该文件的内容由do_task_stat函数(fs/proc/array.c)写。主要操作是

28733 (cpu_test) R 5573 28733
5573 34824 5573 4202496 176
0 0 0 1797172 80 0 20 0 10 278275036400588882
184467440737095516154194304 4195884 140733625322688 140733625322136 41954610 0 0 0 00 0 17 3 00 0 0 0

         seq_printf(m, "%d (%s) %c %d %d%d %d %d %u %lu \

%lu %lu %lu %lu %lu
%ld %ld %ld %ld %d
0 %llu %lu %ld %lu
%lu %lu %lu %lu \

%lu %lu %lu %lu %lu %lu%lu %lu %d %d %u%u %llu %lu %ld\n",

                   1 .pid_nr_ns(pid, ns), //pid

                   2 .tcomm, //进程名

                   3 .state, //进程状态

                   4 .ppid, //父进程号

                   5 .pgid, //线程组ID

                   6 .sid, //会话组ID

                   7 .tty_nr, //该进程的tty终端的设备号,INT34817/256=主设备号,(34817-主设备号)=次设备号

                   8 .tty_pgrp, //终端的进程组号,当前运行在该进程所在终端的前台进程(包括shell应用程序)PID

                   9 .task->flags, //进程标志位,查看该进程的特性(定义在/include/kernel/sched.h)

                   10.min_flt, //累计进程的次缺页数(Copy on Write页和匿名页)

                   11.cmin_flt, //该进程所有的子进程发生的次缺页的次数

                   12.maj_flt, //主缺页数(从映射文件或交换设备读入的页面数)

                   13.cmaj_flt, //该进程所有的子进程发生的主缺页的次数

                   14.cputime_to_clock_t(utime), //该进程在用户态运行的时间,单位为jiffies

                   15.cputime_to_clock_t(stime), //该进程在核心态运行的时间,单位为jiffies

                   16.cputime_to_clock_t(cutime), //该进程所有的子进程在用户态运行的时间总和,单位为jiffies

                   17.cputime_to_clock_t(cstime), //该进程所有的子进程在内核态运行的时间的总和,单位为jiffies

                   18.priority, //进程的优先级

                   19.nice, //进程的静态优先级

                   20.num_threads, //该进程所在的线程组里线程的个数

        21.//0

                   22.start_time, //该进程创建的时间

                   23.vsize, //该进程的虚拟地址空间大小

                   24.mm ? get_mm_rss(mm) : 0, //该进程当前驻留物理地址空间的大小

                   25.rsslim, //该进程能驻留物理地址空间的最大值

                   26.mm ? (permitted ? mm->start_code : 1) : 0, //该进程在虚拟地址空间的代码段的起始地址

                   27.mm ? (permitted ? mm->end_code : 1) : 0, //该进程在虚拟地址空间的代码段的结束地址

                   28.(permitted && mm) ? mm->start_stack : 0, //该进程在虚拟地址空间的栈的结束地址

                   29.esp, //esp(32
位堆栈指针
) 的当前值,与在进程的内核堆栈页得到的一致

                   30.eip, //指向将要执行的指令的指针, EIP(32位指令指针)的当前值

                   31.task->pending.signal.sig[0] & 0x7fffffffUL, //待处理信号的位图,记录发送给进程的普通信号

                   32.task->blocked.sig[0] & 0x7fffffffUL, //阻塞信号的位图

                   33.sigign      .sig[0] & 0x7fffffffUL,  //忽略的信号的位图

                   34.sigcatch    .sig[0] & 0x7fffffffUL,  //被捕捉的信号的位图

                   35.wchan, //如果该进程是睡眠状态,该值给出调度的调用点

                   36.0UL,

                   37.0UL,

                   38.task->exit_signal, //该进程结束时,向父进程所发送的信号

                   39.task_cpu(task), //运行在哪个CPU

                   40.task->rt_priority, //实时进程的相对优先级别

                   41.task->policy,  //进程的调度策略

                   42.(unsigned long long)delayacct_blkio_ticks(task),

                   43.cputime_to_clock_t(gtime),

                   44.cputime_to_clock_t(cgtime));

注:这个输出的中间自动填充了个0,在22 start_time前。参考http://www.kerneltravel.net/?p=291

/proc/sched_debug
这个打印出所有cpu的信息,这里我们过滤出cpu3来解释

$cat /proc/sched_debug | grep "cpu#3" -A 73

Sched Debug Version: v0.09, 2.6.32-220.23.1.tb704.el6.x86_64 #1

now at 2805981745.049080 msecs

  .jiffies                                 : 7100649040 //cpu时间

  .sysctl_sched_latency                    : 20.000000

  .sysctl_sched_min_granularity            : 4.000000

  .sysctl_sched_wakeup_granularity         : 4.000000

  .sysctl_sched_child_runs_first           : 0.000000

  .sysctl_sched_features                   : 3183

  .sysctl_sched_tunable_scaling            : 1 (logaritmic) 

cpu#3, 2399.773 MHz

  .nr_running                    : 2 //cpu3 rq运行队列的进程个数(包括正在运行的)

  .load                          : 2048 //cpu3 rq运行队列的load

  .nr_switches                   : 42606615 //cpu3累计的进程切换次数

  .nr_load_updates               : 220734972 //load更新次数,也是调用update_cpu_load次数

  .nr_uninterruptible            : 0  // uninterruptible发生的次数

  .next_balance                  : 7100.059585 //下次执行负载均衡的时间

  .curr->pid                     : 25329 //当前运行的进程pid

  .clock                         : 2801062666.343504 //当前运行队列的clock

  .cpu_load[0]                   : 2048 //该cpu的历史load

  .cpu_load[1]                   : 2048

  .cpu_load[2]                   : 2048

  .cpu_load[3]                   : 2048

  .cpu_load[4]                   : 2048

  .yld_count                     : 1 //调用yield次数

  .sched_switch                  : 0

  .sched_count                   : 160158232  //调用schedule的次数

  .sched_goidle                  : 21108490  //切换到idle进程的次数

  .avg_idle                      : 1000000  // cpu处于idle的平均时间

  .ttwu_count                    : 21244621  //此cpu try_to_wake_up唤醒进程的次数

  .ttwu_local                    : 20424010 //本地唤醒的次数,即进程睡眠前所在cpu为当前cpu

  .bkl_count                     : 1  //此cpu上大内核锁调用次数

//下面是相应的cfs_rq内容,另外我们的执行进程在/cgroup/one 这个二级cgroup里

cfs_rq[3]:/one  //one group

  .exec_clock                    : 22907786.300379 //

  .MIN_vruntime                  : 22901158.741275 //红黑树最左边的vruntime

  .min_vruntime                  : 22901158.741275 //cfs_rq当前的min_vruntime

  .max_vruntime                  : 22901158.741275 //最右边的vruntime(这里因为只有一个,另一个在运行,所以最左与最右相等)

  .spread                        : 0.000000

  .spread0                       : -300525615.387521 // cpu0上的min_vruntime与当前cpu的min_vruntime差值

  .nr_spread_over                : 0

  .nr_running                    : 2 //该cfs_rq运行队列的进程个数(注:虽然运行的进程不在红黑树里,但是它还是cfs_rq里)

  .load                          : 2048 //该cfs_rq的load,是它下面两个进程的load之和(在account_entity_enqueue、account_entity_dequeue更新)

  .load_avg                      : 16496.090916  //update_cfs_load的统计值

  .load_period                   : 8.054731

  .load_contrib                  : 2047

  .load_tg                       : 2047

  .se->exec_start                : 2801062666.343504 //该cgroup的se调度实体(非它下面进程的se,而是它自身的se)下面的关于se的内容与每个进程自身的/proc/<pid>/sched内的含意是一样的

  .se->vruntime                  : 188458882.115828

  .se->sum_exec_runtime          : 22907786.300379

  .se->wait_start                : 0.000000

  .se->sleep_start               : 0.000000

  .se->block_start               : 0.000000

  .se->sleep_max                 : 0.000000

  .se->block_max                 : 0.000000

  .se->exec_max                  : 1.073055

  .se->slice_max                 : 0.000000

  .se->wait_max                  : 0.041254

  .se->wait_sum                  : 121.099885

  .se->wait_count                : 28673

  .se->load.weight               : 2048  //这个se本身的load,它是通过update_cfs_shares更新

 

cfs_rq[3]:/  //同上

  .exec_clock                    : 182645727.024410

  .MIN_vruntime                  : 0.000001

  .min_vruntime                  : 188458882.115828

  .max_vruntime                  : 0.000001

  .spread                        : 0.000000

  .spread0                       : -134967892.012968

  .nr_spread_over                : 4

  .nr_running                    : 1

  .load                          : 2048

  .load_avg                      : 0.000000

  .load_period                   : 0.000000

  .load_contrib                  : 0

  .load_tg                       : 0

 

runnable tasks: //运行队列里的进程,有两个28733,25329,并且当前运行的是25329

            task   PID         tree-key  switches  prio     exec-runtime         sum-exec        sum-sleep

----------------------------------------------------------------------------------------------------------

        cpu_test 28733  22901158.741275     26280   120  22901158.741275  22600181.659870         0.000000 /one

R       cpu_test 25329  22901163.146132       404   120  22901163.146132      6413.013913         0.000000 /one

tree-key:调度进程的se->vruntime;switches:主动与被动切换之和;exec-runtime:se->vruntime;sum-exec:se->sum_exec_runtime(实际运行的物理时间);sum-sleep:se.sum_sleep_runtime;最后加所属的cgroup

该信息的打印入口在sched_debug.c的sched_debug_show函数。

 注:上面的很多信息是从网上搜索,再加上自己对调度器相关字段的验证,其它的内容没有验证

参考资料

http://chxxxyg.blog.163.com/blog/static/1502811932012912546208/
http://blog.csdn.net/chenyu105/article/details/7068758
proc目录解析:http://www.kerneltravel.net/?p=294
rq结构的注释:http://blog.csdn.net/bullbat/article/details/7160246

抱歉!评论已关闭.