【linux perf top】如何使用perf top 探究性能

Perf 内置于Linux 内核源码树中的性能剖析工具。它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析。可用于性能瓶颈的查找与热点代码的定位。linux2.6及后续版本都自带该工具,几乎能够处理所有与性能相关的事件。perf top 是比较常用于展示占用CPU始终最多的函数或者指令,一般以此来查找热点函数。

实战

root@xxxx:~# apt install linux-tools-common
root@xxxx:~# perf top

Samples: 6K of event ‘cycles’, 4000 Hz, Event count (approx.): 48144737 lost: 0/0 drop: 0/0
Overhead Shared Object Symbol
3.84% [kernel] [k] native_write_msr
2.25% [kernel] [k] update_blocked_averages
1.89% [kernel] [k] update_sd_lb_stats.constprop.0
1.80% [kernel] [k] pvclock_clocksource_read

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Samples : 采样数, perf 总共采集了 6K 个 CPU 时钟事件。

event : 事件类型。

Event count (approx.) : 事件总数量

行列:

Overhead: 是该符号的性能事件在所有采样中的比例,用百分比来表示。

Shared: Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。

Object: Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。

Symbol: Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

上面结果显示内核模块中native_write_msr 占用 CPU时钟最多,比列占3.84%。

同样可以使用perf record 与 perf report 进行定时采集再展示。加上 -g 参数,开启调用关系的采样,方便我们根据调用链来分析性能问题。

root@xxxx:~# perf record
^C //(结束采集)
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.967 MB perf.data (739 samples) ]

root@xxxx:~# perf report

Samples: 739 of event ‘cycles’, Event count (approx.): 22853303
Overhead Command Shared Object Symbol
4.38% swapper [kernel.kallsyms] [k] native_write_msr
4.04% swapper [kernel.kallsyms] [k] native_safe_halt
3.26% swapper [kernel.kallsyms] [k] update_blocked_averages
2.63% swapper [kernel.kallsyms] [k] pvclock_clocksource_read
2.07% swapper [kernel.kallsyms] [k] update_sd_lb_stats.constprop.0
1.94% swapper [kernel.kallsyms] [k] rcu_cblist_dequeue
1.79% swapper [kernel.kallsyms] [k] _raw_spin_lock_irqsave
1.76% swapper [kernel.kallsyms] [k] ktime_get

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

利用 Nginx PHP做演示

root@xxxx:~# docker run --name nginx -p 10000:80 -itd feisky/nginx
root@xxxx:~# docker run --privileged --name phpfpm -itd --network container:nginx feisky/php-fpm

root@xxxx:~# curl http://localhost:10000/
It works!

  • 1
  • 2
  • 3
  • 4
  • 5

接着,我们来测试一下这个 Nginx 服务的性能。在第二个终端运行下面的 ab 命令:

root@xxxx:~# ab -c 10 -n 100 http://localhost:10000/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done

Server Software: nginx/1.15.4
Server Hostname: localhost
Server Port: 10000

Document Path: /
Document Length: 9 bytes

