Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1872476
  • 博文数量: 283
  • 博客积分: 10141
  • 博客等级: 上将
  • 技术积分: 2931
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-21 14:33
文章分类

全部博文(283)

文章存档

2013年(2)

2012年(2)

2011年(17)

2010年(36)

2009年(17)

2008年(18)

2007年(66)

2006年(105)

2005年(20)

分类: LINUX

2007-04-26 18:06:45

icymoon@NKU

0.起因&前注

需要一个效率高点的系统监控程序,而已有的ksh脚本比较慢。

注:

本文中所有样例,2.6.x kernel的取自rhel4, 2.4.x kernel的取自rh9.

时间仓促,有不当之处欢迎指点。谢谢。

Copyright: icymoon@NKU

 

1.需要的系统状态信息

  • CPU Usage
  • Memory/Swap Usage
  • Disk Usage
  • Disk I/O Ratio
  • Process Information

2.
相关文件及计算方法(1)CPU Usage

相关文件:/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

各字段的含义如第一行所写,解释如下:

major 主设备号
minor 从设备号
#blocks 块数
name 设备名
rio读磁盘的次数,成功完成读的总次数(队列中的不算)
rmerge 合并读的次数(两次相邻的IO读写可能被合成一次做)
rsect 读的扇区数(一般而言,一个sector是512 bytes,但是有些硬盘在初始化的时候支持改扇区大小,这个我未做处理)
ruse读花费的毫秒数
wio 写磁盘的次数,成功完成写的总次数(队列中的不算)
wmerge 合并写的次数
wsect 写的扇区数,参见rsect
wuse 写花费的毫秒数
running I/O的当前进度
use花在I/O操作上的毫秒数
aveq 在队列中总的等待的毫秒数

    这里的文件记录的也是从系统启动以来的总时间数,所以也需要两次读取文件  计算差值。

b. 2.6.x kernel: /proc/diskstats

   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.x2.6.xkernel下,此文件中的字段有所不同,但是所需的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+1CPU

  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的值有些偏差,个人认为很正常。

阅读(5842) | 评论(10) | 转发(0) |
给主人留下些什么吧!~~