在软件工程中,我们常常需要监测某个进程或者整个系统的资源消耗情况,这其中包括对于CPU,内存还有IO信息的了解。这方面的工具非常多,其中有些商业工具非常的贵。但在Linux社区里,有很多的免费开源工具做的已经非常优秀。本文就将介绍Linux上一个优秀的系统监测工具:sysstat。
前言
软件工程常常涉及性能优化,而在优化之前,我们首先需要能够度量和了解当前的系统状态,这样才能有目标的进行性能优化。
“We should forget about small efficiencies, say about 97% of the time; premature optimization is the root of all evil”
– Donald E. Knuth, Structured Programming with go to Statements
这就好像电力工程师使用电笔,生物工程师使用显微镜,医生使用各种医疗仪器一样。“工欲善其事,必先利其器”,有了好的工具才能帮助我们更好的完成手上的任务。
本文将介绍的就是一个免费又通用的系统监测工具,它可以用在几乎所有的Linux系统上,当然也包括Android系统。
因此,在熟悉它们之后,我相信很多人都可以在自己的工程中使用这个工具。
阿姆达尔定律
既然提到性能优化,就有必要提一下阿姆达尔定律。
阿姆达尔定律(英语:Amdahl’s law,Amdahl’s argument),是一个计算机科学界的经验法则,由著名半导体工程师及企业家吉恩·阿姆达尔而得名。它代表了处理器并行运算之后效率提升的能力。
阿姆达尔是IBM系统360大型机之父。系统360(System/360)是历史上最成功的大型机,没有之一。
阿姆达尔一生至少有四个标签:最伟大的计算架构师之一(一般认为能和他相比的只有巨型机之父西摩·克雷Seymour Cray),阿姆达尔法则的提出者,微软FUD策略(代表恐惧、不确定和怀疑)的发明人,以及“地狱的常客”。
– 吴军《谷歌方法论》
并行计算中的加速比是用并行前的执行速度和并行后的执行速度之比来表示的,它表示了在并行化之后的效率提升情况。
阿姆达尔定律可以用下面的公式来表达:
\[S_{latency}(s) = \frac{1}{(1 - p) + \frac{p}{s}}\]在这个公式中:
- $S_{latency}$ 是执行整个任务理论上的加速比;
- s 是并行处理的数目;
- p 是可以并行处理部分任务所占的比例;
- 相应的,$(1-p)$ 是需要串行(不可并行)处理部分任务所占的比例;
根据上面的公式我们可以得到下面的结论:
\[\begin{cases} S_{latency}(s) \le \frac{1}{1-p} \\ \lim\limits_{x \to \infty} S_{latency}(s) = \frac{1}{1-p} \end{cases}\]举一个具体的例子:假设一项任务包含两个子任务:
- 子任务A需要串行执行,它的执行需要耗费1个小时;
- 子任务B可以并行执行,在不并行的情况下,它需要耗费19个小时;
那么,这里的 $ p = \frac{19}{20} = 0.95$。在完全串行的情况下,完成整个任务需要耗费20个小时。但如果我们将子任务B进行串行运算,那么总时间将缩短。但无论如何,总时间不会小于1个小时(加速比:$\frac{1}{1-0.95}$ = 20)。
下图是维基百科上提供的一张图。这张图中:
- 横轴表示并行处理的数目;
- 纵轴表示加速比;
- 图中的四条不同颜色的曲线表示了在p取不同的值的情况下的加速情况;
从这幅图可以看出,当p取50%的时候,无论并行处理的节点有多少,最大的加速比只有2。但是,当p取0.95的时候,最大的加速比可以达到20。
这就是在提示我们,优化是有优先级的。假设某个软件系统的时间消耗由几个部分组成,如果我们没有事先测量,那么可能无论我们怎么优化,其收益都可能是很低的,因为我们优化的部分可能在整个系统中所占的时间消耗比例非常小。
当然,生活的事情也是同样的道理。因此,这就告诉我们,在做优化之前进行有效的度量和对任务的认识是多么的重要。
sysstat介绍
sysstat实际上是一个工具箱,这其中包含了好几个工具。它们的介绍如下:
工具 | 说明 |
---|---|
iostat | 报告CPU状态,块设备以及分区的IO信息。 |
mpstat | 报告单个核或整体CPU的信息。 |
pidstat | 报告进程,线程的IO,CPU和内存使用情况。 |
tapestat | 报告磁带设备的信息。 |
cifsiostat | 报告CIFS的信息。 |
sar | 收集,报告和存储系统活动信息。 |
sadc | sar的后端,用来收集系统活动数据。 |
sa1 | 以二进制的形式收集和存储系统活动数据。 |
sa2 | 负责写入日常活动报告的统计信息。 |
sadf | 以不同的格式(CSV,XML,JSON等)显示sar收集的数据。 |
sysstat安装
在Linux上安装sysstat非常的简单,只要通过包管理程序进行安装即可。
在Ubuntu上安装sysstat的命令如下:
sudo apt-get install sysstat
在RHEL/Fedora/CentOS上安装的命令如下:
sudo yum install sysstat
从源码编译sysstat
如果你的系统上没有包管理程序,你可以从源码编译出产物。
sysstat的源码在github上,你可以通过下面这条命令下载其源码:
git clone https://github.com/sysstat/sysstat.git
为Android设备编译
下面以Android ARM类型的设备为例,讲解如何编译出可以运行的产物。
由于Android设备通常使用ARM架构的芯片,这与个人电脑的x86_64架构的CPU不一样,因此电脑上可以运行的可执行文件在ARM设备上是无法运行的。此时就需要借助gcc的交叉编译工具链。
交叉编译器(英语:Cross compiler)是指一个在某个系统平台下可以产生另一个系统平台的可执行文件的编译器。
可以通过下面这组命令编译出可以在Android ARM设备上运行的sysstat工具:
git clone https://github.com/sysstat/sysstat.git
cd sysstat
export CC=arm-linux-gnueabi-gcc
./configure --host=armv7-linux-gnueabi CFLAGS=-static
make
这里指定了交叉编译器为arm-linux-gnueabi-gcc
,同时通过CFLAGS=-static
设定为静态链接。这样编译出的可执行文件不依赖动态链接库,单独将可执行文件push到Android设备上就可以运行了。
编译完成之后可以通过下面的命令查看所有的可执行程序:
find . -maxdepth 1 -type f -executable
./mpstat
./sar
./pidstat
./configure
./config.status
./sadf
./sadc
./iconfig
./iostat
./sa1
./cifsiostat
./do_test
./sysstat
./tapestat
./sa2
接下来将编译出的可执行文件push到设备上即可,之后通过adb shell
切换到Android设备上就可以运行刚刚push的命令了。
如果是没有
root
的Android设备,可以将可执行文件push到/data
目录下使用。
CPU状态查看
借助mpstat
工具,我们可以查询CPU的占用情况。直接输入mpstat
会显示CPU的整体情况,信息量比较少。如果想查询完整的CPU信息,可以输入:
mpstat -A
目前大部分设备(包括移动设备)都是多核的,我们常常想要监测每一个CPU核的占用情况。这时可以通过下面这条命令来完成:
mpstat -P ALL 1
Linux 4.18.0-25-generic (paul-ubuntu) 2019年08月27日 _x86_64_ (8 CPU)
13时37分38秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
13时37分39秒 all 10.75 0.38 5.88 0.12 0.00 0.12 0.00 0.00 0.00 82.75
13时37分39秒 0 3.06 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.94
13时37分39秒 1 9.90 0.00 7.92 0.00 0.00 0.00 0.00 0.00 0.00 82.18
13时37分39秒 2 5.10 0.00 4.08 0.00 0.00 0.00 0.00 0.00 0.00 90.82
13时37分39秒 3 9.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 0.00 87.00
13时37分39秒 4 16.35 0.00 8.65 0.96 0.00 0.00 0.00 0.00 0.00 74.04
13时37分39秒 5 13.13 2.02 4.04 0.00 0.00 0.00 0.00 0.00 0.00 80.81
13时37分39秒 6 6.06 0.00 5.05 0.00 0.00 0.00 0.00 0.00 0.00 88.89
13时37分39秒 7 23.00 0.00 14.00 0.00 0.00 0.00 0.00 0.00 0.00 63.00
13时37分39秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
13时37分40秒 all 1.26 11.68 1.01 0.00 0.00 0.00 0.00 0.00 0.00 86.06
13时37分40秒 0 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99
13时37分40秒 1 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.00
13时37分40秒 2 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00
13时37分40秒 3 0.00 0.99 0.99 0.00 0.00 0.00 0.00 0.00 0.00 98.02
13时37分40秒 4 0.99 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.01
13时37分40秒 5 0.00 93.07 5.94 0.00 0.00 0.00 0.00 0.00 0.00 0.99
13时37分40秒 6 3.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 96.00
13时37分40秒 7 3.06 0.00 1.02 0.00 0.00 0.00 0.00 0.00 0.00 95.92
...
这里的-P ALL
表示所有的CPU核,末尾的数字1
表示每隔一秒刷新一次结果。
详细的
mpstat
命令参数见这里:mpstat - Report processors related statistics.
IO状态查看
iostat
命令用来查看系统输入输出设备的数据传输情况,下面是一个示例。命令参数1 3
表示每隔一秒刷新一次数据,总共刷新三次。
iostat 1 3
Linux 3.10.0+ (localhost) 08/27/19 _armv7l_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
68.44 3.13 28.32 0.05 0.00 0.06
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
vda 14.86 1410.49 0.00 0.00 916957 0 0
vdb 0.08 0.32 0.14 0.00 209 88 0
vdc 6.04 19.58 123.43 0.00 12730 80244 0
vdd 0.15 8.27 0.02 0.00 5377 13 0
avg-cpu: %user %nice %system %iowait %steal %idle
69.31 0.00 30.69 0.00 0.00 0.00
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
vda 25.74 2847.52 0.00 0.00 2876 0 0
vdb 0.00 0.00 0.00 0.00 0 0 0
vdc 3.96 0.00 51.49 0.00 0 52 0
vdd 0.00 0.00 0.00 0.00 0 0 0
avg-cpu: %user %nice %system %iowait %steal %idle
70.30 1.98 27.72 0.00 0.00 0.00
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
vda 0.00 0.00 0.00 0.00 0 0 0
vdb 0.00 0.00 0.00 0.00 0 0 0
vdc 1.98 0.00 7.92 0.00 0 8 0
vdd 0.00 0.00 0.00 0.00 0 0 0
详细的
pidstat
命令参数见这里:iostat - Report Central Processing Unit (CPU)statistics and input/output statistics for devices and partitions.。
进程状态查看
pidstat
用来查看进程和线程的资源使用情况。直接输入这个命令将显示系统中正在运行的进程和这些进程的CPU使用情况,如下所示:
pidstat
Linux 4.18.0-25-generic (paul-ubuntu) 2019年08月27日 _x86_64_ (8 CPU)
13时49分55秒 UID PID %usr %system %guest %wait %CPU CPU Command
13时49分55秒 0 1 0.07 0.07 0.00 0.01 0.14 0 systemd
13时49分55秒 0 2 0.00 0.00 0.00 0.00 0.00 3 kthreadd
13时49分55秒 0 9 0.00 0.00 0.00 0.00 0.00 0 ksoftirqd/0
13时49分55秒 0 10 0.00 0.05 0.00 0.02 0.05 5 rcu_sched
13时49分55秒 0 12 0.00 0.00 0.00 0.00 0.00 0 migration/0
13时49分55秒 0 13 0.00 0.00 0.00 0.00 0.00 0 watchdog/0
13时49分55秒 0 16 0.00 0.00 0.00 0.00 0.00 1 watchdog/1
13时49分55秒 0 17 0.00 0.00 0.00 0.00 0.00 1 migration/1
13时49分55秒 0 18 0.00 0.00 0.00 0.01 0.00 1 ksoftirqd/1
13时49分55秒 0 22 0.00 0.00 0.00 0.01 0.00 2 watchdog/2
13时49分55秒 0 23 0.00 0.00 0.00 0.01 0.00 2 migration/2
13时49分55秒 0 24 0.00 0.00 0.00 0.00 0.00 2 ksoftirqd/2
13时49分55秒 0 28 0.00 0.00 0.00 0.00 0.00 3 watchdog/3
13时49分55秒 0 29 0.00 0.00 0.00 0.00 0.00 3 migration/3
13时49分55秒 0 30 0.00 0.00 0.00 0.00 0.00 3 ksoftirqd/3
13时49分55秒 0 34 0.00 0.00 0.00 0.00 0.00 4 watchdog/4
...
除了查看CPU使用情况,这个命令也可以查看进程的内存和IO情况。只需要带上-d
或-r
参数即可。
线程状态查看
现在很多服务都会是多线程模型,这种情况下,我们就想知道服务的每个线程的运行状态,这个时候运行这个命令加上-t
参数即可。如果只想查看某个进程的子线程,还可以带上-p <pid>
参数。
下面是一个示例:
pidstat -t -p 21848
Linux 4.18.0-25-generic (paul-ubuntu) 2019年08月27日 _x86_64_ (8 CPU)
13时51分37秒 UID TGID TID %usr %system %guest %wait %CPU CPU Command
13时51分37秒 1000 21848 - 0.16 0.05 0.00 0.00 0.20 1 firefox
13时51分37秒 1000 - 21848 0.09 0.02 0.00 0.00 0.11 1 |__firefox
13时51分37秒 1000 - 21855 0.00 0.00 0.00 0.00 0.00 3 |__gmain
13时51分37秒 1000 - 21856 0.00 0.00 0.00 0.00 0.00 0 |__gdbus
13时51分37秒 1000 - 21857 0.00 0.00 0.00 0.00 0.00 4 |__Gecko_IOThread
13时51分37秒 1000 - 21858 0.00 0.00 0.00 0.00 0.00 4 |__JS Watchdog
13时51分37秒 1000 - 21859 0.00 0.00 0.00 0.00 0.00 4 |__JS Helper
13时51分37秒 1000 - 21860 0.00 0.00 0.00 0.00 0.00 5 |__JS Helper
13时51分37秒 1000 - 21861 0.00 0.00 0.00 0.00 0.00 1 |__JS Helper
13时51分37秒 1000 - 21862 0.00 0.00 0.00 0.00 0.00 3 |__JS Helper
13时51分37秒 1000 - 21863 0.00 0.00 0.00 0.00 0.00 2 |__JS Helper
13时51分37秒 1000 - 21864 0.00 0.00 0.00 0.00 0.00 1 |__JS Helper
13时51分37秒 1000 - 21865 0.00 0.00 0.00 0.00 0.00 5 |__JS Helper
13时51分37秒 1000 - 21866 0.00 0.00 0.00 0.00 0.00 0 |__JS Helper
13时51分37秒 1000 - 21867 0.00 0.00 0.00 0.00 0.00 1 |__Timer
13时51分37秒 1000 - 21868 0.00 0.00 0.00 0.00 0.00 3 |__Link Monitor
13时51分37秒 1000 - 21869 0.01 0.00 0.00 0.00 0.01 3 |__Socket Thread
13时51分37秒 1000 - 21870 0.00 0.00 0.00 0.00 0.00 2 |__AudioIPC Callba
13时51分37秒 1000 - 21871 0.00 0.00 0.00 0.00 0.00 6 |__AudioIPC Callba
13时51分37秒 1000 - 21872 0.00 0.00 0.00 0.00 0.00 0 |__AudioIPC Server
13时51分37秒 1000 - 21873 0.00 0.00 0.00 0.00 0.00 3 |__AudioIPC Server
13时51分37秒 1000 - 21877 0.00 0.00 0.00 0.00 0.00 5 |__Cache2 I/O
13时51分37秒 1000 - 21878 0.00 0.00 0.00 0.00 0.00 4 |__Cookie
13时51分37秒 1000 - 21880 0.00 0.00 0.00 0.00 0.00 5 |__DOM Worker
...
详细的
pidstat
命令参数见这里:pidstat - Report statistics for Linux tasks.。
系统活动状态查看
sar
全称是System Activity Report。这是一个大而全的工具。借助它可以查看系统的很多方面状态。
下面是一些常用的参数:
-A
查看最全的信息-B
查看paging统计-b
查看输入输出信息-d
查看块设备活动-n {keyword | ALL}
查看网络信息-P {cpu_list | ALL }
指定CPU核查看信息-r
查看内存使用率信息-S
查看swap空间的使用信息-u
查看CPU使用率
下面是查看内存使用情况的示例:
sar -r 1 5
Linux 3.10.0+ (localhost) 08/29/19 _armv7l_ (1 CPU)
08:12:23 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
08:12:24 226524 0 379004 24.39 19176 903296 30574892 1967.86 581192 689456 0
08:12:25 226400 0 379128 24.40 19176 903296 30574892 1967.86 581180 689456 0
08:12:26 226400 0 379128 24.40 19176 903296 30574892 1967.86 581172 689456 0
08:12:27 226400 0 379128 24.40 19176 903296 30574892 1967.86 581180 689456 0
08:12:28 229064 0 376464 24.23 19176 903296 30568068 1967.42 577748 689456 0
Average: 226958 0 378570 24.37 19176 903296 30573527 1967.77 580494 689456 0
下面是查看网络状况的示例:
sar -n SOCK 1 5
Linux 3.10.0+ (localhost) 08/29/19
_armv7l_ (1 CPU)
08:15:51 totsck tcpsck udpsck rawsck ip-frag tcp-tw
08:15:52 315 1 1 0 0 0
08:15:53 315 1 1 0 0 0
08:15:54 315 1 1 0 0 0
08:15:55 315 1 1 0 0 0
08:15:56 315 1 1 0 0 0
Average: 315 1 1 0 0 0
详细的
sar
命令参数见这里:sar - Collect, report, or save system activity information.。