【Android Linux内存及性能优化】八 系统性能分析工具

  • 二、系统性能分析
    • 2.1 性能分析
      • 2.1.1 /proc 目录
        • 2.1.1.1 系统相关 cat /proc/stat
        • 2.1.1.2 系统相关 cat /proc/loadavg
        • 2.1.1.3 进程相关 cat /proc/51/stat
        • 2.1.1.4 进程相关 top

本文接着
《【Android Linux内存及性能优化】(一) 进程内存的优化 - 堆段》
《【Android Linux内存及性能优化】(二) 进程内存的优化 - 栈段 - 环境变量 - ELF》
《【Android Linux内存及性能优化】(三) 进程内存的优化 - ELF执行文件的 数据段-代码段》
《【Android Linux内存及性能优化】(四) 进程内存的优化 - 动态库- 静态库》
《【Android Linux内存及性能优化】(五) 进程内存的优化 - 线程》
《【Android Linux内存及性能优化】(六) 系统内存的优化》
《【Android Linux内存及性能优化】(七) 程序内存泄漏检查工具》

二、系统性能分析

2.1 性能分析

程序性能的问题,有很多原因,需要对症下药。
导致软件性能低下,主要有下面3种原因:

  1. 程序的运算量很大,导致CPU 过于繁忙,CPU 是瓶颈。
    可以运行 top 命令,如果某个进程的CUP 利用率很高,则说明CPU 是性能瓶颈。

  2. 程序需要大量的I/O ,读写文件、内存操作等,CPU 更多的是处于等待,I/O 部分成为程序性能瓶颈。
    对于大量I/O 引起的程序性能问题,可以学习这篇文章: 《使用异步 I/O 大大提高应用程序的性能》

  3. 程序之间相互等待,结果CPU 利用率很低,但运行速度依然很慢,程序间的共享与死锁制约了程序的性能。
    如果系统的CPU 利用率并不高,而且也不存在大量的I/O 操作,那么很有可能是多个线程之间相互等待造成的,这时就需要对程序进行大规模的重构。


2.1.1 /proc 目录

通过proc 目录,能够了解到CPU 和I/O 设备的工作状况,从而能够帮助分析导致程序性能低下的原因。


2.1.1.1 系统相关 cat /proc/stat

ciellee@sh:~$ cat /proc/stat 累计时间  user  nice system   idle   iowait  irq  softirqcpu  3167348 29348 1381731 80468196 1075970 0 101955 0 0 0cpu0 397571 3476 157335 10150112 70357 0 35871 0 0 0cpu1 372224 3435 174119 10136025 51305 0 16722 0 0 0cpu2 418781 3775 195023 10131454 32896 0 7197 0 0 0cpu3 381767 4442 166107 10172208 33756 0 14511 0 0 0cpu4 376322 3423 160088 10192147 30325 0 3210 0 0 0cpu5 388663 3460 158360 10202394 29673 0 4082 0 0 0cpu6 435006 3761 212003 9410045 713497 0 5559 0 0 0cpu7 397011 3573 158693 10073807 114157 0 14800 0 0 0intr 185329212 9 479 0 0 0 0 0 0 1 5007429 0 0 0 0 0 0 0 60384 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1954ctxt 550116756btime 1590973874processes 536879procs_running 1procs_blocked 0softirq 198450776 16075871 60900311 42960 3505868 1818711 0 1749208 63006387 0 51351460

CPU 后面数值分别代表着CPU 在不同状态下所用的时间,其单位为 jiffy (0.01s),7个数值的含义分别是:

  • user :从系统启动开始累计到当前的时间,用户态的CPU 时间,不包含 nice 值为负的进程。
  • nice :从系统启动开始累计到当前时刻,nice 值为负的进程所占用的CPU 时间。
  • system :从系统启动开始累计到当前时刻,内核所占用的CPU 时间
  • idle :从系统启动开始累计到当前时刻,除硬盘 IO 等待时间以外其他等待时间。
  • iowait :比系统启动开始累计到当前时刻,硬盘IO 等待时间。
  • irq :从系统启动开始累计到当前时刻,硬中断时间。
  • softirq :从系统启动开始累计到当前时刻,软中断时间。

