Linux性能优化-CPU使用率

 

Linux作为一个多任务操作系统,将每个CPU的时间划分成很短的时间片,再通过调度器轮流分配给各个任务使用,因此造成了多个任务同时运行的错觉
为了维护CPU时间,Linux通过实现定义的节拍率(内核中表示为HZ),触发时间中断,并使用全局变量Jiffies记录了开机以来的节拍数,每发生一次时间中断,Jiffies的值就加1
节拍率HZ是内核的可配选项,可以设置为100,250,1000等,不同的系统可能设置不同数值,你可以通过查询
/boot/config 内核选项来查看他的配置值,
比如下面这个,就是每秒有1000个次的时间中断

cat /boot/config-3.10.0-514.16.1.el7.x86_64 | grep HZ
CONFIG_NO_HZ_COMMON=y
# CONFIG_HZ_PERIODIC is not set
# CONFIG_NO_HZ_IDLE is not set
CONFIG_NO_HZ_FULL=y
# CONFIG_NO_HZ_FULL_ALL is not set
CONFIG_NO_HZ=y
# CONFIG_RCU_FAST_NO_HZ is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_MACHZ_WDT=m

这个节拍率HZ是内核选项,所以用户空间程序并不能直接访问,为了方便用户空间程序,内核还提供了一个用户空间节拍率 USER_HZ,它总是固定为100,也就是1/100秒

 


Linux通过/proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,而 /proc/stat 提供的就是系统的CPU和任务统计信息,如果只关注CPU的话,可以执行下面命令

CPU      user%           nice%   system%  idle%              iowait%  irq%    softirq%  steal%  guest_nice%
cpu     46690956        1395    2756716 1100812644      62551   933     216878  35728   0
cpu0    11685110        348     676302  275161847       2032    179     80539   19513   0
cpu1    11655846        375     624830  275424074       1597    65      6651    2351    0
cpu2    11648679        337     680955  275312231       16027   222     36922   3776    0
cpu3    11701320        334     774627  274914491       42894   465     92765   10087   0

