注下面的时间或时刻都是从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 //该se的load 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 |
该信息的入口在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 1 0 2782750364005888 82 184467440737095516154194304 4195884 140733625322688 140733625322136 41954610 0 0 0 0 0 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终端的设备号,INT(34817/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 |
该信息的打印入口在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