Concurrency Level: 10
Time taken for tests: 1.188 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 17200 bytes
HTML transferred: 900 bytes
Requests per second: 84.14 [#/sec] (mean)
Time per request: 118.849 [ms] (mean)

Time per request: 11.885 [ms] (mean, across all concurrent requests)
Transfer rate: 14.13 [Kbytes/sec] received

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

从 ab 的输出结果我们可以看到,Nginx 能承受的每秒平均请求数只有 84.14。

继续在第二个终端,运行 ab 命令:

root@xxxx:~# ab -c 10 -n 10000 http://localhost:10000/

 
 
  • 1

接着,回到第一个终端使用docker exec 指令进入容器,然后运行 top 命令,并按下数字 1 ,切换到每个 CPU 的使用率:

top - 17:50:45 up 21:25,  3 users,  load average: 1.11, 0.27, 0.12
Tasks: 243 total,   6 running, 237 sleeping,   0 stopped,   0 zombie
%Cpu0  : 98.0 us,  1.7 sy,  0.0 ni,  0.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 98.7 us,  1.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 99.0 us,  0.7 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
%Cpu3  : 99.0 us,  1.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   7961.2 total,   4756.2 free,    993.1 used,   2211.9 buff/cache
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   6669.1 avail Mem

// 在容器内部top
KiB Swap: 2097148 total, 2097148 free, 0 used. 6706484 avail Mem
Unknown command - try ‘h’ for help
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
552 daemon 20 0 336700 15420 7744 R 93.3 0.2 0:04.42 php-fpm
553 daemon 20 0 336700 15420 7744 R 86.7 0.2 0:04.14 php-fpm
555 daemon 20 0 336700 15420 7744 R 86.7 0.2 0:03.55 php-fpm
551 daemon 20 0 336700 15420 7744 R 53.3 0.2 0:03.78 php-fpm
554 daemon 20 0 336700 15420 7744 R 46.7 0.2 0:04.51 php-fpm
1 root 20 0 336316 47672 40276 S 0.0 0.6 0:00.31 php-fpm
7 root 20 0 18196 3416 2872 S 0.0 0.0 0:00.00 bash
556 root 20 0 43152 3260 2768 R 0.0 0.0 0:00.00 top

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这里可以看到,系统中有几个 php-fpm 进程的 CPU 使用率加起来接近 400%;而每个 CPU 的用户使用率(us)也已经超过了 98%,接近饱和。这样,我们就可以确认,正是用户空间的 php-fpm 进程,导致 CPU 使用率骤升。那再往下走,怎么知道是 php-fpm 的哪个函数导致了 CPU 使用率升高呢?我们来用 perf 分析一下。

root@xxxx:~# docker exec -i -t phpfpm bash // 进入容器

//容器内部
root@xxxx:~# apt-get update && apt-get install -y linux-perf linux-tools procps
root@xxxx:~# perf top -g -p 555

  • 1
  • 2
  • 3
  • 4
  • 5

按方向键切换到 php-fpm,再按下回车键展开 php-fpm 的调用关系,你会发现,调用关系最终到了 sqrt 和 add_function。看来,我们需要从这两个函数入手了。

我们拷贝出 Nginx 应用的源码,看看是不是调用了这两个函数:

//从容器phpfpm中将PHP源码拷贝出来
root@xxxx:~# docker cp phpfpm:/app .

//使用grep查找函数调用
root@xxxx:~# grep sqrt -r app/
app/index.php: x < s p a n c l a s s = " t o k e n o p e r a t o r " > + = < / s p a n > < s p a n c l a s s = " t o k e n f u n c t i o n " > s q r t < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > x <span class="token operator">+=</span> <span class="token function">sqrt</span><span class="token punctuation">(</span> x<spanclass="tokenoperator">+=</span><spanclass="tokenfunction">sqrt</span><spanclass="tokenpunctuation">(</span>x);

root@xxxxx:~# cat app/index.php
<?php
// test only.
x < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n n u m b e r " > 0.0001 < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ; < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > f o r < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > x <span class="token operator">=</span> <span class="token number">0.0001</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> x<spanclass="tokenoperator">=</span><spanclass="tokennumber">0.0001</span><spanclass="tokenpunctuation">;</span><spanclass="tokenkeyword">for</span><spanclass="tokenpunctuation">(</span>i = 0; $i <= 1000000; $i++) {
x < s p a n c l a s s = " t o k e n o p e r a t o r " > + = < / s p a n > < s p a n c l a s s = " t o k e n f u n c t i o n " > s q r t < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > x <span class="token operator">+=</span> <span class="token function">sqrt</span><span class="token punctuation">(</span> x<spanclass="tokenoperator">+=</span><spanclass="tokenfunction">sqrt</span><spanclass="tokenpunctuation">(</span>x);
}

echo “It works!”
?>root

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看得出这段测试代码导致运行速度变慢。

# 停止原来的应用
root@xxxx:~# docker rm -f nginx phpfpm
# 运行优化后的应用
root@xxxx:~# docker run --name nginx -p 10000:80 -itd feisky/nginx:cpu-fix
root@xxxx:~# docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:cpu-fix

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

删除测试代码后再次编译运行。

$ ab -c 10 -n 10000 http://localhost:10000/
...
Complete requests:      10000
Failed requests:        0
Non-2xx responses:      10000
Total transferred:      3030000 bytes
HTML transferred:       1530000 bytes
Requests per second:    12273.25 [#/sec] (mean)
Time per request:       0.815 [ms] (mean)
Time per request:       0.081 [ms] (mean, across all concurrent requests)
Transfer rate:          3631.64 [Kbytes/sec] received

...

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

从这里你可以发现,现在每秒的平均请求数,已经从原来的 84.14 变成了 12273.25

1.用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。

2.系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。

3.I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。

4.软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的 CPU,所以应该着重排查内核中的中断服务程序。

结束语

碰到 CPU 使用率升高的问题,你可以借助 top、pidstat 等工具,确认引发 CPU 性能问题的来源;再使用 perf 等工具,排查出引起性能问题的具体函数。

转载于 https://blog.csdn.net/RJ0024/article/details/117551145?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167296784216800182164567%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=167296784216800182164567&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-117551145-null-null.142^v70^control,201^v4^add_ask&utm_term=%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8perf%20top&spm=1018.2226.3001.4187
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值