背景:app改版,人為感受卡頓,需要客觀數據支撐觀點。故,搜索各種性能指標,並理解之。(這是一篇摘要文......)
首先,明確人為感受的性能不好屬於下面哪種:
1. 響應時間,界面跳轉后響應時間;
2. 流暢度,界面操作時或動畫展示的效果;
而流暢度的衡量指標又有幾種:
1. 幀率fps(Frames Per Second,每秒鍾填充圖像的幀率)
2. 丟幀SF(Skipped frame)
3. 流暢度SM(SMoothness)(騰訊分享)
其中得到最廣泛使用的還是幀率。以下詳細說明之
回顧本源:Android如何繪制UI?
說實話,這里看的不甚懂,主要理解了垂直同步機制。
每隔1個VSync間隔,Android會發起一次中斷,GPU/CPU就會處理新一幀的數據,處理每幀數據的時間必定為VSync間隔的整數倍;即使GPU/CPU可處理的幀數更多最終也會保持和Android顯示系統一致;而如果GPU/CPU可處理的幀數少於60,則會出現掉幀的情況,即人為感知每幀圖像之間的不連貫。
基於此種情況,還出現了三緩存,注意下圖中的C,在空閑時先處理了C,在之后的某個時間放到屏幕上。
補充關於雙緩存與surface關系參考:Android UI呈現
- 雙緩沖在圖像處理上非常重要,它的工作原理是:先把需要呈現的所有元素都畫
- 在一張圖上(第一層),再把這張圖整個投放到屏幕上去(第二層)。
- surface就相當於第一層,所有元素都要先在Surface上畫,每個window對應一個Surface
- surface處理也存在MVC三層結構:
- SurfaceFlinger:Android系統的一個服務,用來生成Surface,管理幀緩沖區,實際做的事兒就是:把不同z坐標的Window按順序排放,將所有的window合成一張圖,也就是一幀
幀率值在什么范圍可認定為流暢?
理想狀態每秒展示60幀時人眼感受不到卡頓,1000ms/60幀,即每幀繪制時間不應超過16.67ms。
幀率如何計算?
搜索相關文章,幀率的計算大致分為以下兩種。
- adb shell dumpsys gfxinfo <PACKAGE_NAME> 參考:Testing Display Performance
- adb shell dumpsys SurfaceFlinger --latency <window_activity> 參考:Android性能測試之fps獲取
二者的區別是什么?
參考:FPS計算方法比較
這是需要重點了解的功能,部門原已采用gfxinfo獲取相關數據,但網搜到后期數據處理多是基於SurfaceFlinger 的數據。導致研究發現數據處理方法對不上,實則忽略了二者的區別。
gfxinfo:
- 記錄最近128幀的繪制時間,每幀不同階段(網搜大部分文章只有3個階段,實則在Android系統升級過程,已增加,詳見官網)的時間相加,不超過16.67ms就是流暢的;
- 若停止不動,app內部也沒有刷新處理屏幕的需求,會輸出0,有時未開始滑動會直接沒有數據輸出;
- 以上導致了如果app內部也沒有刷新處理屏幕的需求,很流暢,但由於實際每秒處理的幀數不多,fps的值可能也會很少;
SurfaceFlinger:
- 實際記錄127幀數據,第一行標明VSync間隔,一般為16666666/1000/1000 = 16.67ms(毫秒);
- 保持不動,會一直輸出上一幀的數據;
- 最終幀率的計算為期間幀數/時間,int(round((frame_count-1)/ seconds)),詳情參考:Android性能測試之fps獲取
FPS是否能充分衡量app的流暢度?
算出FPS了,這個單純的數據能夠代表流暢度么?關於這點,很多資料中也有質疑。由於Android自帶adb測試性能命令,輸出一個階段的幀繪制耗時,多次測試獲得多個曲線,不能簡單求均值獲得概括數據。有資料是建議使用 掉幀率 來衡量。
利用 處理幀數 / (處理幀數 + 額外的垂直同步脈沖) * 60 計算,其中處理幀數常為128
實測補充說明:
- 前提需要打開設置中的GPU繪制選項
- 記錄過程冷啟動(殺進程),則之前的數據丟失
- 獲取數據不難,后期如何理解數據,利用這些數據,建立數學模型是比較重要的。
附錄:實際獲得的gfxinfo數據:其實后五項的數據意義還不太清晰,求指教,為什么求和之后不等於janky frames