分类: LINUX
2007-04-26 18:06:45
0.起因&前注
需要一个效率高点的系统监控程序,而已有的ksh脚本比较慢。
注:
本文中所有样例,2.6.x kernel的取自rhel4, 2.4.x kernel的取自rh9.
时间仓促,有不当之处欢迎指点。谢谢。
Copyright:
icymoon@NKU
1.需要的系统状态信息
相关文件:/proc/stat的第一行
文件样例&基本计算方法:
a. 2.4.x kernel:
cpu 3156877 522645 1178059 169750391 cpu0
1111979 148713 315873 42075428 cpu1
444227 139960 119846 42947960 cpu2
1113218 155429 480187 41903159 cpu3
487453 78543 262153 42823844 page
1265588 10643253 swap
121 1258 intr
135336914 43651993 84 0 0 1 0 3 0 1 0 0 0 0 0 2 0 0 0 0 0 30 0 0 0 0 0 0
778176 42 60685630 30220952 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 disk_io:
(8,0):(788586,178980,2529284,609606,21286496) (8,1):(3,3,24,0,0) ctxt
171689341 btime
1177119654 processes
3110142 |
在kernel 2.4.x下,第一行只有五个字段,后四个字段依次是自从系统启动以来,系统运行在user
mode, nice, system mode下和idle状态的时间,以1/100秒为单位。(后面的cpu0, cpu1…行是在有多处处理器的机器上,每个处理器运行在不同模式下的值,含义相同。)
则设总CPU运行时间为total,total = usr + nice + sys +
idle
在一定时间间隔下两次读取文件,得到前后两次的处理器运行时间为usr1,
nice1,sys1,idle1与usr2, nice2, sys2, idle2.
total1 = usr1 + nice1 + sys1 + idle1
total2 = usr2 + nice2 + sys2 + idle2
间隔时间为itv = total2-total1,则有
usr_ratio = (usr2-usr1)/itv
nice_ratio = (nice2-nice1)/itv
sys_ratio = (sys2-sys1)/itv
idle_ratio = (idle2-idle1)/itv
b. 2.6.x kernel:
cpu 620459 1528 3480863 8487506 13767 65592 0 cpu0
620459 1528 3480863 8487506 13767 65592 0 intr
130595795 126276003 445 0 8 8 0 6 0 1 0 0 0 1883 0 0 1694405 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 187958 0 0 0 0 0 0 0
2435078 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ctxt
15528352 btime
1177387075 processes
101775 procs_running
2 procs_blocked
0 |
在kernel 2.6.x下,第一行有八个字段,后七个字段依次是自从系统启动以来,系统运行在user
mode, nice, system mode下,idle状态,IO等待,响应中断和处理软件中断请求的时间,以1/100秒为单位。(后面的cpu0, cpu1…行是在有多处处理器的机器上,每个处理器运行在不同模式下的值,含义相同。)
则设总CPU运行时间为total = usr + nice + sys + idle +
irq +sirq。
在一定时间间隔下两次读取文件,依次得到前后两次的处理器运行时间为usr1, nice1, sys1,
idle1, wio1, irq1, sirq1与usr2, nice2, sys2, idle2, wio2, irq2, sirq2,则总时间为:
total1 = usr1 + nice1 + sys1 + idle1 +
wio1 + irq1 + sirq1
total2 = usr2 + nice2 + sys2 + idle2 +
wio2 + irq2 + sirq2
间隔时间为itv = total2-total1,则有
usr_ratio = (usr2-usr1)/itv (同2.4.x
kernel)
nice_ratio = (nice2-nice1)/itv (同2.4.x
kernel)
sys_ratio = (sys2-sys1 + irq2-irq1 +
sirq2-sirq1)/itv
idle_ratio = (idle2-idle1)/itv (同2.4.x
kernel)
wio_ratio = (wio2-wio1)/itv (同2.4.x
kernel)
(2) Memory/Swap Usage
相关文件:/proc/meminfo
文件样例&基本方法:
2.4.x和2.6.x的kernel中,此文件条目有所不同,但都有MemTotal,
MemFree, SwapTotal, SwapFree几项,此处列出的为2.6.x kernel的/proc/meminfo
MemTotal: 1034628 kB //Memory大小 MemFree: 788236 kB //空闲的Memory大小 Buffers: 18280 kB Cached: 77668 kB SwapCached: 7792 kB Active: 189292 kB Inactive: 25920 kB HighTotal: 131008 kB HighFree: 6848 kB LowTotal: 903620 kB LowFree: 781388 kB SwapTotal: 1044216 kB //Swap大小 SwapFree: 882160 kB //空闲的Swap大小 Dirty: 0 kB Writeback: 0 kB Mapped: 174800 kB Slab: 15524 kB Committed_AS: 2617468 kB PageTables: 8376 kB VmallocTotal: 106488 kB VmallocUsed: 2736 kB VmallocChunk: 103720 kB HugePages_Total: 0 HugePages_Free: 0 Hugepagesize: 2048 kB |
直接截取需要的值即可。
(3) Disk Usage
相关文件:/etc/mtab
文件样例:
/dev/sda1
/ ext3 rw 0 0 none
/proc proc rw 0 0 none
/sys sysfs rw 0 0 none
/dev/pts devpts rw,gid=5,mode=620 0 0 none
/dev/shm tmpfs rw 0 0 none /proc/sys/fs/binfmt_misc binfmt_misc rw 0 0 sunrpc
/var/lib/nfs/rpc_pipefs rpc_pipefs rw 0 0 |
这项我没有从procfs中找到相关的容易处理的记录,从/etc/mtab中找出mount的文件系统,然后用statfs()计算出了各分区的大小,使用率等。
(4) Disk I/O Ratio
相关文件:
2.4.x kernel: /proc/partitions
2.6.x kernel: /proc/diskstats
文件样例&基本计算方法:
a. 2.4.x
kernel: /proc/partitions
major
minor #blocks name
rio rmerge rsect ruse wio wmerge wsect wuse running use aveq 8 0
71687000 sda 178957 149039 2530308 888510 605346 2077193 21538256
31996930 1 7071640 28318295 8 1
265041 sda1 94 1442 3072 520 48 46 188 2140 0 2240 2660 8 2
26218080 sda2 158171 58945 1736930 707710 480208 1963728 19630952
26968300 0 3778470 27676880 8 3
2096482 sda3 20645 88501 789146 179980 125010 111991 1895052 5025510
-1 31137500 19312352 8 4 1 sda4 0 0 0 0 0 0 0 0 0 0 0 8 5
2096451 sda5 43 131 1128 280 80 1428 12064 1020 0 1060 1300 8 16
71687000 sdb 3 17 24 30 0 0 0 0 0 30 30 |
各字段的含义如第一行所写,解释如下:
1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 22 0 hdc 0 0 0 0 0 0 0 0 0 0 0 8 0
sda 26641 6669 1046164 486853 175040 533622 5669368 685767 0 482953 1172621 8 1 sda1 27434 1001786 661731 5293848 8 2 sda2 5776 43530 46940 375520 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 |
这个文件中,我们只关心这一行:
8 0 sda 26641 6669 1046164 486853 175040
533622 5669368 685767 0 482953 1172621
除了没有#blocks字段,其他的含义与顺序与2.4.x的/proc/partitions相同。计算方法也一样。
其实,也可以读/proc/sysfs/设备/stat文件中的东西,没有主从设备号与设备名外,字段含义与顺序基本相同。这样的方法更适合查看少量固定的设备。而在需要监控很多设备的时候,还是读/proc/diskstats比较节省文件描述符。:P
(5) Process Information
每个进程在/proc目录下有自己的目录,以进程ID为目录名。
要得到command
line,直接读取/proc/PID/cmdline即可,但要注意里面可能有不可打印字符需要处理。
要得到vsz,和thread Count(2.6.x kernel)则需要从/proc/PID/status直接截取。
要得到cpu
ratio的话,则需要/proc/PID/stat和系统启动的总时间(计算方法见(6)c.)了。虽然2.4.x与2.6.x的kernel下,此文件中的字段有所不同,但是所需的utime,stime,start_time却是相同的字段(luckily...)。
2086 (crond) S 1 2086 2086 0 -1 4194368 2558 384582 0
101 90 668 2533 20814 16 0 1 0 12431 4788224 266 4294967295 3149824 3186304
3221044688 3221043812 5158818 0 0 0 81923 0 0 0 17 0 0 0 |
utime: 第14个字段,指此进程被调入user mode执行的时间,以1/100秒为单位
stime: 第15个字段,指此进程被调入system mode执行的时间,以1/100秒为单位
start_time: 第20个字段,指此进程是从系统启动多长时间后后被启动的,以1/100秒为单位
则cpu_ratio =
(utime+stime)/(uptime-start_time)
(6) 其他:
a.cpu个数
一个方法是可以通过/proc/cpuinfo来看,另外一个方法是找/proc/stat文件中第二行开始有以cpu0...cpux开头的行,则有x+1个CPU。
b.内核版本
读取/proc/version即可,包括了内核版本和机器架构等信息。
c.系统起动时间
可以从/proc/stat的第一行算(就是总的CPU time),以1/100s为单位,也可以从/proc/uptime中读,以秒为单位,精确到两位小数。第二种方法比第一种方法快。
3.代码实现的一些细节问题
//用C代码实现过程中,遇到的一些问题。
(1) /proc/PID/cmdline中有可能含有不可打印字符分割参数,截取参数可能出错,需要单独处理。
(2) 分析记录系统启动以来的各项操作的总数/总时间的文件时候需要至少读取两次文件,在连续监控系统状态时,可以考虑将在相关函数中声明static变量保存上一次读取到的值,这样,如果需要N次记录的话,只需要读N+1次文件即可。
(3) 注意处理溢出。
(4) 最初我写出来的代码时间很差,花了一天时间进行优化,发现有以下几点值得注意(对性能影响较大),一是要减少读文件的次数,二是要注意读取文件所用的函数(read/fgets/getline…)。可以使用gprof工具与gettimeofday()函数来辅助性能分析。
(5) Disk IO取出来的值与iostat的值有些偏差,个人认为很正常。