由此可以推导出:
CPU 时间 = user + nice + idle + iowait + irq + softirq
CPU 的利用率 = 1 - (idle)/(user + system + nice + iowait + irq + softirq)

根据CPU 的利用率,可以知道当前系统的CPU 负载情况。

从这些数据,可以知道分析性能瓶颈在哪里:

  1. 程序代码有问题,导致占用了大量的CPU ,可以计算CPU 用户态利用率
    CPU 用户态利用率 = (user + nice)/(user + system + nice + idle + iowait + irq + softirq)

  2. 程序代码调用了大量的系统调用,导致Linux 内核占用了大量的CPU
    CPU 内核态利用率 = (system)/(user + system + nice + idle + iowait + irq + softirq)

  3. 系统和Flash 、内存等 有大量的交互和等待,从而导致系统性能下降
    IO 利用率 = (iowait)/(user + system + nice + idle + iowait + irq + softirq)


2.1.1.2 系统相关 cat /proc/loadavg

ciellee@sh:~$ cat /proc/loadavg1.97 2.14 1.74 2/1048 6774上面数字中:1.97 :1分钟平均负载2.14 :5分钟平均负载1.74 :15分钟平均负载2:在采样时刻,运行队列的任务的数量,与/proc/stat 的procs_running 表示相同意思1048 :在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务)6774:最大的 PID 值,包括轻量级进程,即线程

2.1.1.3 进程相关 cat /proc/51/stat

ciellee@sh:~$ cat /proc/51/stat51 (migration/7) S 2 0 0 0 -1 69238848 0 0 0 0 0 11 0 0 -100 0 1 0 4 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 7 99 1 0 0 0 0 0 0 0 0 0 0 0每个参数解析如下;pid = 50 进程(线程)pid号comm = migration应用程序或命名的名字task_state=S任务的状态:R:running,S:sleeping,D:disk sleep,  T:stopped,T:tracing stop,Z:zombie,X:deadppid = 2父进程IDpgid = 0线程组号sid = 0该任务所在的会话组IDttnr = 0该任务的tty终端的设备号,tty_pgrp = -1 终端的进程组号,当前运行在该任务所在终端的前台任务(包括 shell 应用程序)的pidtask->flags = 69238848进程标志位,查看该任务的特性min_flt = 0该任务不需要从硬盘拷数据而发生的缺页(次缺页)次数cmin_flt = 0累计的该任务的所有的waited-for 进程曾经发生的次缺页的数目maj_flt = 0该任务需要从硬盘拷数据而发生的缺页(主缺页)次数cmaj_flt = 0累计的该任务的所有的waited-for 进程曾经发生的主缺页的数目utime = 0该任务在用户态运行的时间,单位为 jiffystime = 11该任务在核心态运行的时间,单位为 jiffycutime = 0 累计的该任务的所有的waited-for 进程曾经在用户态运行的时间,单位为 jiffycstime = 0累计的该任务的所有的waited-for 进程曾经在核心态运行的时间,单位为 jiffypriority = -100任务的动态优先级nice = 0任务的静态优先级num_threads = 1该任务所在的线程组里线程的个数it_real_value = 0由于计时间隔导致下一个SIGALRM 发送进程的时延,以jiffy 为单位start_time = 4该任务的启动的时间,单位为 jiffyvsize = 0该任务的虚拟地址空间大小rss = 0(page)该任务当前驻留虚拟地址空间的大小vsize = 18446744073709551615(bytes)该任务的虚拟空间大小rss = 0(page)该任务当前驻留物理地址空间的大小rlim = 0(bytes)该任务能驻留物理地址空间的最大值start_code = 0该任务在虚拟地址空间的代码段的起始地址end_code = 0该任务在虚拟地址空间的代码段的结束地址start_stack = 0该任务在虚拟地址空间的栈的结束地址kstkesp = 0esp(32位堆栈指针)的当前值,与在进程的内核堆栈页得到的一致kstkeip = 0指向将要执行的指令的指针,EIP(32位指令指针)的当前值pendingsig = 2147483647待处理信号的位图,记录发产送给进程的普通信号block_sig = 0阻塞信号的位图sigign = 0忽略的信号的位图sigcatch = 0被俘获的信号的位图wchan = 0如果该进程是睡眠状态,该值给出调度的调用点nswap = 17被 swapped 的页数,当前没用cnswap = 7所有子进程被swapped 的页数和,当前没用exit_signal = 99该进程结束时,向父进程所发送的信号task_cpu(task) = 1运行在哪个CPU 上task_rt_priority = 0实时进程的相对优先级别task_policy = 0进程的调度策略,0:非实时进程,1:FIFO实时进程,2:RR实时进程

