Android 系統性能優化(36)---顯示效能指標
從 Android 誕生的那一刻起,流暢度就為眾人所關注。一時之間,似乎所有人都在討論 Android 和 iOS 誰的流暢度更好。但是,毫不誇張的說,流暢度絕對是 Android 眾多效能維度中最為奇葩的一個。因為,為了刻畫這一效能維度,業界設計了各式各樣的指標來對其進行衡量。可以說弄清了這些指標我們就明白了什麼是流暢度,可是這似乎並不太容易。
筆者簡單蒐集了一些業界中提及的顯示效能指標,大家可以來品評一下:
指標名稱:Jankiness count、Max accumulated frames、Frame rate
相關資料:JankTestBase.java指標名稱:SM、Skipped frames
相關資料:Android應用效能評測調優
面對如此之多的顯示效能指標,想必大家也會跟筆者一樣,心中難免疑惑叢生。其實,我們只需要依次弄清楚以下三個哲學問題,所有的問題也許就會迎刃而解:
- 你是誰——這些指標具體反映了什麼問題
- 你從哪兒來——這些指標數值是怎麼得到的
- 你要到哪兒去——這些指標如何落地來指導優化
因此,本文將嘗試依次從上訴三個問題來逐步分析和探討各個顯示效能指標。
Step 1:你是誰——這些指標具體反映了什麼問題
總所周知,脫離了具體的應用背景,所有的指標都是沒有意義的。所以,為了徹底弄清楚各個顯示效能指標的具體身份,我們勢必得從 Android 的影象渲染流程說起。
具體展開之前,首先需要說明的是,為了降低複雜程度和本章篇幅,在這個環節之中,我們只討論影象渲染流程中的各個具體環節所對應的指標有哪些。而指標的具體定義,由第二章《你從哪兒來——這些指標數值是怎麼得到的》進行討論。
Android 影象渲染流程
下圖是筆者結合各類資料(主要是是原始碼及官方文件),在根據自己的理解梳理出的幾種常見場景下的影象渲染流程:
PS 1:筆者個人技術水平有限,若存在理解有誤的地方還望指正。
PS 2:本文主要討論的 Android 原始碼為 Android 6.0
備註:基於 OpenGL 的應用可以使用 Choreographer 中的 VSYNC 訊號來進行影象渲染工作的安排。
上面這幅圖涉及的概念較多,要完全吃透估計得費不少時間。不過好在我們只是想弄明白顯示效能各種指標的含義,所以我們只需要理清下面兩大關係即可:
SurfaceFlinger、HWComposer與Surface的關係
- Surface
- SurfaceFlinger:服務執行在System程序中,用來統一管理系統的幀緩衝區裝置,其主要作用是將系統中的大部分Surface進行合成。SurfaceFlinger主要使用GPU進行Surface的合成,合成的結果將形成一個FrameBuffer。
- HWComposer:即Hardware Composer HAL,其作用是將SurfaceFlinger通過GPU合成的結果與其他Surface一起最終形成BufferQueue中的一個Buffer。此外,HWComposer可以協助SurfaceFlinger進行Surface的合成,但是否進行協助是由HWComposer決定的。
- 值得注意的是,有的Surface不由WindowManager管理,將直接作為HWComposer的輸入之一與SurfaceFlinger的輸出做最後的合成。
- Surface
Choreographer、SurfaceFlinger、HWComposer與VSYNC的關係
- VSYNC:Vertical Synchronization的縮寫,它的作用是使GPU的渲染頻率與顯示器的重新整理頻率(一般為固定值)同步從而避免出現畫面撕裂的現象。
- HWComposer:VSYNC訊號主要由HWComposer通過硬體觸發。
- Choreographer:當收到VSYNC訊號時,Choreographer將按優先順序高低依次去呼叫使用者通過postCallback提前設定的回撥函式,它們分別是:優先順序最高的CALLBACK_INPUT、優先順序次高的CALLBACK_ANIMATION以及優先順序最低的CALLBACK_TRAVERSAL。
- SurfaceFlinger:Surface的合成操作也時基於VSYNC訊號進行的。
簡單來說,Android 影象渲染流程主要由以下特徵:
- 我們可以簡單把 Android 影象渲染架構分為應用(Surface)、系統(SurfaceFlinger)、硬體(Screen)三個層級,其中繪製在應用層,合成及提交上屏在系統層,顯示在硬體層;
- 無論應用(Surface)、系統(SurfaceFlinger)、硬體(Screen)都是當且僅當繪製內容發生改變,才會對繪製內容進行處理;
- 系統中的 SurfaceFlinger 以及絕大部分 Surface 都是按照 VSYNC 訊號的節奏來安排自己的任務;
- 目前,絕大部分 Surface 都屬於 Hardware Rendering。
各個指標在 Android 影象渲染流程所代表的意義
大致梳理了 Android 的影象渲染流程之後,我們需要做的一件事情,就是看看上面提到的指標,都對應了渲染流程的哪些階段,這樣對於我們瞭解各個指標所反映的具體物理意義及其優勢劣勢都有極大幫助。再次強調,在這個環節之中,我們的討論僅限於只討論指標所對應的渲染流程的具體階段,各指標的具體定義由第二章具體展開。
系統層級(SurfaceFlinger)的顯示效能指標
- 基礎資料:SurfaceFlinger 合成次數
- 指標意義:
- 系統合成幀率:FPS
- 特別說明:
- SurfaceFlinger 僅在顯示區域內的 Surface 有提交內容更新時才會進行合成(上屏),因此,系統合成幀率低並不一定意味著影象顯示效能差,有可能是因為當前並沒有任何的內容更新所導致。
- 若顯示區域內的某個待測 Surface 持續進行更新時, SurfaceFlinger的合成(上屏)的頻率可以在某種程度上反映該 Surface 的顯示效能,但從理論上分析該指標並不一定準確。這是因為,若顯示區域內尚存在其他 Surface,它們也會影響 SurfaceFlinger 的合成(上屏)的行為,從而干擾結果。
- 若某個 Surface 的合成不在 SurfaceFlinger 中進行(如 Camera Preview),則該 Surface 的顯示效能無法用這類指標進行衡量。
應用層級(Surface)的顯示效能指標
- 基礎資料:繪製過程中每一幀的關鍵時間點(如開始繪製時間、結束繪製時間等)
- 指標意義:
- 應用繪製幀率:Frame rate
- 應用繪製輪詢頻率:SM
- 應用繪製超時(跳幀)的次數:Aggregate frame stats、Jankiness count、Skipped frames
- 應用繪製超時(跳幀)的幅度:Aggregate frame stats、Max accumulated frames、Skipped frames
- 特別說明:
- 與 SurfaceFlinger 類似, Surface也僅在有內容更新時才會進行繪製,因此,繪製頻率低並不一定意味著影象顯示效能差,有可能是因為當前並沒有任何的內容更新所導致。
- 如 SM、Skipped frames 這類指標,由於其基礎資料取自 Choreographer,若 某些 Surface 的繪製不依賴於 Choreographer ,則這些指標無法衡量該 Surface 的顯示效能。
- 如 Aggregate frame stats、Jankiness count、Max accumulated frames、Frame rate 這類指標, 由於其基礎資料僅在硬體繪製(Hardware Rendering)過程中進行統計,屬於 HWUI 的功能,所以非硬體繪製的 Surface 自然無法使用這類指標進行衡量。
小結
評價顯示效能的各個指標,可以按其在影象渲染流程中的作用,分為以下兩類:
- 系統層級的指標僅有 FPS 一根獨苗,它的限制是 Surface 的和合成需要在 SurfaceFlinger中進行;
- 應用層級的指標較多,它們之中又可以分為兩類:
1) SM、Skipped frames 需要 Surface 依賴 Choreographer進行繪製,才能正常工作;
2) Aggregate frame stats、Jankiness count、Max accumulated frames、Frame rate 屬於 HWUI 的功能, 需要 Surface 的繪製由 HWUI 進行才能進行分析。
Step 2:你從哪兒來——這些指標數值是怎麼得到的
第一章的內容僅僅是站在整個影象繪製流程的高度來簡單分析各個指標的,本章將進一步分析各個指標的基礎資料來源以及具體計算方式。
基礎資料:系統層級(SurfaceFlinger)的合成(上屏)的次數
前面說到,在 Android 系統中,SurfaceFlinger 扮演了系統中所有 Surface 的管理者的角色,當應用程式所對應的 Surface 更新之後,絕大多數的 Surface 都將在 SurfaceFlinger 之中完成了合併的工作之後,最終才會在 Screen 上顯示出來。
當然, SurfaceFlinger 的執行也是由 VSYNC 訊號驅動的,這也決定了每秒鐘合成次數的上限就是 60 次。當 SurfaceFlinger 接收到 Surface 更新通知的時候,將會由 SurfaceFlinger::handleMessageRefresh 函式進行處理,其中包含重建可見區域、初始化、合成等步驟。這裡,我們主要關注 SurfaceFlinger::doComposition() 這個方法。
void SurfaceFlinger::handleMessageRefresh() {
...
if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
// Latch buffers, but don't send anything to HWC, then signal another
// wakeup for the next vsync
preComposition();
repaintEverything();
} else {
preComposition();
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition(); //重點關注物件
postComposition();
}
...
}
- 在 doComposition 中,完成 Surface 的合成之後,都會呼叫 DisplayDevice::flip(),它會使用變數 mPageFlipCount 統計我們進行合成的次數,這個變數就是我們統計 FPS 的核心原始資料。mPageFlipCount 記錄了 SurfaceFlinger 一共進行了多少次合成,也可以簡單理解為,SurfaceFlinger 向螢幕提交了多少幀的資料。
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->isDisplayOn()) {
...
hw->flip(hw->swapRegion);//重點關注物件
...
}
// inform the h/w that we're done compositing
hw->compositionComplete();
}
postFramebuffer();
}
void DisplayDevice::flip(const Region& dirty) const {
...
mPageFlipCount++;
}
- 不僅如此, Android 還為我們獲取這個基礎資料提供了比較方便的方法。通過執行 adb 命令:service call SurfaceFlinger 1013,我們就可以得出當前的 mPageFlipCount。
C:\Users\xiaosongluo>adb shell
shell@cancro:/ $ su
su
root@cancro:/ # service call SurfaceFlinger 1013
service call SurfaceFlinger 1013
Result: Parcel(00aea4f4 '....')
- FPS 的計算方法
根據 FPS 的定義,我們不難逆推得出 FPS 的計算方法:
在 t1 時刻獲取 mPageFlipCount 的數值 v1,在在 t2時刻獲取 mPageFlipCount 的數值 v2,FPS 的計算公式:
FPS = (v2 - v1) / (t2 - t1);
- 需要注意的是:mPageFlipCount 的原始資料是 16 進位制的,一般而言計算之前需要先進行進位制轉換。
基礎資料:應用層級(Surface)的繪製過程中每一幀的關鍵時間點(FrameInfo)
請大家先注意 FrameInfo 是由 Android 6.0(具體來講是 Android M Preview) 引入到 HWUI 模組中的統計功能。 因此,目前來講絕大多數系統上的大多數應用都暫時無法獲取這一基礎資料。不過 This IsTheFuture。
我們再來仔細瞧瞧 Google 給出的顯示效能測試的十全大補丸 《Testing Display Performance : Aggregate frame stats》 。其中,特別值得關注的是 adb shell dumpsys gfxinfo framestats 這一條命令。通過這條命令,我們獲取每一幀繪製過程中每個關鍵節點的耗時情況,從而仔細的分析潛在的效能問題。
不得不說,按照 Google 給出的這種測試方法進行測試得到的顯示效能資料是非常全面的。
這些基礎資料都是記錄在 FrameInfo 之中,由 CanvasContext 在doFrame()時進行記錄。相關的主要原始碼如下:
//原始碼:FrameInfo.cpp
#include "FrameInfo.h"
#include <cstring>
namespace android {
namespace uirenderer {
const std::string FrameInfoNames[] = {
"Flags",
"IntendedVsync",
"Vsync",
"OldestInputEvent",
"NewestInputEvent",
"HandleInputStart",
"AnimationStart",
"PerformTraversalsStart",
"DrawStart",
"SyncQueued",
"SyncStart",
"IssueDrawCommandsStart",
"SwapBuffers",
"FrameCompleted",
};
void FrameInfo::importUiThreadInfo(int64_t* info) {
memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
}
} /* namespace uirenderer */
} /* namespace android */
- Aggregate frame stats 指標的計算方法
首先需要說明的是 Aggregate frame stats 不是一個指標,而是一系列指標集合。我們來看一個具體的 Aggregate frame stats 的例子:
Stats since: 752958278148ns
Total frames rendered: 82189
Janky frames: 35335 (42.99%)
90th percentile: 34ms
95th percentile: 42ms
99th percentile: 69ms
Number Missed Vsync: 4706
Number High input latency: 142
Number Slow UI thread: 17270
Number Slow bitmap uploads: 1542
Number Slow draw: 23342
在 Android M 以上的系統上,上述資訊的獲取十分方便(事實上也只有這些系統能夠獲取這些資訊)。僅需要執行以下命令即可:
adb shell dumpsys gfxinfo <PACKAGE_NAME>
- Jankiness count、Max accumulated frames、Frame rate 指標的計算方法
首先需要說明的是:Jankiness count、Max accumulated frames、Frame rate 與 Aggregate frame stats的基礎資料並不一致,它們的基礎屬於來源於 gfxinfo(Profile data in ms)。
只是在 Android M 中 gfxinfo(Profile data in ms) 的基礎數值來源於 FrameInfo,詳見原始碼:FrameInfoVisualizer。但在更早的系統之上, gfxinfo(Profile data in ms) 的數值也可以獲取。
這裡需要特別指出的是, gfxinfo(Profile data in ms)只儲存了 Surface 最近渲染的128幀的資訊,因此,Jankiness count、Max accumulated frames、Frame rate 也僅僅是針對這 128 幀資料所計算出來的結果,它們的具體含義分別是:
- Jankiness count:根據相鄰兩幀繪製時間的差值,“估計”是否存在跳幀並進行跳幀次數的統計;
- Max accumulated frames: 根據相鄰兩幀繪製時間的差值,“估計”這 128 幀繪製過程中可能形成的最大連續跳幀數;
- Frame rate:計算所得平均(繪製)幀率。
如果你對具體的計算過程感興趣,可以參考詳見原始碼:JankTestBase
基礎資料:應用層級(Surface)的繪製過程中每一幀的關鍵時間點(Choreographer)
先說一句有點繞口的話: Choreographer 是依據 Choreographer 繪製的 Surface 在 UI 繪製過程中最為核心的機制。
Choreographer 的工作機制簡單來說就是,使用者首先通過 postCallback 在 Choreographer 中設定的自己回撥函式:
- CALLBACK_INPUT:優先順序最高,和輸入事件處理有關。
- CALLBACK_ANIMATION:優先順序其次,和Animation的處理有關。
- CALLBACK_TRAVERSAL:優先順序最低,和UI等控制元件繪製有關。
那麼,當 Choreographer 接收到 VSYNC 訊號時,Choreographer 會呼叫 doFrame 函式依次對上述藉口進行回撥,從而進行渲染。
那麼顯然,doFrame 的執行效率(次數、頻率)也就是我們需要的顯示效能資料。而這樣的基礎資料,Choreographer 自身也進行了記錄。如下面程式碼中, jitterNanos 記錄了繪製前後兩幀所間隔的時間差, 而 skippedFrames 則記錄了 jitterNanos 這段時間 doFrame 錯過了多少個 VSYNC 訊號,即跳過了多少幀。
// Set a limit to warn about skipped frames.
// Skipped frames imply jank.
private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt("debug.choreographer.skipwarning", 30);
void doFrame(long frameTimeNanos, int frame) {
...
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread.");
}
...
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
...
frameTimeNanos = startNanos - lastFrameOffset;
}
...
}
- 上述資料的獲取並不是那麼的直接,所以需要一定的手段。方法一共有三種,都不難:
- Logcat 方案
缺點:該方案需要系統授權 “Adb Root” 許可權,用於修改系統屬性;對於丟幀資訊只能統計分析,無法進行實時處理。
優點:設定完成後,可以獲取系統中所有應用各自的繪製丟幀情況(丟幀發生的時間以及連續丟幀的數量)。
其實,仔細觀察程式碼,我們就可以注意到 Choreographer 原始碼中本身就有輸出的方案:
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread.");
}
- 唯一阻礙我們獲取數值的是:skippedFrames 的數值只有大於 SKIPPED_FRAME_WARNING_LIMIT 才會輸出相關的警告。而 SKIPPED_FRAME_WARNING_LIMIT 的數值可以由系統引數 debug.choreographer.skipwarning 來設定。
注意:初始條件下,系統中不存在 debug.choreographer.skipwarning 引數,因此 SKIPPED_FRAME_WARNING_LIMIT 將取預設值 30。因此,正常情況下,我們能夠看見上訴 Log 出現的機會極少。
因此,如果我們修改(設定)系統屬性 debug.choreographer.skipwarning 為 1,Logcat 中將打印出每一次丟幀的Log。需要說明的是,由於為 SKIPPED_FRAME_WARNING_LIMIT 賦值的程式碼段由 Zygote 在系統啟動階段載入,而其他應用都是在拷貝複用 Zygote 中的設定,因此設定系統屬性後需要重啟 Zygote 才能使得上述設定生效。
具體的設定方法如下:
setprop debug.choreographer.skipwarning 1
setprop ctl.restart surfaceflinger; setprop ctl.restart zygote
- 設定完成以後,我們可以直接通過 Logcat 中的資訊得到系統中所有應用的繪製丟幀資訊,包括丟幀發生的時間以及連續丟幀的數量。不過由於 Logcat 資訊的滯後性,以上資訊我們幾乎只能進行在測試完成後進行統計分析,而無法進行實時處理。
- Choreographer.FrameCallback 方案
缺點:該方案需要將測試程式碼與待測應用打包在一起,因此理論上僅能測試自己開發的應用。
優點:可以對丟幀資訊進行實時處理
Implement this interface to receive a callback when a new display frame is being rendered. The callback is invoked on theLooper thread to which the Choreographeris attached.
通過這個介面,我們可以在每一幀被渲染的時候記錄下它開始渲染的時間,這樣在下一幀被處理是,我們不僅可以判斷上一幀在渲染過程中是否出現掉幀,而整個過程都是實時處理的,這為我們可以及時獲取相關的呼叫棧資訊來輔助定位潛在的效能缺陷有極大的幫助。
- 程式碼注入方案
缺點:該方案需要通過注入程式為指定應用注入測試程式碼,因此需要系統為注入程式授權 “應用Root” 許可權。
優點:與 Choreographer.FrameCallback 方案一致。
該方案可以簡單理解為通過注入的方式來實現與 Choreographer.FrameCallback 方案一樣的目的。因此,這裡我們主要討論兩者在實現方式上的區別。
顯而易見,我們需要注入的物件是 Choreographer ,因此理論上任何第三方應用都是可以被注入的。但是隨著 Android 系統對”應用Root” 許可權管理越來越嚴格,所以該方案可用的範圍越來越小。
SM 指標的計算方法
根據定義,SM 其實類似於 FPS,它被設計為可以衡量應用平均每秒執行 doFrame() 的次數。我們可以認為它是在衡量 Surface 渲染輪詢的次數。
針對 Logcat 方案,我們只需統計測試過程中目標程序一共掉了多少幀,由於對於絕大多數應用在沒有丟幀的情況下會針對每一次 VSYNC 訊號執行一次 doFrame(),而 VSYNC 絕大多數情況下每秒會觸發 60 次,因此我們可以反向計算得出 SM 的數值:
SM = (60* totalSeconds - totalSkippedFrames) / totalSeconds;
- 針對 Choreographer.FrameCallback 方案 以及 程式碼注入方案,我們需要在程式碼中自己進行統計輸出(可以是設計成實時的,也可以設計成測試結束後進行統計計算的)。
Skipped frames 指標的計算方法
這個指標的就是指當前應用在丟幀發生時的丟幀幀數。
針對 Logcat 方案, 該數值直接在 Logcat 中輸出,並且帶有時間資訊。
04-18 16:31:24.957 I/Choreographer(24164): Skipped 4 frames! The application may be doing too much work on its main thread.
04-18 16:31:25.009 I/Choreographer(24164): Skipped 2 frames! The application may be doing too much work on its main thread.
- 針對 Choreographer.FrameCallback 方案 以及 程式碼注入方案,我們可能很方便的通過計算前後兩幀開始渲染的時間差獲得這一數值,同樣方便。同樣與 Logcat 方案 不同的是,它也是可以設計成實時計算的。
小結
通過對各個顯示效能指標的分析,我們可以知道,雖然目前指標眾多,但其實有本質區別的指標確很少:
- 系統層面:
- 合成(上屏)幀率:FPS
- 應用層面:
- 跳幀次數:Aggregate frame stats、Jankiness count、Skipped frames
- 跳幀幅度:Aggregate frame stats、Max accumulated frames、Skipped frames
- 繪製幀率:Frame rate
- 繪製輪詢頻率:SM
更為重要的是,我們從上述的分析中知道了各個指標都有著自己的優勢和不足,這也從根本上決定了它們各自有各自的用法。
Step 3:你要到哪兒去——這些指標如何落地來指導優化
其實指標的用法也是多種多樣的,為了方便討論,我們僅從日常監控、缺陷定位以及資料上報三個方面來討論各個顯示效能指標是如何落地的。
日常監控
- FPS:資料形式最為直觀(FPS 是最早的顯示效能指標,而且在多個平臺中都有著類似的定義),且對系統平臺的要求最低(API level 1),遊戲、視訊等連續繪製的應用可以考慮選用,但不適用於絕大多數非連續繪製的應用;
- SM:資料形式與 FPS 類似,可以很好的彌補 FPS 無法準確刻畫非連續繪製的應用顯示效能的缺陷;
- Aggregate frame stats:除了對系統平臺有較高的要求以外,其採集方式最為簡單(系統自帶功能);
- Skipped frames:與 Aggregate frame stats 類似, 資訊量相對較少,但可適用範圍更廣
特別說明:Jankiness count、Max accumulated frames、Frame rate 只統計了128幀的資訊(約2~3秒),而且 Jankiness count、Max accumulated frames對於掉幀情況的計算並非是一個準確值,因此這些指標都不太適用於日常監控
舉個栗子,筆者服務的某個產品使用如下的一些指標來監控產品與競品的效能變化情況:
測試指標 | 場景1 | 場景2 | 場景3 | 場景4 |
---|---|---|---|---|
FPS | 58 | 58 | 58 | 58 |
SM | 59 | 59 | 59 | 59 |
Num of 6+ Skipped Frames | 0 | 0 | 0 | 0 |
Num of 3+ Skipped Frames | 0 | 0 | 2 | 0 |
備註:
1. Num of x+ Skipped Frames 代表測試過程中發生連續丟 x 幀(及以上)的次數;
2. 至於為什麼我們選擇關注連續丟 3 幀以及連續丟 6 幀的的次數,在【缺陷定位】部分有相關的分析討論;
缺陷定位
- Skipped frames:基於 Choreographer.FrameCallback 方案實現的 Skipped frames 指標,可以在卡頓出現的時刻獲取應用堆疊資訊,可以在一定程度上進行缺陷定位
特別說明:
1. FrameInfo 相關指標無法直接進行缺陷定位,但 FrameInfo 當中包含了大量詳盡的繪製基礎資料,對於缺陷定位也有較大幫助;
2. 關於缺陷定位過程中連續掉幀閾值的選取,可參考維基百科中提到幾個重要的幀率數值:
- 12 fps:由於人類眼睛的特殊生理結構,如果所看畫面之幀率高於每秒約10-12幀的時候,就會認為是連貫的
- 24 fps:有聲電影的拍攝及播放幀率均為每秒24幀,對一般人而言已算可接受
- 30 fps:早期的高動態電子遊戲,幀率少於每秒30幀的話就會顯得不連貫,這是因為沒有動態模糊使流暢度降低
- 60 fps:在實際體驗中,60幀相對於30幀有著更好的體驗以上各資料分別對應: 0 幀、1幀、2.5幀、5~6幀。(這就是為啥選擇3/6的原因)
舉個栗子, 筆者的同事萬大師(yuwan)基於上述原理自研了一款效能分析工具。該工具在集成於待測應用之後,可以自動儲存如下的效能缺陷資訊:
Frame lost:... (連續丟幀數量,一般我們會設定一個閾值,例如 6 幀以上我們才會進行記錄)
User action:...(當前使用者操作)
Stack trace: ...(當前堆疊資訊)
- 有了這個工具之後,我們可以收集應用的各個潛在“卡頓”點,用於進一步的分析和優化。
資料上報
- Aggregate frame stats:除了對系統平臺有較高的要求以外,其採集方式最為簡單(系統自帶功能)、資料也比較清晰,相信基於這類指標實現效能資料上報是特別方便的
- Skipped frames :基於 Choreographer.FrameCallback 方案實現的 Skipped frames 指標,採集方式簡單,實現基礎效能資料上報、卡頓資料上報也是很方便的
這方面應用,筆者所服務的產品暫時沒有涉及,就不舉例子了。如果各位觀眾感興趣,建議參考 Android ANR 的設計理念。
小結
發現了沒有 Skipped frames 的用處很大有沒有? 而且通讀全篇,你會發現 Aggregate frame stats、Jankiness count、Max accumulated frames 這些指標都有提供類似的功能。
至於為什麼,這就不是本文需要討論的內容了,如果大家比較感興趣,筆者這裡給出兩份相關的連結以供各位參考:
友情附贈: 現有顯示效能指標對比
本來寫到這裡本文的主要內容就應該結束了。但是如果不對比一下顯示效能指標神馬的,總會讓人覺得缺少了一些什麼。
友情提示:下述內容相對主觀,建議各位讀者依據專案情況自行進行選擇。
相關推薦
Android 系統性能優化(36)---顯示效能指標
從 Android 誕生的那一刻起,流暢度就為眾人所關注。一時之間,似乎所有人都在討論 Android 和 iOS 誰的流暢度更好。但是,毫不誇張的說,流暢度絕對是 Android 眾多效能維度中最為奇葩的一個。因為,為了刻畫這一效能維度,業界設計了各式各樣的指標來對
Android 系統性能優化(11)---UC效能優化方案
一、效能優化六項指標: 效能、記憶體、穩定性、流量、電量、安裝包大小; 二、背景 ---- Android程式卡頓產生原因: 1、Android系統低效 --渲染執行緒、同步介面、廣播機制
android系統性能優化(63)---Android APP 卡頓問題分析及解決方案
使用者對卡頓的感知, 主要來源於介面的重新整理. 而介面的效能主要是依賴於裝置的UI渲染效能. 如果我們的UI設計過於複雜, 或是實現不夠友好,計算繪製演算法不夠優化, 裝置又不給力, 介面就會像卡住了一樣, 給使用者卡頓的感覺.如果你的應用介面出現卡頓不流暢的情況,不用懷疑,這很大原因是你沒有在16ms完成
Android 系統性能優化(16)--Android 系統性能優化第4季
1)Cachematters for networking想要使得Android系統上的網路訪問操作更加的高效就必須做好網路資料的快取。這是提高網路訪問效能最基礎的步驟之一。從手機的快取中直接讀取資料肯定比從網路上獲取資料要更加的便捷高效,特別是對於那些會被頻繁訪問到的資料,
Android 系統性能優化(52)---移動端效能監控方案Hertz
效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等導致的。即便是最有經驗的程式設計師
Android 系統性能優化(34)---Android UI 效能優化
Android官網 Slow rendering;個人覺得非常有價值,比如指出 物件分配、垃圾回收(GC)、執行緒排程以及Binder呼叫 是Android系統中常見的卡頓原因,更重要的是給出了定位和解決這些問題的方案;而非簡單地告訴你避免物件分配,減少佈局層級,減少過度
Android系統性能優化(64)---build.設定
1. 強制把Home程式駐入記憶體.引數:ro.HOME_APP_ADJ=12.提高 JPG 質量為 100%引數:ro.media.enc.jpeg.quality=1003. VM 虛擬堆大小; 提高 RAM引數:dalvik.vm.heapsize=48m4. 使用 GPU 渲染UI引數:debug.s
Android 系統性能優化(28)---Android 效能優化工具集合
磁碟檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快
Android系統性能優化(44)---全面&詳細的記憶體優化指南
前言在 Android開發中,效能優化策略十分重要本文主要講解效能優化中的記憶體優化,希望你們會喜歡目錄1. 定義優化處理 應用程式的記憶體使用、空間佔用2. 作用避免因不正確使用記憶體 & 缺乏管理,從而出現 記憶體洩露(ML)、記憶體溢位(OOM)、記憶體空間佔用
Android 系統性能優化(30)---Android效能全面分析與優化方案研究
5.1、渲染問題先來看看造成應用UI卡頓的常見原因都有哪些?1、人為在UI執行緒中做輕微耗時操作,導致UI執行緒卡頓;2、佈局Layout過於複雜,無法在16ms內完成渲染;3、同一時間動畫執行的次數過多,導致CPU或GPU負載過重;4、View過度繪製,導致某些畫素在同一幀時間內被繪製多次,從而使CPU或G
Android繪制優化(一)繪制性能分析
pro -i tco public 繼續 但是 們的 sched mda 前言 一個優秀的應用不僅僅是要有吸引人的功能和交互,同時在性能上也有很高的要求。運行Android系統的手機,雖然配置在不斷的提升,但仍舊無法和PC相比,無法做到PC那樣擁有超大的內存以及高性能的CP
Mysql數據庫性能優化(一)
效率 dir sort variables 緩存 模型 mysql5.6 包含 dpt 參考 http://www.jb51.net/article/82254.htm 今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對於Web應用尤其明顯。關於數據庫的性能,這並不只
Android內存優化(一)DVM和ART原理初探
java虛擬機 劃分 cimage beef 靜態 由於 jar blank 查找 要學習Android的內存優化,首先要了解Java虛擬機,此前我用了多篇文章來介紹Java虛擬機的知識,就是為了這個系列做鋪墊。在Android開發中我們接觸的是與Java虛擬機類似的Dal
mysql性能優化(一)
配置文件 mysql 數據庫 網絡 信息 mysql性能優化、慢查詢分析、優化索引和配置一.每項的基本思路步驟1.性能瓶頸定位:show命令、慢查詢日誌、explain分析查詢、profiling分析查詢、2.索引及查詢優化3.配置優化二.my
Web頁面性能優化(YSlow)
java 字符 新版 目標 網絡 imp web頁面 檢查 用戶 YSlow(解析為Why Slow)是雅虎基於網站優化規則推出的工具,幫助你分析並優化網站性能。舊版Yslow 有13條規則,新版Yslow有23項規則,YSlow會根據這些規則分析你的網站,並給出評級。
從-View-繪制談性能優化(轉)
有趣 || left 例子 bject create 我想 roo 並且 在開發過程中,往往會聽到 “性能優化” 這個概念,這個概念很大,比如網絡性能優化、耗電量優化等等,對我們開發者而言,最容易做的,或者是影響最大的,應該是 View 的性能優化。一般小項目或許用不上
前端性能優化(一):桌面瀏覽器前端優化策略
data lan ucc 靜態 sync 怎樣 拆分 打包成 pan 摘要: 前端性能優化是一個很寬泛的概念,本書前面的部分也多多少少提到一些前端優化方法,這也是我們一直在關註的一件重要事情。配合各種方式、手段、輔助系統,前端優化的最終目的都是提升用戶體驗,改善頁面性能,我
前端性能優化(二):移動端瀏覽器前端優化策略
因此 本地 網絡流量 桌面 cse kit 極致 加載 文件 相對於桌面端瀏覽器,移動端Web瀏覽器上有一些較為明顯的特點:設備屏幕較小、新特性兼容性較好、支持一些較新的HTML5和CSS3特性、需要與Native應用交互等。但移動端瀏覽器可用的CPU計算資源和網絡資源極為
10種簡單的Java性能優化(轉)
IT none hset 工作流程 執行 為什麽 util 服務器 也有 本文由 ImportNew - 一直在路上 翻譯自 jaxenter。歡迎加入翻譯小組。轉載請見文末要求。你是否正打算優化hashCode()方法?是否想要繞開正則表達
sqlserver2008查詢性能優化(文摘)
TP ron 性能 分析 bubuko inf tro str sqlserve 第1章 sql查詢性能調整 第4章 索引分析 sqlserver2008查詢性能優化(文摘)