1、前言
很多時候在使用APP的時候债查,手機可能會發(fā)熱發(fā)燙。這是因為CPU使用率過高盹廷,CPU過于繁忙,會使整個手機無法響應(yīng)用戶俄占,整體性能降低,用戶體驗就會很差,也容易引起ANR等等一系列問題吭敢。以下會根據(jù)實際app性能測試案例,展開進(jìn)行app性能評測之CPU使用率的分析和總結(jié)鹿驼。
CPU使用率原理理解
在Linux系統(tǒng)下,CPU利用率分為用戶態(tài)畜晰、系統(tǒng)態(tài)、空閑態(tài)腊瑟,分別表示CPU處于用戶態(tài)執(zhí)行的時間块蚌,系統(tǒng)內(nèi)核執(zhí)行的時間闰非,和空閑系統(tǒng)進(jìn)程執(zhí)行的時間峭范。
平時所說的CPU利用率是指:CPU執(zhí)行非系統(tǒng)空閑進(jìn)程的時間 / CPU總的執(zhí)行時間。
那么我們來看看這個時間究竟是什么纱控?
先介紹幾個和Linux時間有關(guān)的名詞:HZ、tick與jiffies舶掖。
HZ:Linux 核心每隔固定周期會發(fā)出timer interrupt (IRQ 0),HZ是用來定義每一秒有幾次timer interrupts访锻。例如HZ為1000,就代表每秒有1000次timer interrupts期犬。
Tick:Tick是HZ的倒數(shù),Tick = 1/HZ 龟虎。即timer interrupt每發(fā)生一次中斷的時間。如HZ為250時佳吞,tick為4毫秒(millisecond)。
Jiffies :在Linux的內(nèi)核中底扳,有一個全局變量:Jiffies贡耽。 Jiffies代表時間衷模。它的單位隨硬件平臺的不同而不同蒲赂。jiffies的單位就是 1/HZ。Intel平臺jiffies的單位是1/100秒滥嘴,這就是系統(tǒng)所能分辨的最小時間間隔了。每個CPU時間片镊叁,Jiffies都要加1。 CPU的利用率就是用執(zhí)行用戶態(tài)+系統(tǒng)態(tài)的Jiffies除以總的Jifffies來表示意系。
CPU利用率計算公式也就是:
CPU使用率=(用戶態(tài)Jiffies+系統(tǒng)態(tài)Jiffies)/總Jiffies
2饺汹、CPU測試方法
2.1 CPU占用率數(shù)據(jù)獲取方法--adb命令
CPU是系統(tǒng)非常重要的資源蛔添,在Android中/proc/stat, 包含了所有CPU的相關(guān)詳情信息兜辞,查看CPU使用情況,CPU不是一個瞬時態(tài)逸吵,而是一個過程態(tài)的體現(xiàn),一般可以使用top命令和dump cpuinfo命令進(jìn)行CPU占用率獲取足绅。
一般獲取Android CPU數(shù)據(jù)的有兩個命令:top和dump cpuinfo
(1)top命令方式獲取原理了解:
top是比較經(jīng)典的CPU計算方法捷绑,top的代碼在androidm/system/core/toolbox/top.c下面氢妈,輸出process的cpu使用率在print_procs里面,CPU的計算是proc->delta_time * 100 / total_delta_time
先看total_delta_time由:
total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
- (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
+ old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
而這些變量的值壮吩,是在read_procs通過讀取/proc/stat的jiffies得到:
所以總的cpu時間 = user + nice + system + idle + iowait + irq + softirq 加缘,例如:User 147 + Nice 11 + Sys 79 + Idle 408 + IOW 1 + IRQ 0 + SIRQ 6 = 652
而proc->delta_time是兩次讀取/proc/pid/stat相減得到鸭叙,可見拣宏,top是一段時間內(nèi),計算process的cpu jiffies與總的cpu jiffies差值得到勋乾。
注釋:
/proc/stat文件:
該文件包含了所有CPU活動的信息,該文件中的所有值都是從系統(tǒng)啟動開始累計到當(dāng)前時刻。不同內(nèi)核版本中該文件的格式可能不大一致滤奈。
- user (147):
從系統(tǒng)啟動開始累計到當(dāng)前時刻,處于用戶態(tài)的運行時間蜒程,不包含 nice值為負(fù)進(jìn)程。 - nice (11):
從系統(tǒng)啟動開始累計到當(dāng)前時刻忌锯,nice值為負(fù)的進(jìn)程所占用的CPU時間 - system (79):
從系統(tǒng)啟動開始累計到當(dāng)前時刻领炫,處于核心態(tài)的運行時間 - idle (408):
從系統(tǒng)啟動開始累計到當(dāng)前時刻偶垮,除IO等待時間以外的其它等待時間 - iowait (1):
從系統(tǒng)啟動開始累計到當(dāng)前時刻帝洪,IO等待時間(since 2.5.41) - irq (0)
從系統(tǒng)啟動開始累計到當(dāng)前時刻,硬中斷時間(since 2.6.0-test4) - softirq (6):
從系統(tǒng)啟動開始累計到當(dāng)前時刻砚哗,軟中斷時間(since 2.6.0-test4)
(2)top命令獲取CPU占用率實例:
adb shell top -m 100 -n 1 -s cpu | grep 包名
adb shell top -m 100 -n 1 -s cpu | grep com.pafinancialtech.fuzhoubank
auto:auto$ adb shell top -m 100 -n 1 -s cpu | grep com.pafinancialtech.fuzhoubank
18540 0 42% S 108 2102520K 317264K fg u0_a858 com.pafinancialtech.fuzhoubank
2.2.2 dump cpuinfo命令獲取方法
(1)dump命令方式獲取原理了解:
dump cpuinfo是Android特有的命令砰奕,dump cpuinfo命令的實現(xiàn)在androidm/frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java類里面提鸟,方法是printCurrentState:
而printProcessCPU輸出process CPU的使用情況:
private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
int totalTime, int user, int system, int iowait, int irq, int softIrq,
int minFaults, int majFaults) {
pw.print(prefix);
if (totalTime == 0) totalTime = 1;
printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
...
}
user+system+iowait+irq+softIrq就是totalTime仅淑。 st變量的賦值称勋,在collectStats里面漓糙,st.rel_utime 和 st.rel_stime還是通過讀/proc/pid/stat相減得到,而st.rel_uptime卻是通過 SystemClock.uptimeMillis()差值蝗蛙,并不是跟top一樣,通過proc/stat得到總CPU jiffies,
所以捡硅,進(jìn)程的總Cpu時間processCpuTime = utime + stime + cutime + cstime盗棵,該值包括其所有線程的cpu時間壮韭。(例外纹因,一般cpu按100%計算,如果是多核情況下還需乘以cpu的個數(shù))
附注釋:
/proc/pid/stat文件:
該文件包含了某一進(jìn)程所有的活動的信息瞭恰,該文件中的所有值都是從系統(tǒng)啟動開始累計 到當(dāng)前時刻。
Utime(39) 該任務(wù)在用戶態(tài)運行的時間恶耽,單位為jiffies
Stime(25) 該任務(wù)在核心態(tài)運行的時間,單位為jiffies
Cutime(0) 所有已死線程在用戶態(tài)運行的時間偷俭,單位為jiffies
Cstime(0) 所有已死在核心態(tài)運行的時間缰盏,單位為jiffies
(2)dump命令獲取CPU占用率實例
adb shell dumpsys cpuinfo |grep 包名
auto:auto$ adb shell dumpsys cpuinfo |grep com.pafinancialtech.fuzhoubank
117% 16322/com.pafinancialtech.fuzhoubank: 106% user + 11% kernel / faults: 45403 minor 99 major
0.5% 14032/com.pafinancialtech.fuzhoubank:pushservice: 0.5% user + 0% kernel / faults: 1610 minor
+0% 16547/com.pafinancialtech.fuzhoubank:remote: 0% user + 0% kernel
2.3 CPU問題分析思路及工具
如果APP某場景進(jìn)行操作時出現(xiàn)發(fā)燙、卡頓口猜、ANR現(xiàn)象時,可以懷疑出現(xiàn)CPU問題笙以,一般解決思路如下:
a. 如果已經(jīng)導(dǎo)致ANR, 則去log里面搜索"ANR in"
b. 沒有導(dǎo)致ANR則基于以上方法獲取到的CPU占用率,如果某場景的CPU占用率走勢異常猖腕、峰值存在異常、均值大于基線倘感,則可以利用DDMS查看分析Trace文件,或者使用Android studio里面的Android Monitor根據(jù)Monitor中的CPU可以看出目前CPU明細(xì)使用老玛。
c.查找程序中有沒有特殊布局或者特殊操作(GPS定位,一直刷新類的服務(wù)等)蜡豹,特殊加載(Gif圖片加載,視頻弄诲,音頻加載等)
2.3.1 Android Monitor監(jiān)控分析
拿到APP源碼,在Android studio中構(gòu)建測試DEBUG包進(jìn)行調(diào)試如下截圖:
雙擊我綠色框標(biāo)記的這個按鈕齐遵,就會生成這么一個文件塔插,如圖:
上圖就一目了然的看到了耗費CPU 都有哪些方法。此時點擊黑色的文本伶授,幾秒鐘后studio會生成.trace文件,我們就可以分析各方法使用cpu的情況了。
2.3.2 分析TraceView文件查找CPU問題
TraceView 是 Android SDK 中內(nèi)置的1個工具逢倍,它可以加載 trace 文件,用圖形的情勢展現(xiàn)代碼的履行時間较雕、次數(shù)及調(diào)用棧,便于我們分析扣典。
(1)使用Android Studio工具DDMS
生成Traceview 進(jìn)行分析查看具體Trace期間各方法調(diào)用關(guān)系,調(diào)用次數(shù)以及耗時比例
附注釋:
Traceview 面板分上下兩部分
上面是時間軸面板 (Timeline Panel)
左側(cè)顯示的是線程信息
右側(cè)黑色部分是顯示執(zhí)行時間段贮尖、白色是線程暫停時間段趁怔,
右側(cè)鼠標(biāo)放在上面會出現(xiàn)時間線縱軸薪前,在頂部會顯示當(dāng)前時間線所執(zhí)行的具體函數(shù)信息
下面是分析面板(Profile Panel) - 每一列內(nèi)容
Inclusive time - 函數(shù)本身運行花費時間 + 函數(shù)調(diào)用其他函數(shù)時間
Exclusive time - 函數(shù)本身運行花費時間关斜。
Calls + RecurCall/Total 調(diào)用 + 重復(fù)調(diào)用次數(shù) / 函數(shù)總調(diào)用次數(shù)
Cpu Time/Call 總的Cpu時間與總的調(diào)用次數(shù)之比
附: Profile Panel各列作用說明
- Name
該線程運行過程中所調(diào)用的函數(shù)名 - Incl Cpu Time
某函數(shù)占用的CPU時間,包含內(nèi)部調(diào)用其它函數(shù)的CPU時間 - Excl Cpu Time
某函數(shù)占用的CPU時間痢畜,但不含內(nèi)部調(diào)用其它函數(shù)所占用的CPU時間 - Incl Real Time
某函數(shù)運行的真實時間(以毫秒為單位),內(nèi)含調(diào)用其它函數(shù)所占用的真實時間 - Excl Real Time
某函數(shù)運行的真實時間(以毫秒為單位)丁稀,不含調(diào)用其它函數(shù)所占用的真實時間 - Call+Recur Calls/Total
某函數(shù)被調(diào)用次數(shù)以及遞歸調(diào)用占總調(diào)用次數(shù)的百分比 - Cpu Time/Call
某函數(shù)調(diào)用CPU時間與調(diào)用次數(shù)的比。相當(dāng)于該函數(shù)平均執(zhí)行時間 - Real Time/Call
同CPU Time/Call類似二驰,只不過統(tǒng)計單位換成了真實時間
(2)使用代碼生成 trace 文件
Debug.startMethodTracing("shixintrace");
//開始 trace,保存文件到 "/sdcard/shixintrace.trace"
// ...
Debug.stopMethodTracing(); //結(jié)束
代碼很簡單矿酵,當(dāng)你調(diào)用開始代碼的時候,系統(tǒng)會生產(chǎn) trace 文件全肮,并且產(chǎn)生追蹤數(shù)據(jù)棘捣,當(dāng)你調(diào)用結(jié)束代碼時辜腺,會將追蹤數(shù)據(jù)寫入到 trace 文件中乍恐。
下1步使用 adb 命令將 trace 文件導(dǎo)出到電腦:
adb pull /sdcard/shixintrace.trace /tmp
使用代碼生成 trace 方式的好處是容易控制追蹤的開始和結(jié)束,缺點就是步驟略微多了一點百匆。
2.3 CPU測試場景
一般cpu檢測我們要分4種情況:
1.在空閑時間的消耗,基本沒大應(yīng)用使用cpu
如果APP在退出界面后還有進(jìn)程長期運行加匈,那需要關(guān)注下待機場景的CPU。待機場景下CPU的消耗一般不會很大雕拼,例如銀行APP在后臺運行時粘招,可能消耗經(jīng)常是0%啥寇,長時間平均下,可能只有0.1%示姿、0.2%,看看競品岂傲,也是差不多,好像沒有太大區(qū)別镊掖。那么CPU消耗這么少是不是就不用管CPU了呢褂痰,然而即使是平均值很小亩进,但是長時間待機缩歪,例如安全類工具,CPU的消耗還是不容忽視匪蝙。
這種場景下我們測試時常用的單位有:消耗XX jiffies/分鐘;半/1小時共增加XX jiffies千元。
2.在運行一些應(yīng)用的情況下,cpu已占50%的情況下幸海,觀察應(yīng)用程序占用cpu的情況
簡單說這種情況就是后臺已經(jīng)有幾個應(yīng)用在運行已經(jīng)并且消耗了系統(tǒng)的一些資源的情況下進(jìn)行測試。
3.在高負(fù)荷的情況下看CPU的表現(xiàn)奥务,我定義這個高負(fù)荷,cpu占用應(yīng)是在80%以上
滿規(guī)格狀態(tài)下的應(yīng)用CPU消耗情況
4.觀察App 相同/不同場景下CPU走勢氯葬、峰值情況
對比不同場景頁面CPU占用大小
對比不同時間段同一場景頁面CPU占用走勢情況
3、XX銀行性能評測-CPU測試結(jié)果分析
3.1 總覽
性能測試的采集的CPU占用數(shù)據(jù)主要是針對場景頁面的CPU占用測試溢谤,CPU占用數(shù)據(jù)獲取原理是CPU執(zhí)行非系統(tǒng)空閑進(jìn)程的時間 / CPU總的執(zhí)行時間憨攒。
從CPU消耗對比來看,行業(yè)競品均值為8.4%肝集,90分位約4.9%,75分位約7.8%所刀,中位數(shù)約9.3%衙荐,25分位約16.2%浮创。
CPU占用對比.png
【榕商Bank】和10家競品分析對比,CPU占用12.0%溜族,表現(xiàn)較差,不及行業(yè)平均水準(zhǔn)煌抒。但是從APP本品各場景CPU占用率來看,占用率最大的為理財產(chǎn)品詳情頁22.7%寡壮,主要原因是該頁面存在6個不同時段近七日和萬份收益率曲線走勢圖繪制,但是仍然未超過CPU占用率基線30%况既,且目前大部分手機是四核闸婴、八核系統(tǒng)坏挠,所以目前測試數(shù)據(jù)表明整體表現(xiàn)良好不存在瓶頸邪乍,但是從行業(yè)標(biāo)準(zhǔn)來看,理財產(chǎn)品詳情頁仍然有優(yōu)化空間庇楞,建議優(yōu)化。
4蛋褥、App端CPU問題排查思路:
(1)是否有非常多的網(wǎng)絡(luò)請求
(2)是否開了很多進(jìn)程OR 應(yīng)用睛驳,嘗試關(guān)閉其他應(yīng)用再查看CPU是否降下來
(3)是否有大量大圖片烙心、視頻處理跟加載或布局
(4)查找程序中有沒有特殊布局或者特殊操作(GPS定位乏沸,一直刷新類的服務(wù)等),特殊加載(Gif圖片加載蹬跃,視頻,音頻加載等)
(5)當(dāng)前頁面是否有過多的圖表丹喻、曲線圖等繪制操作
(6)通過Android Studio 自帶的monitor查找是哪個Activity或者哪個方法有一直不停止的運算消耗CPU(比如:不停止的while 或者for 循環(huán))