通过文件stat 的utime, stime, cutime 和 cstime 的数值,能够计算出进程的CPU 占用率。

要想获得CPU 占用率,需要两个采样点:
采样点1: 系统时间记为 sys1, 进程时间分别为:utime1,stime1,cutime1,cstime1
采样点2: 系统时间记为 sys2, 进程时间分别为:utime2,stime2,cutime2,cstime2

进程CPU 占用率 = ( (utime2 + stime2 - cutime2 - stime2) - (utime1 + stime1 - cutime1 - stime1) ) / (sys2 - sys1)
进程用户态占用率 = ( (utime2 - cutime2) - (utime1 - cutime1) ) / (sys2 - sys1)
进程内核态占用率 = ( (stime2 - stime2) - (stime1 - stime1) ) / (sys2 - sys1)


2.1.1.4 进程相关 top

top 是最常用来监控系统范围内进程活动的工具,它提供运行在系统上的与CPU 关系最密切的进程列表,以及许多有意义的统计值(如负载平均,进程数量 以及 使用的 存储器和页面空间的数量)。

Tasks: 302 total,   1 running, 229 sleeping,   0 stopped,   0 zombie%Cpu(s):  3.7 us,  1.6 sy,  0.0 ni, 93.2 id,  1.3 wa,  0.0 hi,  0.1 si,  0.0 stKiB Mem : 16281312 total,  2675480 free,  2865172 used, 10740660 buff/cacheKiB Swap: 16605180 total, 16598768 free,     6412 used. 12037752 avail Mem   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                            3571 ciellee   20   0 2139236 191748  40460 S  23.5  1.2  96:04.80 compiz                                                                             1141 root      20   0  580232 185248 137744 S  17.6  1.1  41:17.93 Xorg                                                                               3315 ciellee   20   0  827724 302988  15876 S  11.8  1.9   1:40.13 hud-service                                                                        3515 ciellee   20   0 2036500 104556  49964 S  11.8  0.6   1:17.75 nautilus                                                                           2521 ciellee   20   0 2951112 209128  36744 S   5.9  1.3 112:49.49 WeChat.exe                                                                         3270 ciellee   20   0  516464  48528  18988 S   5.9  0.3   0:23.38 bamfdaemon                                                                         3341 ciellee   20   0  704340 120900  24328 S   5.9  0.7   7:01.88 unity-panel-ser                                                                   24020 ciellee   20   0   24928   4140   3404 R   5.9  0.0   0:00.03 top                                                                                   1 root      20   0  175892   5764   3220 S   0.0  0.0   0:03.46 systemd                                                                               2 root      20   0       0      0      0 S   0.0  0.0   0:00.13 kthreadd                                                                              4 root       0 -20       0      0      0 I   0.0  0.0   0:00.00 kworker/0:0H                                                                          6 root       0 -20       0      0      0 I   0.0  0.0   0:00.00 mm_percpu_wq

更多相关文章

  1. 解开Android应用程序组件Activity的"singleTask"之谜(2)
  2. INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
  3. Android(安卓)进程回收之LowMemoryKiller原理篇
  4. Android开发这么久你竟然还不知道Dropbox?
  5. Android(安卓)Container原理分析
  6. AndroidManifest.xml文件剖析 (二)
  7. android中使用adb shell命令kill掉应用程序
  8. 微信小程序性能分析Trace工具
  9. android L 启动流程

随机推荐

  1. android Handler 介绍
  2. 吹雪花demo,学习android传感器《IT蓝豹》
  3. 创建android文件系统(Root file system)
  4. 【Android(安卓)应用开发】 Android(安卓
  5. Android(安卓)安装卸载程序
  6. Android(安卓)splitActionBarWhenNarrow
  7. Android(安卓)自定义View及其在布局文件
  8. android开发每日汇总【2011-10-31】
  9. Android的源代码结构
  10. Android(安卓)Fragment 实例