Linux 性能分析
cpu 使用分析
top 命令
1 | procps-ng-top -H -p 899 -w 120 |
- -H 是线程模式
- -p 指定进程 id
- -w 指定显示宽度(列数)
- -d 指定延时 ,屏幕更新间隔
shift+p 按照 cpu 使用率对线程排序。如下是一个实例:
1 | procps-ng-top - 10:11:13 up 1:00, 0 users, load average: 3.90, 4.10, 3.89 |
第一行任务队列信息:
- 10:11:13 - 当前时间
- up 1:00 - 系统已经运行 1 小时
- 0 users - 当前系统有 0 个用户登录
- load average: 3.90, 4.10, 3.89 - load average 后面的三个数分别是 1 分钟、5 分钟、15 分钟的负载情况。
load average 数据是每隔 5 秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑 CPU 的数量,结果高于 5 的时候就表明系统在超负荷运转了。
第二行 Tasks 或 Thread 信息:
Threads: 81 total - 线程总数 81 个
- 0 running - 当前没有线程在运行
- 81 sleeping - 81 个线程在睡眠
- 0 stopped -stoped 状态的线程为 0 个
- 0 zombie - zombie 状态(僵尸)的有 0 个
第三行 cpu 状态信息:
%Cpu0 46.6/30.7 当前 cpu0 的用户态线程占 cpu46.6%,内核态占 cpu30.7% 如果在 pc 上运行可能是如下信息
Cpu(s): 5.9%us, 3.4%sy, 0.0%ni, 90.4%id, 0.0%wa, 0.0%hi, 0.2%si, 0.0%st
- 5.9%us — 用户空间占用 CPU 的百分比。
- 3.4% sy — 内核空间占用 CPU 的百分比。
- 0.0% ni — 改变过优先级的进程占用 CPU 的百分比
- 90.4% id — 空闲 CPU 百分比
- 0.0% wa — IO 等待占用 CPU 的百分比
- 0.0% hi — 硬中断(Hardware IRQ)占用 CPU 的百分比
- 0.2% si — 软中断(Software Interrupts)占用 CPU 的百分比
第四行内存状态信息:
GiB Mem : 84.5/0.239 - 用户态占内存 84.5%,内核态占内存 0.239%
如果是 pc 上可能是如下信息
Mem: 32949016k total, 14411180k used, 18537836k free, 169884k buffers
- 32949016k total — 物理内存总量(32GB)
- 14411180k used — 使用中的内存总量(14GB)
- 18537836k free — 空闲内存总量(18GB)
- 169884k buffers — 缓存的内存量 (169M)
第五行 swap 交换分区信息:
- GiB Swap: 0.0/0.000 - 当前系统没有使用交换分区
- 如果是 pc 则可能是如下信息
Swap: 32764556k total, 0k used, 32764556k free, 3612636k cached
- 32764556k total — 交换区总量(32GB)
- 0k used — 使用的交换区总量(0K)
- 32764556k free — 空闲交换区总量(32GB)
- 3612636k cached — 缓冲的交换区总量(3.6GB)
第六行空行:
第七行各进程或线程的状态信息:
- PID — 进程 id
- USER — 进程所有者
- PR — 进程优先级
- NI — nice 值。负值表示高优先级,正值表示低优先级
- VIRT — 进程使用的虚拟内存总量,单位 kb。VIRT=SWAP+RES
- RES — 进程使用的、未被换出的物理内存大小,单位 kb。RES=CODE+DATA
- SHR — 共享内存大小,单位 kb
- S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
- %CPU — 上次更新到现在的 CPU 时间占用百分比
- %MEM — 进程使用的物理内存百分比
- TIME+ — 进程使用的 CPU 时间总计,单位 1/100 秒
- COMMAND — 进程名称(命令名/命令行)
perf 工具
查看消耗 cpu 比较高的内核函数或者进程:
1 | pert top |
列出 perf 支持的事件:
1 | perf list |
统计 profiling 进程的各种信息:
1 | perf stat |
profiling 进程的数据,生成 xx.data 文件:
1 | perf record |
读取 xx.data 文件:
1 | perf report |
GDB
打出程序崩溃的调用栈
选中 gdb 工具:
1
2
3make menuconfig -->
Development -->
<*> gdb------------------- GNU Debugger配置 coredump:
程序运行过程中遇到异常终止或崩溃,操作系统会保存一个文件到本地目录,这个文件就是 coredump 文件,选中工具:1
2
3make kernel menuconfig,选中以下配置。
Userspace binary formats -->
[*]Enable core dump support配置:
1
2ulimit -c unlimited //对产生的 coredump 文件大小不做限制
echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern //产生的文件带有崩溃的程序名称以及进程 id运行 app
运行 app 的时候会在/tmp 目录下生成 corexxxxx 文件。获取程序崩溃的调用栈
1
gdb /usr/bin/app /tmp/corexxxx
然后执行 bt 就会打出函数调用栈。
其他命令
frame、x、info、disassemble ...
交叉调试
有时 flash 空间大小不足以装下 gdb,这时需要在 pc 上使用交叉编译工具链中的 gdb 调试,详细过程如下:
- 编译完的固件保存好 app 的 bin 文件,带符号表的那个
- 当应用挂掉后从机器里取出 core 文件,放入 pc 上
- 执行 arm-xxxx-gdb app core-file
设置 sysroot 路径 set sysroot /home/workspace/project/out/project/staging_dir/target/rootfs 得到如下,说明设置成功:
1
2
3
4
5
6
7
8
9
10
11Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/lib/libstdc ++.so.6...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ libasound.so.2...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/libz. so.1...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ eyesee-mpp/libcdx_base.so...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ eyesee-mpp/libcdx_parser.so...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ eyesee-mpp/libcdx_stream.so...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ eyesee-mpp/libcdx_common.so...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/lib/libgcc_s. so.1...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/lib/ ld-musl-armhf.so.1...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ts/ input.so...done.
Reading symbols from /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs/usr/lib/ libts.so.0...done.- 执行 bt 命令,会打出崩溃时的函数调用栈。
- frame n 命令表示在 GDB 下切换到编号为 n 的栈帧 (n 表示一个正整数)。例如,frame 4 将切换到栈的第 5 层。切换完后,如果想查看当前栈帧的编号、函数名、函数参数值、函数所在文件及行号、函数执行到的语句等信息,可直接使用
frame
命令,如下图所示。 info 命令查看当前栈帧的信息,如函数地址、调用函数的地址、被调用函数的地址、当前函数由哪种编程语言编写、函数参数地址及形参值、局部变量的地址等
1
2echo PATH=/home/user/workspace/sdk/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/ toolchain/bin
set sysroot /home/user/workspace/sdk/out/vendor/staging_dir/target/rootfs
内存查看
内存碎片化查看工具
1 | cat /proc/buddyinfo |
参考文献
《全志SDK文档》