实践 Linux 编程之叁 - 优化
根据木桶效应,一个程序瓶颈决定它的性能,所以性能优化的核心是找出系统的瓶颈点。
分析系统瓶颈
系统响应变慢,首先得定位大致的问题出在哪里,是 IO 瓶颈、CPU 瓶颈、内存瓶颈还是程序导致的系统问题;
使用 top 工具能够比较全面的查看我们关注的点:
1 | $top |
进入交互模式后:
输入
M
,进程列表按内存使用大小降序排序,便于我们观察最大内存使用者使用有问题(检测内存泄漏问题); 输入P
,进程列表按 CPU 使用大小降序排序,便于我们观察最耗 CPU 资源的使用者是否有问题;top
第三行显示当前系统的,其中有两个值很关键:% id
:空闲 CPU 时间百分比,如果这个值过低,表明系统 CPU 存在瓶颈;% wa
:等待 I/O 的 CPU 时间百分比,如果这个值过高,表明 IO 存在瓶颈;
分析内存瓶颈
查看内存是否存在瓶颈,使用 top
指令看比较麻烦,而 free
命令更为直观:
1 | $ free |
top
工具显示了 free
工具的第一行所有信息,但真实可用的内存,还需要自己计算才知道;系统实际可用的内存为 free
工具输出第二行的 free+buffer+cached
;也就是第三行的 free
值 191580;关于 free
命令各个值的详情解读,请参考这篇文章 free 查询可用内存 ;
如果是因为缺少内存,系统响应变慢很明显,因为这使得系统不停的做换入换出的工作;
进一步的监视内存使用情况,可使用 vmstat
工具,实时动态监视操作系统的内存和虚拟内存的动态变化。 参考: vmstat 监视内存使用情况 ;
分析 IO 瓶颈
如果 IO 存在性能瓶颈,top
工具中的 % wa
会偏高;
进一步分析使用 iostat
工具:
1 | $ iostat -d -x -k 1 1 |
- 如果
% iowait
的值过高,表示硬盘存在 I/O 瓶颈。 - 如果
% util
接近 100%,说明产生的 I/O 请求太多,I/O 系统已经满负荷,该磁盘可能存在瓶颈。 - 如果
svctm
比较接近await
,说明 I/O 几乎没有等待时间; - 如果
await
远大于svctm
,说明 I/O 队列太长,io 响应太慢,则需要进行必要优化。 - 如果
avgqu-sz
比较大,也表示有大量 io 在等待。
更多参数说明请参考 iostat 监视 I/O 子系统 ;
分析进程调用
通过 top
等工具发现系统性能问题是由某个进程导致的之后,接下来我们就需要分析这个进程;继续 查询问题在哪;
这里我们有两个好用的工具: pstack
和 pstrace
pstack 用来跟踪进程栈,这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于 work 状态(如假死状态,好似死循环),使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次 pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方;
示例:查看 bash 程序进程栈:
1 | /opt/app/tdev1$ps -fe| grep bash |
而 strace
用来跟踪进程中的系统调用;这个工具能够动态的跟踪进程执行时的系统调用和所接收的信号。是一个非常有效的检测、指导和调试工具。系统管理员可以通过该命令容易地解决程序问题。
参考: strace 跟踪进程中的系统调用 ;
优化程序代码
优化自己开发的程序,建议采用以下准则:
- 二八法则:在任何一组东西中,最重要的只占其中一小部分,约 20%,其余 80% 的尽管是多数,却是次要的;在优化实践中,我们将精力集中在优化那 20% 最耗时的代码上,整体性能将有显著的提升;这个很好理解。函数 A 虽然代码量大,但在一次正常执行流程中,只调用了一次。而另一个函数 B 代码量比 A 小很多,但被调用了 1000 次。显然,我们更应关注 B 的优化。
- 先编码后优化;编码的时候总是考虑最佳性能未必总是好的;在强调最佳性能的编码方式的同时,可能就损失了代码的可读性和开发效率;
gprof 使用步骤
- 用 gcc、g++、xlC 编译程序时,使用
-pg
参数,如:g++ -pg -o test.exe test.cpp
编译器会自动在目标代码中插入用于性能测试的代码片断,这些代码在程序运行时采集并记录函数的调用关系和调用次数,并记录函数自身执行时间和被调用函数的执行时间。 - 执行编译后的可执行程序,如:
./test.exe
。该步骤运行程序的时间会稍慢于正常编译的可执行程序的运行时间。程序运行结束后,会在程序所在路径下生成一个缺省文件名为gmon.out
的文件,这个文件就是记录程序运行的性能、调用关系、调用次数等信息的数据文件。 - 使用
gprof
命令来分析记录程序运行信息的 gmon.out 文件,如:gprof test.exe gmon.out
则可以在显示器上看到函数调用相关的统计、分析信息。上述信息也可以采用gprof test.exe gmon.out> gprofresult.txt
重定向到文本文件以便于后续分析。
关于 gprof
的使用案例,请参考 [f1] ;
其它工具
可以使用 valgrind 来分析内存泄漏问题。
使用 OProfile 或 sar 来分析程序性能。