做的好的中醫(yī)網(wǎng)站廣州新聞熱點(diǎn)事件
“?最近忙著新房子裝修的事情,這篇計(jì)劃內(nèi)的文章拖了好久一直沒(méi)有足夠的時(shí)間來(lái)寫(xiě)作,終于擠出些兒時(shí)間來(lái)繼續(xù)研究學(xué)習(xí)了。”
整了四個(gè)晚上終于拼湊出一篇文章,雖說(shuō)是講FPS計(jì)算原理,但該文涉及的知識(shí)點(diǎn)還是蠻多的,特別是對(duì)于present fence的來(lái)龍去脈重點(diǎn)做了分析,還牽涉到一些合成&HWC的邏輯。全文5000多字,內(nèi)容豐滿(mǎn)。一個(gè)業(yè)余愛(ài)好者的拙劣認(rèn)知,請(qǐng)大家審慎閱讀!
01
前言
FPS即Frames Per Second,表示每秒顯示的幀數(shù)。作為衡量UI流暢度、視頻播放性能、游戲性能的基礎(chǔ)指標(biāo),開(kāi)發(fā)者通常會(huì)觀(guān)察FPS來(lái)評(píng)價(jià)應(yīng)用是否有掉幀/卡頓等性能問(wèn)題。前面我們分享了兩篇計(jì)算FPS的文章:
Android Graphics 顯示系統(tǒng) - 監(jiān)測(cè)、計(jì)算FPS的工具及設(shè)計(jì)分析
Android Graphics 顯示系統(tǒng) - 通過(guò)dumpsys SurfaceFlinger --latency計(jì)算FPS
那這些方法計(jì)算FPS的原理是什么呢?本篇我們就著手探索下利用dumpsys SurfaceFlinger --latency計(jì)算FPS的原理
02
Fence的概念
在介紹FPS計(jì)算原理前,需要先理解Android中Fence的概念。在前面的文章中我們有對(duì)Fence做過(guò)講解,這里我們就簡(jiǎn)略贅述。
Android Graphics 顯示系統(tǒng) - GraphicBuffer同步機(jī)制-Fence(二十)
Fence是什么呢?
Fence,直譯為“柵欄”,用來(lái)把某個(gè)東西攔截住。顧名思義,它是一種同步機(jī)制:把東西攔截住,又在合適的時(shí)機(jī)放行,達(dá)到同步的效果。
CPU、GPU、HWC是異步工作的,所以需要Fence這種同步機(jī)制來(lái)協(xié)調(diào)他們的工作。
那么Fence要攔住什么東西呢?
就是GraphicBuffer。GraphicBuffer中存放了應(yīng)用繪制好的待要顯示的數(shù)據(jù),GraphicBuffer在整個(gè)繪制、合成、顯示的過(guò)程中一直在 CPU、GPU 和 HWC 之前傳遞,某一方要使用GraphicBuffer之前,需要先檢查上一個(gè)使用者是否已經(jīng)移交了GraphicBuffer的“使用權(quán)”。而這里的“使用權(quán)”,就是Fence。當(dāng)Fence 釋放(即signal)的時(shí)候,說(shuō)明GraphicBuffer的上一個(gè)使用者已經(jīng)交出了使用權(quán),此時(shí)對(duì)于GraphicBuffer 進(jìn)行操作(read or write)是安全的。
Android中有哪些Fence呢?
在A(yíng)ndroid里面,總共有3類(lèi)Fence:
-
acquire fence
生產(chǎn)者(App)將GraphicBuffer通過(guò)queueBuffer()還給BufferQueue的時(shí)候,此時(shí)異步工作的GPU可能還沒(méi)有完成繪制,此時(shí)會(huì)帶上一個(gè)Fence,這個(gè) Fence就是acquire fence。當(dāng)消費(fèi)者(SurfaceFlinger/HWC)要讀取GraphicBuffer以進(jìn)行合成操作的時(shí)候,需要等acquire fence釋放之后才行。
acquire fence就是生產(chǎn)者用來(lái)告訴消費(fèi)者生產(chǎn)數(shù)據(jù)完成的同步信號(hào)!
-
release fence
當(dāng)生產(chǎn)者(App)通過(guò)dequeueBuffer()從BufferQueue申請(qǐng)到一塊GraphicBuffer,要對(duì)GraphicBuffer進(jìn)行繪制(寫(xiě)操作)的時(shí)候,需要保證消費(fèi)者(上一個(gè)使用者)已經(jīng)不再使用這個(gè)GraphicBuffer了,即需要等release fence signal才能對(duì)這塊GraphicBuffer進(jìn)行寫(xiě)操作。
acquire fence就是消費(fèi)者用來(lái)告訴生產(chǎn)者Buffer中的數(shù)據(jù)我已消費(fèi)完畢的信號(hào)!
-
present fence?
當(dāng)前幀成功顯示到屏幕的時(shí)候,present fence就會(huì)signal。
解釋比較簡(jiǎn)略,建議大家閱讀Android官網(wǎng)的英文解讀,從不同角度并結(jié)合API理解
https://source.android.com/docs/core/graphics/sync
03
計(jì)算Layer FPS的方法
計(jì)算Layer FPS的方法我們前面提供了兩種方法,本篇我們主要分析利用dumpsys命令計(jì)算FPS的原理:
dumpsys SurfaceFlinger --latency Layer-name
讓我們看看這條命令執(zhí)行后會(huì)輸出什么內(nèi)容呢?
以播放Youtube視頻時(shí)抓取信息為例:
首先,看看當(dāng)前可見(jiàn)圖層的狀況
$?adb?shell?dumpsys?SurfaceFlinger?--hwclayers
Display?4629995505126966272?(active)?HWC?layers:
---------------------------------------------------------------------------------------------------------------------------------------------------------------Layer?nameZ?|??Window?Type?|??Comp?Type?|??Transform?|???Disp?Frame?(LTRB)?|??????????Source?Crop?(LTRB)?|?????Frame?Rate?(Explicit)?(Seamlessness)?[Focused]
---------------------------------------------------------------------------------------------------------------------------------------------------------------SurfaceView[com.google.android.youtu[...].tv.activity.MainActivity](BLAST)#99rel??????0?|????????????0?|?????DEVICE?|??????????0?|????0????0?1920?1080?|????0.0????0.0?1920.0?1080.0?|??????????????????????????????????????????????[*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------com.google.android.youtube.tv/com.go[...].youtube.tv.activity.MainActivity#96rel??????0?|????????????1?|?????CLIENT?|??????????0?|????0????0?1920?1080?|????0.0????0.0?1920.0?1080.0?|??????????????????????????????????????????????[*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
可知,Youtube播放時(shí)是有一個(gè)SurfaceView來(lái)顯示video畫(huà)面的,我們要監(jiān)測(cè)的圖層也是這個(gè)SurfaceView,它的id是#99
然后要獲取這個(gè)layer的完整名字
$?adb?shell?dumpsys?SurfaceFlinger?--list
Display?0?name="Built-in?Screen"#363cfece?ActivityRecordInputSink?com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#102
ActivityRecord{eef71ef?u0?com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#94
e145d51?com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#95
Background?for?SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]#100
SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]#98
SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity](BLAST)#99
最后執(zhí)行dumpsys SurfaceFlinger --latency看看到底會(huì)輸出什么內(nèi)容:
$?adb?shell?dumpsys?SurfaceFlinger?--latency?"SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]\(BLAST\)#99"
16683294
6870189659137???6870202006496???6870189659137
6870206342431???6870218689941???6870206342431
6870223025725???6870235371015???6870223025725
6870239709019???6870252064348???6870239709019
6870256392313???6870268737385???6870256392313
6870273075607???6870285421718???6870273075607
6870289758901???6870302111163???6870289758901
6870306442195???6870318792718???6870306442195
6870323125489???6870335474904???6870323125489
6870339808783???6870352160978???6870339808783
6870356492077???6870368841496???6870356492077
6870373175371???6870385524422???6870373175371
......
一坨一坨的數(shù)字到底是啥意思呢?
-
第一行的數(shù)字
代表當(dāng)前的VSYNC間隔,單位是納秒。例如現(xiàn)在的屏幕刷新率是60Hz的,因此就是16.6ms
-
后面?3列127行 的數(shù)字
每一行有 3 個(gè)數(shù)字,每個(gè)數(shù)字都是時(shí)間戳,單位是納秒,分別表示 desiredPresentTime,actualPresentTime,frameReadyTime,在計(jì)算FPS的時(shí)候,使用的是第二個(gè)時(shí)間戳。
actualPresentTime就是present fence signal的時(shí)間,根據(jù)獲取的這127個(gè)actualPresentTime數(shù)據(jù),就可以計(jì)算一秒內(nèi)有多少個(gè)present fence signal了,也即多少幀刷新到屏幕了。
計(jì)算公式
更多信息閱讀原文
Android Graphics 顯示系統(tǒng) - 計(jì)算FPS的原理與探秘Present Fence