Linux 性能分析

cpu 使用分析

top 命令

1
procps-ng-top -H -p 899 -w 120
  • -H 是线程模式
  • -p 指定进程 id
  • -w 指定显示宽度(列数)
  • -d 指定延时 ,屏幕更新间隔

shift+p 按照 cpu 使用率对线程排序。如下是一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procps-ng-top - 10:11:13 up  1:00,  0 users,  load average: 3.90, 4.10, 3.89
Threads: 81 total, 0 running, 81 sleeping, 0 stopped, 0 zombie
%Cpu0 : 46.6/30.7 77[||||||||||||||||||||||||||||||||||||||||| ]
GiB Mem : 84.5/0.239 [ ]
GiB Swap: 0.0/0.000 [ ]

PID USER PR NI VIRT RES %CPU %MEM TIME+ S COMMAND
915 root 20 0 191.4m 174.1m 13.7 71.2 8:33.07 S VIChnDMS
890 root 20 0 191.4m 174.1m 10.9 71.2 6:11.33 S isp_yhread
869 root 20 0 191.4m 174.1m 9.7 71.2 5:36.66 S app
1163 root 20 0 191.4m 174.1m 4.0 71.2 2:32.27 S AEncComp
1158 root 20 0 191.4m 174.1m 3.4 71.2 2:16.15 S RecSink[0]
1145 root -21 0 191.4m 174.1m 2.3 71.2 1:01.76 S VEncComp
1154 root 20 0 191.4m 174.1m 1.7 71.2 1:15.99 S MuxerComp
1170 root 20 0 191.4m 174.1m 1.7 71.2 0:55.57 S RecSink[0]
1146 root -21 0 191.4m 174.1m 1.7 71.2 1:16.99 S VEncComp
1139 root 20 0 191.4m 174.6m 1.1 71.4 0:23.14 S CDX_VRender
1166 root 20 0 191.4m 174.1m 1.1 71.2 0:49.78 S MuxerComp
1155 root 20 0 191.4m 174.1m 1.1 71.2 0:53.52 S RecSink[0]
1134 root 20 0 191.4m 174.6m 1.1 71.4 0:28.99 S CDX_VRender
1161 root 20 0 191.4m 174.1m 1.1 71.2 0:48.20 S recordThread
1141 root -21 0 191.4m 174.1m 1.1 71.2 0:45.83 D VEncComp
926 root 20 0 191.4m 174.1m 1.1 71.2 0:42.77 S app
885 root 20 0 191.4m 174.1m 0.6 71.2 0:27.83 S VIChnPreview

第一行任务队列信息:

  • 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
    3
    make menuconfig -->
    Development -->
    <*> gdb------------------- GNU Debugger

  • 配置 coredump:
    程序运行过程中遇到异常终止或崩溃,操作系统会保存一个文件到本地目录,这个文件就是 coredump 文件,选中工具:

    1
    2
    3
    make kernel menuconfig,选中以下配置。
    Userspace binary formats -->
    [*]Enable core dump support

    配置:

    1
    2
    ulimit -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
    11
    Reading 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
    2
    echo 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
2
cat /proc/buddyinfo
Node 0, zone Normal 115 148 72 34 1 0 1 0 1 0 0

参考文献

《全志SDK文档》