06 Linux
性能优化
1. 概述
# 主要思路
- 找到应用或系统的瓶颈, 然后设法避免或解决它;
# 核心指标
- 网络型应用, 提升吞吐率;
- 批处理应用, 加快计算速度;
2. 查看资源使用概况 (top 或 /proc)
# 1.查看资源使用概况
- 使用 `top` 查看系统整体资源的使用情况, 尤其是所有进程的资源使用情况;
- 使用 `free` 查看内存使用概况;
- 使用 `iostat` 查看磁盘使用概况;
- 使用 `iftop` 查看流量使用概况;
# 更详细地, 可以查看 /proc 文件夹下的文件
- /proc : 该文件夹是伪文件系统, 它通过文件系统的形式展现内核和进程的动态资源
- cpuinfo 文件: CPU 资源使用情况;
- meminfo 文件: 内存资源使用情况;
- /proc/num 文件夹: pid 为 num 进程的资源文件, 可以看到 `cmdline` 进程启动命令, `environ` 环境变量配置等等;
- 还可以直接通过修改文件的值, 改变内核参数, 如: 修改 icmp_echo_ignore_all 参数, 控制主机不响应 ping 命令;
3. 查看进程系统调用 (strace)
# 查看系统调用
- `strace` 命令可以监控进程运行过程中的系统调用, 信号传递等;
- 如果一个进程无法启动的原因在于系统调用, `strace` 可以找出在哪个系统调用时出错, 如: 用 open() 打开了不存在的文件;
- 如果一个进程打开后被关闭, `strace` 可以找出被哪个进程发出的 kill 信号关闭的;
- 如果一个进程效率低, `strace` 可以记录运行过程中触发的所有系统调用信息, 一般频繁的创建和销毁子进程非常耗时;
4. 查看进程资源分类使用情况 (pidstat)
# 思路
- 利用 `pidstat -u` 查看进程 CPU 分类时间的占用情况, 定位进程在哪个方面存在问题和瓶颈;
# CPU 时间分类
- 诺用户 CPU 占用过高: 问题出在用户逻辑代码端, 比如算法复杂度过高, 优化算法;
- 诺系统 CPU 占用过高: 问题出在系统调用, 比如大量系统调用, 创建子进程等;
- 诺I/O等待 CPU 过高: 问题出在磁盘或网络的读写, 可能是阻塞的方式, 可以改用非阻塞或 I/O 复用的方式优化;
# 更具体地
- 利用 `pidstat -r` 查看进程 内存 分类的占用情况, 定位进程在哪个方面存在问题和瓶颈;
- 利用 `pidstat -d` 查看进程 IO 分类的占用情况, 定位进程在哪个方面存在问题和瓶颈;
- 利用 `pidstat -w` 查看进程 上下文切换 的情况, 定位进程在哪个方面存在问题和瓶颈;
5. 性能统计分析工具 (perf)
# 思路
- 通过不同类型的中断, 来触发计数器进行采样统计的性能分析工具, 具有系统级(top), 进程级(stat), 函数级(record) 三种不同的粒度;
# 触发事件分类
- (硬件)时钟中断, 缺页中断等;
- (软件)上下文切换;
# 分析流程
- 主要可以用时钟中断的方式, 对程序的性能进行分析;
- 首先, 用 `perf top`, 找出占用整个 CPU 时间最多的进程;
- 再用 `perf stat`, 指定该进程, 查找它哪个类型的 CPU 时间占用最多;
- 最后, 用 `perf record`. 进一步找到该进程哪个函数的 CPU 时间占用最多;
其他
1. 文件软硬连接
# 文件存储架构
- 文件路径 : 描述文件对象
- inode表 : 记录文件路径 和 对应的 inode 编号
- metadata : 根据 inode 编号, 可以找到文件元数据信息
- data block : 文件元数据中记录了数据的具体信息, 包括数据块数量和具体存放位置
# 硬连接
- ln a b
- 多个文件名 指向 一个文件 来解决源文件共享的问题
- 存在问题: 无法跨分区创建链接
# 软连接
- ln -s a b
- 独立文件, 包含文件名称, inode 编号, metadata 数据, block
- block 中存放的数据是 被链接文件的指向
2. 僵尸进程排查
# Kill 父进程
- 找到父进程, 然后把它杀死;
- 僵尸进程自动过继给 init 进程, 由其杀死;
# 修改代码
- 在代码中定位 fork 函数, 或者是其他可能产生子进程的函数;
- 检查产生子进程后, 是否调用 wait 函数将其资源作回收;
3. 内存泄露排查
# 智能指针
- 使用智能指针代替普通指针;
- 完成对象资源的自动回收;
# 自定义对象计数器
- 在类中定义计数器变量;
- 在类对象构造时, 计数器++. 类对象析构时, 计数器--;
- 定时打印类对象名称和数量, 诺发现有类对象的数量一直增长, 就说明它有内存泄露的问题;
4. make 和 makefile
# make
- 用于实现大型 C++ 项目的 ‘自动化编译’;
- 主要通过编写 makefile 文件, 确定文件的依赖关系和文件编译的先后顺序, 然后直接通过 make 命令生成可持续文件;
# makefile 编写规则
- all: tag1 tag2 ...
* 执行 make 后编译的标签清单;
- tag1: file1 file2 ...
* 依赖于标签 tag1 的源文件, 如果依赖的源文件内容发生了变化,再次执行 make 的时候就会重新编译 tag1;
- [tab] gcc -o ...
* 编译命令,和在操作系统命令行输入的命令一样,但前面要用 tab 空开, 可以输入多行命令;
- clean:
cmd1 ...
* clean 不依赖于任何文件;
* 使用 make clean 执行的命令, 可以省略;
# 变量
- 设置: CC=gcc
- 使用: $(CC)
- 好处
* 让文件更加简洁;
* 便于修改, 只要修改变量的设定, 就可以改变全局;
#