1. 程式人生 > 其它 >專項測試實戰 | 如何測試 App 流暢度(基於 FPS 和丟幀率)?

專項測試實戰 | 如何測試 App 流暢度(基於 FPS 和丟幀率)?


FPS 和丟幀率可以在一定程度上作為 APP 流暢度的一項衡量標準,本文介紹利用 adb shell dumpsys gfxinfo 命令獲取軟體渲染載入過程的資料,進行計算從而獲取測試結果。
在此之前,需要先了解螢幕展示繪製過程及 Android 的 VSync 機制
VSync 全稱是 Vertical Synchronization(垂直同步),在 Android 4.1 中引入 Android 系統(同時引入的一個概念是 Triple Buffering)。
學計算機的經常聽到 Buffer 的概念(生活中也碰到過很多),起到的都是一個類似的作用。用來協調兩個不同速度的東西工作。
為什麼會這樣呢?因為 CPU/GPU 處理和螢幕展示的速度不一樣但是卻使用的是同一塊記憶體。
怎麼解決呢?可以將 CPU/GPU 處理和螢幕展示分開,CPU/GPU 在後臺處理,處理完一幀的資料以後才交給螢幕展示(這樣可能導致另外的問題是,如果 CPU/GPU 處理很慢,那麼螢幕可能會一直展示某一幀的資料,下面主要分析這個問題的處理)。

  • 手機螢幕重新整理率:手機硬體每秒重新整理螢幕的次數,單位 HZ。一般是一個固定值,例如 60HZ。
  • FPS:畫面每秒傳輸幀數,通俗來講就是指動畫或視訊的畫面數。單位 HZ。
    手機螢幕重新整理率是固定的,FPS 則是一直變化的,怎麼才能保證能夠執行流暢呢?從幾個例子來看吧。
    先解釋圖片代表的意思:最下面黑線代表的是時間,黃色代表螢幕展示,綠色代表 GPU 處理,藍色代表 CPU 處理。Jank 代表的是重複展示上一幀的異常。下面會從螢幕展示的每一幀開始分析:

上圖是沒有引入VSync 機制的處理流程。

  • Display 展示第0幀資料,這時 CPU/GPU 會去處理第1幀的資料。
  • Display 展示第1幀資料(此時螢幕顯示是正常的),這時 CPU/GPU 可能處理其他任務導致很晚才去處理繪製。
  • 因為 CPU/GPU 沒處理好第2幀的資料,所以 Display 還是展示第1幀資料(此時螢幕顯示是異常的),CPU/GPU 處理完第2幀沒有處理完的資料然後繼續處理第3幀的資料。
  • 上圖中一個很明顯的問題是,只要一次 CPU/GPU 處理出現異常就可能導致後面的一系列的處理出現異常。
    VSync 可以簡單的認為是一種定時中斷,系統在每次需要繪製的時候都會發送VSync Pulse 訊號,CPU/GPU 收到訊號後馬上處理繪製。
    在4.1以後引入VSync 機制。

在 FPS < 手機螢幕重新整理率的情況下,一切執行完美。
VSync 機制下 Double Buffering 時 FPS > 手機螢幕重新整理率的情況。

  • Display 展示第A 幀資料,CPU/GPU 收到 VSync Pulse 訊號馬上處理B 幀的資料,但是由於計算太多,導致沒有在一個 VSync 間隔內處理完。
  • 由於第B 幀資料沒有處理好,Display 繼續展示第A 幀資料(此時螢幕顯示是異常的)。由於系統中只存在一塊記憶體給 CPU/GPU 處理繪製,所以在這個 VSync 間隔內cpu 不處理任何事。
  • Display 展示第 B 幀資料,CPU/GPU 收到 VSync Pulse 訊號馬上處理即將展示A 幀的資料,由於計算太多,導致沒有在一個 VSync 間隔內處理完。
  • 需要展示的A 幀資料沒有處理好,Display 繼續展示第 B 幀資料(此時螢幕顯示是異常的)。由於系統中只存在一塊記憶體給 CPU/GPU 處理繪製,所以在這個 VSync 間隔內 CPU 不處理任何事。

    上圖中一個很明顯的問題是,只要出現一次Jank 就會影響下一次的VSync(cpu 不能工作)。
    Triple Buffering 的引入。
  • Display 展示第A 幀資料,CPU/GPU 收到VSync Pulse 訊號馬上處理B 幀的資料,但是由於計算太多,導致沒有在一個VSync 間隔內處理完。
    由於第B 幀資料沒有準備好,Display 繼續展示第A 幀資料(此時螢幕顯示是異常的)。此時雖然B 被gpu 在使用,但是cpu 可以處理Buffer C(因為有3個緩衝)。
  • Display 展示第B 幀資料,gpu 繼續處理上一步驟的C,cpu 則處理A。
    後續過程出錯的情況被降低了…
    1.執行命令"adb -s " + deviceName + " shell dumpsys gfxinfo " + packageName 獲取基礎資料,我們會獲得很多資料,這裡擷取需要進行分析的部分:
    注:如果執行完命令發現無上圖中的4個引數,則很可能是手機的“GPU呈現模式分析”未開啟;
    2.如上圖資訊表示了每一幀在安卓系統中的四個階段:
  • Draw: 表示在Java中建立顯示列表部分中,OnDraw()方法佔用的時間
  • Prepare: 準備時間
  • Process:表示渲染引擎執行顯示列表所花的時間,view越多,時間就越長
  • Execute:表示把一幀資料傳送到螢幕上排版顯示實際花費的時間,其實是實際顯示幀資料的後臺快取區與前臺緩衝區交換後並將前臺緩衝區的內容顯示到螢幕上的時間
  • 將上面的四個時間加起來就是繪製一幀所需要的時間,如果超過了16.67就表示掉幀了
    Android 定義了流暢度的資料標準,以 60FPS 為標準(FPS 為每秒繪製的幀數),幀數過小就會出現卡頓感。
    每一幀在安卓系統中分4個階段,4個階段的總和超過16.67(1秒60幀,算下來平均1幀的間隔就約是16.67ms)就認為丟幀。
    這個定義在 Android6.0 以前是一定的,但是現在已經沒有固定的標準了,因為目前安卓系統有3層快取機制,加上硬體上的進步,即使超過16.67,也不一定會出現卡頓感。所以這個資料在測試時作為一種對比和相對衡量標準,也可根據需求自定義標準。
    通過以上資料,就可以獲取到每一幀的時間、總幀數;從而就可以計算出 jank 數、vsync 數,進而就可以得到最終的 FPS 和丟幀率資料。
    當然,手工計算無疑效率低,出錯率大,所以這裡的計算過程最好還是以指令碼形式,讓程式碼幫我們去計算,具體程式碼計算原理與專項自動化過程後續探討。

原文連結

⬇️ 點選“下方連結”,提升測試核心競爭力!https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=bokeyuan&timestamp=1650617583

>>更多技術文章分享和免費資料領取