每一列的含义如下
1.user(缩写us),表示用户态CPU时间,不包括下面的nice时间,但包括了guest时间
2.nice(缩写ni),表示低优先级用户态CPU时间,进程nice值为1-19之间的CPU时间,-20(最高)到19(最底)
3.sysem(sys),代表内核态CPU时间
4.idle(id)代表空闲时间,但不包括等待I/O的时间
5.iowait(wa),代表等待I/O的CPU时间
6.irq(hi),代表处理硬件中断的CPU时间
7.softirq(si),代表处理软中断的CPU时间
8.steal(st),代表系统运行在虚拟机中的时候,被其他虚拟机占用的CPU时间
9.guest(guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的CPU时间
10.guest_nice(gnice),代表以低优先运行虚拟机的时间

我们通常所说的CPU使用率,是除了空闲时间外的其他时间占总CPU时间的百分比,用公式来表示为

根据这个公式,我们就可以从/proc/stat中的数据,计算出CPU使用率,
这个文件中的值就是开机以来的节拍数累加值,直接算出来的,是开机以来的平均CPU使用率
为了计算CPU使用率,性能工具一般都会取间隔一段时间(如3秒)的两次值,做差之后,再计算这段时间内的平均CPU使用率,公式如下

除了/proc/stat,还有/proc/[PID]/stat 这个文件
这两个文件都会被各种系统性能分析工具读取并解析,所以这两个工具是系统指标的来源
性能分析工具给出的都是一段时间的平均CPU使用率,所以要注意间隔时间的设置,特别是用多个工具对比分析时,一定要保证他们用的是相同的间隔时间
比如top默认使用3秒时间间隔,而ps使用的是整个进程的生命周期
 

除了/proc/stat,还有/proc/[PID]/stat 这个文件
这两个文件都会被各种系统性能分析工具读取并解析,所以这两个工具是系统指标的来源
性能分析工具给出的都是一段时间的平均CPU使用率,所以要注意间隔时间的设置,特别是用多个工具对比分析时,一定要保证他们用的是相同的间隔时间
比如top默认使用3秒时间间隔,而ps使用的是整个进程的生命周期


top显示了系统总体的CPU和内存使用情况,以及各个进程的资源使用情况
ps 则只显示了每个进程的资源使用情况
top的第三行就是CPU的各个指标的使用率情况
pidstat命令显示每个进程的CPU使用率情况

 


GDB(The GUN Project Debugger),是一个程序调试工具,在调试程序错误方面很强大,但在调试程序的过程中会中断程序运行,在线上环境就不合适了,只适用于性能分析的后期,找到问题的大致函数后,线下再借助这个工具来进一步调试函数内部的问题
perf比较适合在线上环境做性能分析,它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定营业程序的性能问题
比如perf top,类似top,能显示占用CPU始终最多的函数或指令,因此可以用来查找热点函数

Samples: 555  of event 'cpu-clock', Event count (approx.): 112367154                                                                                                    
Overhead  Shared Object            Symbol                                                                                                                               
   8.01%  [kernel]                 [k] vsnprintf
   4.28%  libc-2.17.so             [.] __strcmp_sse42
   3.75%  [kernel]                 [k] format_decode
   3.58%  [kernel]                 [k] __memcpy
   3.58%  [kernel]                 [k] kallsyms_expand_symbol.constprop.1
   3.07%  perf                     [.] 0x00000000000c53b4
   2.85%  [kernel]                 [k] _raw_spin_unlock_irqrestore
   2.73%  perf                     [.] __dso__load_kallsyms
   2.44%  perf                     [.] rb_next
   2.38%  perf                     [.] hex2u64
   2.10%  [kernel]                 [k] finish_task_switch
   1.87%  [kernel]                 [k] module_get_kallsym
   1.87%  [kernel]                 [k] number.isra.2
   1.70%  [kernel]                 [k] strnlen
   1.70%  libc-2.17.so             [.] _IO_getdelim
   1.70%  libc-2.17.so             [.] __memcpy_sse2
   1.57%  libc-2.17.so             [.] _int_malloc
   1.56%  libc-2.17.so             [.] __strchr_sse42
   1.54%  libc-2.17.so             [.] __memcpy_ssse3_back
   1.53%  perf                     [.] 0x00000000000c53c7
   1.42%  [kernel]                 [k] tick_nohz_idle_enter
   1.36%  [kernel]                 [k] string.isra.7
   1.27%  libpthread-2.17.so       [.] pthread_rwlock_unlock
   1.19%  [kernel]                 [k] pointer.isra.19
   1.07%  perf                     [.] rb_insert_color
   1.02%  libc-2.17.so             [.] __strlen_sse2_pminub
   0.86%  [kernel]                 [k] run_timer_softirq
   0.73%  libpthread-2.17.so       [.] pthread_rwlock_rdlock
   0.73%  perf                     [.] __symbols__insert
   0.71%  libc-2.17.so             [.] __memset_sse2
   0.68%  [kernel]                 [k] strlcpy
   0.68%  libc-2.17.so             [.] _IO_feof
   0.68%  libc-2.17.so             [.] memchr
   0.68%  libpthread-2.17.so       [.] pthread_mutex_init
   0.68%  perf                     [.] rb_erase
   0.67%  libc-2.17.so             [.] _int_free
   0.62%  libelf-0.168.so          [.] gelf_getsym
   0.62%  perf                     [.] symbols__insert
   0.61%  [kernel]                 [k] __do_softirq
   0.61%  [kernel]                 [k] rcu_gp_kthread
   0.56%  [kernel]                 [k] mem_cgroup_charge_common
   0.56%  perf                     [.] dso__load_sym
   0.51%  [kernel]                 [k] __x86_indirect_thunk_rax
   0.51%  [kernel]                 [k] clear_page_c_e

输出结果中,第一行包含三个数据
分别是采样数(Samples),时间类型(event)和事件总数量(Event count)
这里的采样了555个CPU时钟事件,事件总数是112367154个,如果采样数过少(只有十几个)那么排序和百分比意义就不大了
再往下看是一个表格样式数据,每一行包含四列,分别是
1.Overhead, 是该符号的性能事件在所有采样中的比例,用百分比来表示
2.Shared,   是该函数或指令所在的动态共享对象(Dynamic Shared Object)如内核,进程名,动态链接库
  的名字,内核模块名字等
3.Object,   是动态共享对象的类型,比如[.]表示用户空间的可执行程序,或动态链接库,而[k]表示
   内核空间
4.Symbol,   是符号名,也就是函数名,当函数名未知时,用16进制的地址来表示
perf工具本身也会占用一定的CPU

perf top虽然实时展示了系统的性能信息,但他的缺点是并不保存数据,也就无法用于离线或后续分析,使用
perf record 保存数据,perf report用于后续解析展示

用perf top分析进程的调用栈,但这种方式只适应于c,php等程序,对java并不合适

top -g -p 6492
Samples: 437  of event 'cpu-clock', Event count (approx.): 109250000 
Children      Self  Shared Object  Symbol                                                                                                                            ?-  100.00%   100.00%  d              [.] d
__libc_start_main
     main
     a
     b
     c
     d
......


//选择d
Annotate d
?Zoom into d DSO
?Browse map details
?Exit


3a8  400 g _init
? 3e0  3f0 g __libc_start_main@plt
? 3f0  400 g __gmon_start__@plt
? 400  430 g _start
??30  460 l deregister_tm_clones
 460  4a0 l register_tm_clones
 4a0  4c0 l __do_global_dtors_aux
 4c0  4ed l frame_dummy
 4ed  4f3 g d 
 4f3  503 g c
 503  513 g b 513  523 g a
 523  538 g main
 540  5a5 g __libc_csu_init
 5b0  5b2 g __libc_csu_fini
??b4 2000 g _fini     

关于CPU使用率要关注
用户,nice,系统,等待I/O,中断,软中断,这几个不同的CPU使用率,还要注意
1.用户CPU和nice高,说明用户态进程占用了较多的CPU,应该排查进程的性能问题
2.系统CPU高,说明内核态占用了较多的CPU,应该排查内核线程或者系统调用的性能问题
3.I/O等待CPU高,说明等待I/O的时间比较长,应该排查系统存储是不是出现了I/O问题
4.软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的CPU,应该排查内核中的中断服务程序
配合top,ps,mpstat,pidstat,vmstat,再结合perf等工具分析

 

碰到常规问题无法解释的CPU使用率情况时,首先要想到的可能是短时应用导致的问题
1.应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,用top等工具也不容易发现
2.应用本身因为段错误,配置挫等,在不停的时候,但进程退出后又被监控系统自动重启了

使用execsnoop 来监控这种行为,他通过ftrace实时监控进程的exec行为,并输出短时进程的基本信息,包括
  pid,父进程id,命令行擦拿上及执行结果等

利用 execsnoop 监控结果(自己写了程序不断fork->exec)

./execsnoop.sh 
Tracing exec()s. Ctrl-C to end.
Instrumenting sys_execve
   PID   PPID ARGS
  7935   7931 gawk -v o=1 -v opt_name=0 -v name= -v opt_duration=0 [...]
  7936   7934 cat -v trace_pipe
  7937   7589 ./fork
  8037   7937 fork [?]
  8020   7937 fork [?]
  8034   7937 fork [?]
  8033   7937 fork [?]
  8017   7937 fork [?]
  7998   7937 fork [?]
.......

 

 

参考

CONFIG_HZ 和 USER_HZ

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值