【Android Linux內存及性能優化】八 系統性能分析工具
本文接着
《【Android Linux內存及性能優化】(一) 進程內存的優化 - 堆段》
《【Android Linux內存及性能優化】(二) 進程內存的優化 - 棧段 - 環境變量 - ELF》
《【Android Linux內存及性能優化】(三) 進程內存的優化 - ELF執行文件的 數據段-代碼段》
《【Android Linux內存及性能優化】(四) 進程內存的優化 - 動態庫- 靜態庫》
《【Android Linux內存及性能優化】(五) 進程內存的優化 - 線程》
《【Android Linux內存及性能優化】(六) 系統內存的優化》
《【Android Linux內存及性能優化】(七) 程序內存泄漏檢查工具》
二、系統性能分析
2.1 性能分析
程序性能的問題,有很多原因,需要對症下藥。
導致軟件性能低下,主要有下面3種原因:
-
程序的運算量很大,導致CPU 過於繁忙,CPU 是瓶頸。
可以運行 top 命令,如果某個進程的CUP 利用率很高,則說明CPU 是性能瓶頸。 -
程序需要大量的I/O ,讀寫文件、內存操作等,CPU 更多的是處於等待,I/O 部分成爲程序性能瓶頸。
對於大量I/O 引起的程序性能問題,可以學習這篇文章: 《使用異步 I/O 大大提高應用程序的性能》 -
程序之間相互等待,結果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 softirq
cpu 3167348 29348 1381731 80468196 1075970 0 101955 0 0 0
cpu0 397571 3476 157335 10150112 70357 0 35871 0 0 0
cpu1 372224 3435 174119 10136025 51305 0 16722 0 0 0
cpu2 418781 3775 195023 10131454 32896 0 7197 0 0 0
cpu3 381767 4442 166107 10172208 33756 0 14511 0 0 0
cpu4 376322 3423 160088 10192147 30325 0 3210 0 0 0
cpu5 388663 3460 158360 10202394 29673 0 4082 0 0 0
cpu6 435006 3761 212003 9410045 713497 0 5559 0 0 0
cpu7 397011 3573 158693 10073807 114157 0 14800 0 0 0
intr 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 1954
ctxt 550116756
btime 1590973874
processes 536879
procs_running 1
procs_blocked 0
softirq 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 負載情況。
從這些數據,可以知道分析性能瓶頸在哪裏:
-
程序代碼有問題,導致佔用了大量的CPU ,可以計算CPU 用戶態利用率
CPU 用戶態利用率 = (user + nice)/(user + system + nice + idle + iowait + irq + softirq)
-
程序代碼調用了大量的系統調用,導致Linux 內核佔用了大量的CPU
CPU 內核態利用率 = (system)/(user + system + nice + idle + iowait + irq + softirq)
-
系統和Flash 、內存等 有大量的交互和等待,從而導致系統性能下降
IO 利用率 = (iowait)/(user + system + nice + idle + iowait + irq + softirq)
2.1.1.2 系統相關 cat /proc/loadavg
ciellee@sh:~$ cat /proc/loadavg
1.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/stat
51 (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:dead
ppid = 2 父進程ID
pgid = 0 線程組號
sid = 0 該任務所在的會話組ID
ttnr = 0 該任務的tty終端的設備號,
tty_pgrp = -1 終端的進程組號,當前運行在該任務所在終端的前臺任務(包括 shell 應用程序)的pid
task->flags = 69238848 進程標誌位,查看該任務的特性
min_flt = 0 該任務不需要從硬盤拷數據而發生的缺頁(次缺頁)次數
cmin_flt = 0 累計的該任務的所有的waited-for 進程曾經發生的次缺頁的數目
maj_flt = 0 該任務需要從硬盤拷數據而發生的缺頁(主缺頁)次數
cmaj_flt = 0 累計的該任務的所有的waited-for 進程曾經發生的主缺頁的數目
utime = 0 該任務在用戶態運行的時間,單位爲 jiffy
stime = 11 該任務在覈心態運行的時間,單位爲 jiffy
cutime = 0 累計的該任務的所有的waited-for 進程曾經在用戶態運行的時間,單位爲 jiffy
cstime = 0 累計的該任務的所有的waited-for 進程曾經在覈心態運行的時間,單位爲 jiffy
priority = -100 任務的動態優先級
nice = 0 任務的靜態優先級
num_threads = 1 該任務所在的線程組裏線程的個數
it_real_value = 0 由於計時間隔導致下一個SIGALRM 發送進程的時延,以jiffy 爲單位
start_time = 4 該任務的啓動的時間,單位爲 jiffy
vsize = 0 該任務的虛擬地址空間大小
rss = 0(page) 該任務當前駐留虛擬地址空間的大小
vsize = 18446744073709551615(bytes) 該任務的虛擬空間大小
rss = 0(page) 該任務當前駐留物理地址空間的大小
rlim = 0(bytes) 該任務能駐留物理地址空間的最大值
start_code = 0 該任務在虛擬地址空間的代碼段的起始地址
end_code = 0 該任務在虛擬地址空間的代碼段的結束地址
start_stack = 0 該任務在虛擬地址空間的棧的結束地址
kstkesp = 0 esp(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 st
KiB Mem : 16281312 total, 2675480 free, 2865172 used, 10740660 buff/cache
KiB 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