python实时获取Android FPS
python---實現(xiàn)實時獲取Android FPS
- 1:如何計算FPS信息?
- 2:如何獲取FPS信息?
- 3:python實現(xiàn) fps實時獲取和計算
- 使用adb shell dumpsys gfxinfo 獲取fps信息
- 1:在開始獲取fps信息之前,我們先進行獲取當(dāng)前活動窗口,get_focus_window
- 2:在開始獲取fps信息之前,我們先進行清除當(dāng)前窗口fps數(shù)據(jù)
- 3:使用shell dumpsys gfxinfo +包名 + framestats 獲取的這個進程的最近128幀的的詳細信息,可能包含多個窗口(也可能包含重復(fù)幀,也可能沒有128幀)
- 4:去除重復(fù)幀
- 5:計算FPS,jank,卡頓
- 6:python腳本實現(xiàn)
1:如何計算FPS信息?
標(biāo)準(zhǔn)的FPS 是 1s 60 幀,也就是16.67ms一幀渲染完成,用戶不會覺得卡頓。但是大部分應(yīng)用是不需要1s內(nèi)繪制60幀,我們需要根據(jù)丟幀率去計算fps,如果1s內(nèi)應(yīng)用只需要繪制30幀,但每幀的時間是不超過16.67ms,那么它的fps也是60。
當(dāng)一幀渲染的時間大于16.67ms,按照垂直同步機制,該幀就已經(jīng)渲染超時,那么,如果它正好是16.67的整數(shù)倍,比如66.68,則它花費了4個垂直同步脈沖,減去本身需要一個,則超時3個;如果它不是16.67的整數(shù)倍,比如67,那么它花費的垂直同步脈沖應(yīng)向上取整,即5個,減去本身需要一個,即超時4個,可直接算向下取整
最后的計算方法思路:
執(zhí)行一次命令,總共收集到了m幀(理想情況下m=128),但是這m幀里面有些幀渲染超過了16.67毫秒,算一次jank,一旦jank,
需要用掉額外的垂直同步脈沖。其他的就算沒有超過16.67,也按一個脈沖時間來算(理想情況下,一個脈沖就可以渲染完一幀)
所以FPS的算法可以變?yōu)?#xff1a;
m / (m + 額外的垂直同步脈沖) * 60
2:如何獲取FPS信息?
Android性能測試之fps獲取
安卓8.0之前使用dumpsys SurfaceFlinger 獲取FPS信息詳解(必看)
adb shell dumpsys SurfaceFlinger --latency <window_activity>
安卓9.0之后使用dumpsys gfxinfo framestats 獲取FPS信息詳解(必看)
adb shell dumpsys gfxinfo < PACKAGE_NAME > framestats
兩種都是獲取指定窗口的詳細顯示信息,需要了解每一列參數(shù)的詳細信息
以9.0之后使用dumpsys gfxinfo 獲取信息為例:
每一幀的時間就是 FRAME_COMPLETED - INTENDED_VSYNC ,時間是以ns為單位
3:python實現(xiàn) fps實時獲取和計算
使用adb shell dumpsys gfxinfo 獲取fps信息
由于是根據(jù)包名獲取每一幀的詳細信息,且最多只能獲取128幀,所以最理想的狀態(tài)就是2s內(nèi)手機繪制了120幀,但大部分應(yīng)用2s內(nèi)是不會繪制120幀的,所以根據(jù)實際項目需要,我們需要設(shè)置不同的時間間隔去獲取fps,此處我們使用2s間隔獲取一次fps數(shù)據(jù),相同時間內(nèi),繪制的幀越多,則fps越準(zhǔn)確。
self.frequency = 2 取樣頻率 就是每間隔2秒獲取一次fps信息
sn是設(shè)備id
_collector_thread 是用來獲取fps信息的線程
_calculator_thread 是用來計算fps的線程
定義大于16.67ms為丟幀 jank
定義大于166.7ms為卡頓 caton
1:在開始獲取fps信息之前,我們先進行獲取當(dāng)前活動窗口,get_focus_window
adb shell dumpsys activity | findstr mResume(適用于安卓9.0之后的,安卓8.0之前可使用adb shell dumpsys activity | findstr “mFocusedActivity”)
C:\Users\ysfa>adb shell dumpsys activity | findstr mResumemResumedActivity: ActivityRecord{db71ee8 u0 com.android.settings/.SubSettings t1572}com.android.settings/.SubSettings 這個則是當(dāng)前手機上活動的窗口名(包名省略為.)
注意! 部分三方應(yīng)用的窗口會把包名全部顯示,例如com.eg.android.AlipayGphone/com.alipay.mobile.security.login.ui.RecommandAlipayUserLoginActivity
拿到窗口名,我們可以提取出包名+窗口名的信息
因為使用shell dumpsys gfxinfo +包名+framestats 獲取的這個進程的最近128幀的的詳細信息,可能包含多個窗口(也可能包含重復(fù)幀),而信息中的窗口名是全名,沒有.省略包名,所以我們需要自己拼出完整的窗口名
如將com.android.settings/.SubSettings 改成com.android.settings/com.android.settings.SubSettings
**
2:在開始獲取fps信息之前,我們先進行清除當(dāng)前窗口fps數(shù)據(jù)
"adb shell dumpsys gfxinfo " + package_name + " reset"3:使用shell dumpsys gfxinfo +包名 + framestats 獲取的這個進程的最近128幀的的詳細信息,可能包含多個窗口(也可能包含重復(fù)幀,也可能沒有128幀)
例如下面則是有兩個窗口
C:\Users\ysfa>adb shell dumpsys gfxinfo com.android.settings framestats Applications Graphics Acceleration Info: Uptime: 56776419 Realtime: 113853289** Graphics info for pid 15490 [com.android.settings] **Stats since: 43790991914179ns Total frames rendered: 1021 Janky frames: 52 (5.09%) 50th percentile: 6ms 90th percentile: 11ms 95th percentile: 16ms 99th percentile: 77ms Number Missed Vsync: 11 Number High input latency: 182 Number Slow UI thread: 30 Number Slow bitmap uploads: 0 Number Slow issue draw commands: 1 Number Frame deadline missed: 31 HISTOGRAM: 5ms=486 6ms=157 7ms=112 8ms=65 9ms=49 10ms=27 11ms=33 12ms=18 13ms=13 14ms=2 15ms=6 16ms=2 17ms=2 18ms=0 19ms=4 20ms=1 21ms=1 22ms=0 23ms=4 24ms=1 25ms=1 26ms=2 27ms=1 28ms=3 29ms=0 30ms=0 31ms=0 32ms=3 34ms=0 36ms=1 38ms=1 40ms=4 42ms=2 44ms=3 46ms=0 48ms=0 53ms=2 57ms=2 61ms=0 65ms=0 69ms=1 73ms=1 77ms=3 81ms=2 85ms=0 89ms=1 93ms=0 97ms=0 101ms=0 105ms=1 109ms=1 113ms=0 117ms=0 121ms=0 125ms=1 129ms=0 133ms=0 150ms=2 200ms=0 250ms=0 300ms=0 350ms=0 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0 650ms=0 700ms=0 750ms=0 800ms=0 850ms=0 900ms=0 950ms=0 1000ms=0 1050ms=0 1100ms=0 1150ms=0 1200ms=0 1250ms=0 1300ms=0 1350ms=0 1400ms=0 1450ms=0 1500ms=0 1550ms=0 1600ms=0 1650ms=0 1700ms=0 1750ms=0 1800ms=0 1850ms=0 1900ms=0 1950ms=0 2000ms=0 2050ms=0 2100ms=0 2150ms=0 2200ms=0 2250ms=0 2300ms=0 2350ms=0 2400ms=0 2450ms=0 2500ms=0 2550ms=0 2600ms=0 2650ms=0 2700ms=0 2750ms=0 2800ms=0 2850ms=0 2900ms=0 2950ms=0 3000ms=0 3050ms=0 3100ms=0 3150ms=0 3200ms=0 3250ms=0 3300ms=0 3350ms=0 3400ms=0 3450ms=0 3500ms=0 3550ms=0 3600ms=0 3650ms=0 3700ms=0 3750ms=0 3800ms=0 3850ms=0 3900ms=0 3950ms=0 4000ms=0 4050ms=0 4100ms=0 4150ms=0 4200ms=0 4250ms=0 4300ms=0 4350ms=0 4400ms=0 4450ms=0 4500ms=0 4550ms=0 4600ms=0 4650ms=0 4700ms=0 4750ms=0 4800ms=0 4850ms=0 4900ms=0 4950ms=0 Font Cache (CPU):Size: 623.27 kBGlyph Count: 41 CPU Caches: GPU Caches:Other:Other: 0.00 bytes (1 entry)Buffer Object: 2.05 KB (2 entries)Image:Texture: 151.12 KB (13 entries)Scratch:RenderTarget: 9.00 KB (1 entry)Buffer Object: 48.00 KB (1 entry)Texture: 4.00 MB (1 entry) Other Caches:Current / MaximumVectorDrawableAtlas 0.00 kB / 0.00 KB (entries = 0)Layers Total 0.00 KB (numLayers = 0) Total GPU memory usage:4409524 bytes, 4.21 MB (153.18 KB is purgeable)Pipeline=Skia (OpenGL)Layout Cache Info:Usage: 513/5000 entriesHit ratio: 15858/16371 (0.968664) Profile data in ms:com.android.settings/com.android.settings.Settings/android.view.ViewRootImpl@f131882 (visibility=8) Window: com.android.settings/com.android.settings.Settings Stats since: 52644835521687ns Total frames rendered: 5 Janky frames: 2 (40.00%) 50th percentile: 5ms 90th percentile: 53ms 95th percentile: 53ms 99th percentile: 53ms Number Missed Vsync: 0 Number High input latency: 2 Number Slow UI thread: 1 Number Slow bitmap uploads: 0 Number Slow issue draw commands: 0 Number Frame deadline missed: 1 HISTOGRAM: 5ms=3 6ms=0 7ms=0 8ms=0 9ms=0 10ms=0 11ms=0 12ms=0 13ms=0 14ms=0 15ms=0 16ms=0 17ms=0 18ms=0 19ms=0 20ms=0 21ms=0 22ms=0 23ms=0 24ms=0 25ms=0 26ms=0 27ms=0 28ms=0 29ms=0 30ms=0 31ms=0 32ms=0 34ms=0 36ms=0 38ms=0 40ms=0 42ms=1 44ms=0 46ms=0 48ms=0 53ms=1 57ms=0 61ms=0 65ms=0 69ms=0 73ms=0 77ms=0 81ms=0 85ms=0 89ms=0 93ms=0 97ms=0 101ms=0 105ms=0 109ms=0 113ms=0 117ms=0 121ms=0 125ms=0 129ms=0 133ms=0 150ms=0 200ms=0 250ms=0 300ms=0 350ms=0 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0 650ms=0 700ms=0 750ms=0 800ms=0 850ms=0 900ms=0 950ms=0 1000ms=0 1050ms=0 1100ms=0 1150ms=0 1200ms=0 1250ms=0 1300ms=0 1350ms=0 1400ms=0 1450ms=0 1500ms=0 1550ms=0 1600ms=0 1650ms=0 1700ms=0 1750ms=0 1800ms=0 1850ms=0 1900ms=0 1950ms=0 2000ms=0 2050ms=0 2100ms=0 2150ms=0 2200ms=0 2250ms=0 2300ms=0 2350ms=0 2400ms=0 2450ms=0 2500ms=0 2550ms=0 2600ms=0 2650ms=0 2700ms=0 2750ms=0 2800ms=0 2850ms=0 2900ms=0 2950ms=0 3000ms=0 3050ms=0 3100ms=0 3150ms=0 3200ms=0 3250ms=0 3300ms=0 3350ms=0 3400ms=0 3450ms=0 3500ms=0 3550ms=0 3600ms=0 3650ms=0 3700ms=0 3750ms=0 3800ms=0 3850ms=0 3900ms=0 3950ms=0 4000ms=0 4050ms=0 4100ms=0 4150ms=0 4200ms=0 4250ms=0 4300ms=0 4350ms=0 4400ms=0 4450ms=0 4500ms=0 4550ms=0 4600ms=0 4650ms=0 4700ms=0 4750ms=0 4800ms=0 4850ms=0 4900ms=0 4950ms=0---PROFILEDATA--- Flags,IntendedVsync,Vsync,OldestInputEvent,NewestInputEvent,HandleInputStart,AnimationStart,PerformTraversalsStart,DrawStart,SyncQueued,SyncStart,IssueDrawCommandsStart,SwapBuffers,FrameCompleted,DequeueBufferDuration,QueueBufferDuration, 1,52644835725530,52644835725530,9223372036854775807,0,52644839507156,52644839521322,52644839522208,52644882804499,52644884679760,52644884854083,52644884964447,52644890317208,52644890604395,398000,115000, 0,52644852435274,52644885768606,9223372036854775807,0,52644891648406,52644891663354,52644892190333,52644892544864,52644894457364,52644894569864,52644894716947,52644896089499,52644896420489,323000,130000, 0,52644902567663,52644902567663,9223372036854775807,0,52644903024135,52644903036687,52644903037624,52644903244812,52644903515385,52644903659551,52644903796322,52644905614239,52644906009603,485000,155000, 0,52645654850958,52645654850958,9223372036854775807,0,52645655074707,52645655090697,52645655092832,52645655544968,52645655855541,52645656225228,52645656841530,52645659397416,52645659824343,353000,136000, 0,52645688284367,52645688284367,9223372036854775807,0,52645688486895,52645688497624,52645688498874,52645688666322,52645688838822,52645688971218,52645689081166,52645689787416,52645690071426,71000,102000, ---PROFILEDATA---com.android.settings/com.android.settings.SubSettings/android.view.ViewRootImpl@3253b93 (visibility=8) Window: com.android.settings/com.android.settings.SubSettings Stats since: 52648079271686ns Total frames rendered: 135 Janky frames: 9 (6.67%) 50th percentile: 7ms 90th percentile: 12ms 95th percentile: 23ms 99th percentile: 44ms Number Missed Vsync: 1 Number High input latency: 39 Number Slow UI thread: 5 Number Slow bitmap uploads: 0 Number Slow issue draw commands: 0 Number Frame deadline missed: 5 HISTOGRAM: 5ms=39 6ms=15 7ms=27 8ms=13 9ms=9 10ms=3 11ms=10 12ms=7 13ms=2 14ms=0 15ms=1 16ms=0 17ms=0 18ms=0 19ms=0 20ms=1 21ms=0 22ms=0 23ms=2 24ms=0 25ms=0 26ms=1 27ms=0 28ms=0 29ms=0 30ms=0 31ms=0 32ms=2 34ms=0 36ms=0 38ms=0 40ms=1 42ms=0 44ms=1 46ms=0 48ms=0 53ms=0 57ms=1 61ms=0 65ms=0 69ms=0 73ms=0 77ms=0 81ms=0 85ms=0 89ms=0 93ms=0 97ms=0 101ms=0 105ms=0 109ms=0 113ms=0 117ms=0 121ms=0 125ms=0 129ms=0 133ms=0 150ms=0 200ms=0 250ms=0 300ms=0 350ms=0 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0 650ms=0 700ms=0 750ms=0 800ms=0 850ms=0 900ms=0 950ms=0 1000ms=0 1050ms=0 1100ms=0 1150ms=0 1200ms=0 1250ms=0 1300ms=0 1350ms=0 1400ms=0 1450ms=0 1500ms=0 1550ms=0 1600ms=0 1650ms=0 1700ms=0 1750ms=0 1800ms=0 1850ms=0 1900ms=0 1950ms=0 2000ms=0 2050ms=0 2100ms=0 2150ms=0 2200ms=0 2250ms=0 2300ms=0 2350ms=0 2400ms=0 2450ms=0 2500ms=0 2550ms=0 2600ms=0 2650ms=0 2700ms=0 2750ms=0 2800ms=0 2850ms=0 2900ms=0 2950ms=0 3000ms=0 3050ms=0 3100ms=0 3150ms=0 3200ms=0 3250ms=0 3300ms=0 3350ms=0 3400ms=0 3450ms=0 3500ms=0 3550ms=0 3600ms=0 3650ms=0 3700ms=0 3750ms=0 3800ms=0 3850ms=0 3900ms=0 3950ms=0 4000ms=0 4050ms=0 4100ms=0 4150ms=0 4200ms=0 4250ms=0 4300ms=0 4350ms=0 4400ms=0 4450ms=0 4500ms=0 4550ms=0 4600ms=0 4650ms=0 4700ms=0 4750ms=0 4800ms=0 4850ms=0 4900ms=0 4950ms=0---PROFILEDATA--- Flags,IntendedVsync,Vsync,OldestInputEvent,NewestInputEvent,HandleInputStart,AnimationStart,PerformTraversalsStart,DrawStart,SyncQueued,SyncStart,IssueDrawCommandsStart,SwapBuffers,FrameCompleted,DequeueBufferDuration,QueueBufferDuration, 0,52649246791970,52649246791970,9223372036854775807,0,52649247008977,52649247016633,52649247083560,52649247252883,52649247318508,52649247419133,52649247507258,52649247726894,52649247943248,50000,68000, 0,52649263499755,52649263499755,9223372036854775807,0,52649263745904,52649263753456,52649263821425,52649263966112,52649264042935,52649264141008,52649264225852,52649264446789,52649264594394,52000,75000, 0,52649280172678,52649280172678,9223372036854775807,0,52649280390643,52649280398821,52649280492779,52649280826789,52649280901841,52649280991789,52649281092258,52649282058143,52649282244029,719000,84000, 0,52649296908974,52649296908974,9223372036854775807,0,52649297192571,52649297200956,52649297272987,52649297500748,52649297570018,52649297660071,52649297755123,52649298330800,52649298491789,388000,79000, 0,52649314226393,52649314226393,9223372036854775807,0,52649314576321,52649314590643,52649314682414,52649314878300,52649314976946,52649315080487,52649315199237,52649316256841,52649316463873,718000,87000, 0,52649330956704,52649330956704,9223372036854775807,0,52649331218456,52649331229706,52649331328925,52649331494654,52649331568821,52649331661529,52649331772883,52649332717258,52649332905748,693000,84000, 0,52649347049758,52649347049758,9223372036854775807,0,52649347281893,52649347293143,52649347379706,52649347608196,52649347693039,52649347778196,52649347890591,52649348834498,52649349042987,683000,102000, 0,52649697887620,52649697887620,9223372036854775807,0,52649702086373,52649702120643,52649702124862,52649703167310,52649708892727,52649709473560,52649710831060,52649717494654,52649718642466,499000,464000, 0,52649714600252,52649714600252,9223372036854775807,0,52649715011216,52649715042466,52649715046477,52649715644810,52649719492414,52649719910852,52649720709706,52649722900956,52649723371060,160000,184000, 0,52649731310975,52649731310975,9223372036854775807,0,52649731588612,52649731612362,52649731614758,52649732029341,52649734277570,52649734497466,52649735169029,52649737701372,52649738107883,160000,161000, 0,52649748021669,52649748021669,9223372036854775807,0,52649748340227,52649748360800,52649748363664,52649748845122,52649751609810,52649751923977,52649752743716,52649755433664,52649755953768,149000,243000, 0,52649764732139,52649764732139,9223372036854775807,0,52649765139289,52649765163195,52649765167258,52649765903091,52649769690539,52649770072206,52649770664966,52649774161997,52649774849550,193000,338000, 0,52649781442682,52649781442682,9223372036854775807,0,52649781792310,52649781814237,52649781818195,52649782385487,52649785698872,52649786096425,52649786659341,52649790374706,52649791046529,224000,310000, 0,52649798153253,52649798153253,9223372036854775807,0,52649798517831,52649798542050,52649798546060,52649799112883,52649802161268,52649802525435,52649803129602,52649806656581,52649807274602,240000,271000, 0,52649814863694,52649814863694,9223372036854775807,0,52649815799706,52649815828508,52649815832570,52649817335487,52649820929497,52649821328195,52649822128768,52649825968872,52649826741268,241000,395000, 0,52649831574226,52649831574226,9223372036854775807,0,52649831939654,52649831963300,52649831967414,52649832604602,52649835772466,52649836293404,52649836986112,52649840806581,52649841405018,223000,265000, 0,52649848284615,52649848284615,9223372036854775807,0,52649849011372,52649849041425,52649849045018,52649851157727,52649854439497,52649854777466,52649855739810,52649859079862,52649859603872,357000,228000, 0,52649864995380,52649864995380,9223372036854775807,0,52649865322362,52649865343664,52649865346425,52649865810487,52649868761529,52649869067883,52649869989289,52649873253768,52649873828560,151000,228000, 0,52649881706029,52649881706029,9223372036854775807,0,52649882549810,52649882577779,52649882580383,52649883775695,52649886574081,52649886904029,52649887672102,52649890712675,52649891259497,465000,218000, 0,52649898416683,52649898416683,9223372036854775807,0,52649898804237,52649898834810,52649898837675,52649899376841,52649902517570,52649902790695,52649903661320,52649906252206,52649906706841,149000,180000, 0,52649915127446,52649915127446,9223372036854775807,0,52649915427518,52649915452102,52649915454185,52649916730487,52649918999810,52649919207883,52649919950227,52649922103925,52649922502102,232000,163000, 0,52649931838312,52649931838312,9223372036854775807,0,52649932090852,52649932108508,52649932110279,52649932414654,52649934322987,52649934504445,52649935012831,52649936734237,52649937059185,111000,138000, 0,52649948548982,52649948548982,9223372036854775807,0,52649949961789,52649949987206,52649949990174,52649951342518,52649954262622,52649954549081,52649955380070,52649961340904,52649961895487,171000,228000, 0,52649965257509,52649965257509,9223372036854775807,0,52649966073612,52649966105956,52649966108820,52649966579862,52649968551477,52649968823560,52649969662414,52649973552102,52649974074654,958000,200000, 0,52649998612728,52649998612728,9223372036854775807,0,52649998977622,52649999557206,52649999559549,52650017059133,52650020417883,52650020646320,52650021568768,52650025146633,52650025758195,481000,200000, 0,52650015326027,52650015326027,9223372036854775807,0,52650021651945,52650021653299,52650022256320,52650022672935,52650023145487,52650025904237,52650026439497,52650028692154,52650029208664,104000,212000, 0,52650032044406,52650032044406,9223372036854775807,0,52650032325539,52650032351633,52650032628664,52650032995174,52650033231164,52650033404549,52650033809602,52650036246529,52650036571424,549000,144000, 0,52650048712678,52650048712678,9223372036854775807,0,52650049223247,52650049248352,52650049509706,52650050059966,52650050409289,52650050707310,52650051197727,52650052948872,52650053928299,303000,628000, 0,52650065451017,52650065451017,9223372036854775807,0,52650065783091,52650065811372,52650065992570,52650067972883,52650068491477,52650068892466,52650069592570,52650070378560,52650072193039,135000,1567000, 0,52650082148943,52650082148943,9223372036854775807,0,52650082448872,52650082474810,52650082711737,52650084045956,52650084379341,52650084573508,52650085195070,52650085874081,52650086263404,119000,172000, 0,52650098856086,52650098856086,9223372036854775807,0,52650099223768,52650099243977,52650099439602,52650099924549,52650101026008,52650101260956,52650101923872,52650102694966,52650103103768,157000,166000, 0,52650115562739,52650115562739,9223372036854775807,0,52650115944706,52650115969341,52650116332310,52650116949081,52650117979133,52650118371424,52650118993977,52650120497466,52650121246477,340000,302000, 0,52650132269055,52650132269055,9223372036854775807,0,52650132743247,52650132778091,52650133080070,52650133797727,52650135069497,52650135579133,52650136537727,52650138084862,52650138892154,492000,336000, 0,52650148975500,52650148975500,9223372036854775807,0,52650149621216,52650149650226,52650149885174,52650150524654,52650151176372,52650151718091,52650152564914,52650153554601,52650154188664,193000,308000, 0,52650165681977,52650165681977,9223372036854775807,0,52650166140122,52650166172154,52650166478143,52650167273612,52650168604758,52650169180226,52650169986893,52650171338299,52650172238247,370000,447000, 0,52650182388296,52650182388296,9223372036854775807,0,52650182942779,52650182972362,52650183367101,52650183978456,52650185713039,52650186415591,52650187213195,52650189186529,52650189928716,924000,340000, 0,52650199094781,52650199094781,9223372036854775807,0,52650199689549,52650199830956,52650200480226,52650200939445,52650202084914,52650202350226,52650203078404,52650203995383,52650204613351,215000,218000, 0,52650215800540,52650215800540,9223372036854775807,0,52650216403976,52650216429393,52650217027206,52650217563716,52650218779810,52650219244497,52650219859706,52650221868820,52650223560747,676000,1300000, 0,52650232507063,52650232507063,9223372036854775807,0,52650232925226,52650232957935,52650233205226,52650233922570,52650234452726,52650234798508,52650235375174,52650236484289,52650237067518,223000,261000, 0,52650249213762,52650249213762,9223372036854775807,0,52650249567049,52650249631841,52650249828247,52650250196841,52650250466216,52650252292518,52650253297466,52650254284654,52650254833195,208000,256000, ---PROFILEDATA---View hierarchy:com.android.settings/com.android.settings.Settings/android.view.ViewRootImpl@f131882255 views, 270.94 kB of display listscom.android.settings/com.android.settings.SubSettings/android.view.ViewRootImpl@3253b93274 views, 291.13 kB of display listsTotal ViewRootImpl: 2 Total Views: 529 Total DisplayList: 562.06 kB例如下面則是有兩個窗口
Window: com.android.settings/com.android.settings.SubSettings(窗口一) Window: com.android.settings/com.android.settings.Settings(窗口二)我們需要根據(jù)上面獲取的當(dāng)前活動窗口(包名不能省略,如果包名省略了,需要轉(zhuǎn)換為全名),去篩選出當(dāng)前正在活動窗口的fps信息,也就是PROFILEDATA的中間數(shù)據(jù)
原理:根據(jù)返回的信息中含有window去定位到當(dāng)前窗口,第一個—PROFILEDATA— 中的數(shù)據(jù)就是當(dāng)前窗口的詳細信息
詳細方法看_get_fps_data
4:去除重復(fù)幀
記錄當(dāng)前窗口的最后一次時間(第一次取0,可能會存在一些誤差,所以測試之前我們需要清除數(shù)據(jù)),遍歷PROFILEDATA中IntendedVsync(每幀的起始時間)的時間大于最后一次記錄的時間,這時候就不是重復(fù)幀,才進行采集數(shù)據(jù)
# 我們需要在次數(shù)去除重復(fù)幀,通過每幀的起始時間去判斷是否是重復(fù)的for timestamp in each_frame_timestamps:if timestamp[0] > self.last_timestamp:timestamps.append((timestamp[1] - timestamp[0]) / 1000000)self.last_timestamp = timestamp[0]return timestamps, int(phone_time)5:計算FPS,jank,卡頓
每幀耗時時間 time = (FRAME_COMPLETED - INTENDED_VSYNC)/1000000 (單位ms)
最終去除重復(fù)幀后,集合中有多少行就是有多少幀繪制,大于16.67ms的則是jank ,大于166.7ms則是卡頓
總共收集到了m幀(理想情況下m=128),但是這m幀里面有些幀渲染超過了16.67毫秒,算一次jank,一旦jank,
需要用掉額外的垂直同步脈沖。其他的就算沒有超過16.67,也按一個脈沖時間來算(理想情況下,一個脈沖就可以渲染完一幀)
所以FPS的算法可以變?yōu)?#xff1a;
m / (m + 額外的垂直同步脈沖) * 60
6:python腳本實現(xiàn)
FpsInfo 是結(jié)構(gòu)體
FpsListenserImpl 是定義的接口實現(xiàn),用來調(diào)用顯示和打印的,調(diào)試時可刪除
功能就是每隔2s獲取當(dāng)前活動窗口的fps,并統(tǒng)計丟幀數(shù)和丟幀的耗時時間
執(zhí)行結(jié)果如下
C:\Users\ysfa\AppData\Local\Programs\Python\Python37\python.exe D:/PycharmProjects/untitled/fps.py FPS monitor has start! 已經(jīng)清除FPS數(shù)據(jù),請3秒后開始滑動界面當(dāng)前進程是:com.android.settings 當(dāng)前窗口是:com.android.settings/com.android.settings.SubSettings 當(dāng)前手機窗口刷新時間:2020-07-30 19:59:57 當(dāng)前窗口fps是:59.0625 當(dāng)前2s獲取總幀數(shù):63 當(dāng)前窗口丟幀數(shù)>16.67ms)是:1 [24.982251] 當(dāng)前窗口卡頓數(shù)(>166.7ms)是:0當(dāng)前進程是:com.android.settings 當(dāng)前窗口是:com.android.settings/com.android.settings.SubSettings 當(dāng)前手機窗口刷新時間:2020-07-30 19:59:59 當(dāng)前窗口fps是:60.0 當(dāng)前2s獲取總幀數(shù):41 當(dāng)前窗口丟幀數(shù)>16.67ms)是:0 [] 當(dāng)前窗口卡頓數(shù)(>166.7ms)是:0 import os import queue import threading import time from math import floorfrom FpsInfo import FpsInfo from FpsListenserImpl import FpsListenserImplclass FPSMonitor(object):def __init__(self, sn):self.frequency = 2 # 取樣頻率self.device = snself.fpscollector = FpsCollector(self.device, self.frequency)def set_listener(self, listener):self.fpscollector.set_listener(listener)def start(self, start_time):self.start_time = start_timeif self.fpscollector.package_name is None:print("手機沒亮屏,或者usb未連接")returnprint('FPS monitor has start!')self.fpscollector.start(start_time)def stop(self):'''結(jié)束FPSMonitor日志監(jiān)控器'''if self.fpscollector.package_name is None:print("手機沒亮屏,或者usb未連接")returnself.fpscollector.stop()print('FPS monitor has stop!')def save(self):passdef parse(self, file_path):'''解析:param str file_path: 要解析數(shù)據(jù)文件的路徑'''passdef get_fps_collector(self):'''獲得fps收集器,收集器里保存著time fps jank的列表:return: fps收集器:rtype: SurfaceStatsCollector'''return self.fpscollectorclass FpsCollector(object):'''Collects surface stats for a SurfaceView from the output of SurfaceFlinger'''def __init__(self, device, frequency):self.device = deviceself.frequency = frequencyself.jank_threshold = 16.7 # 內(nèi)部的時間戳是毫秒秒為單位self.last_timestamp = 0 # 上次最后最早一幀的時間self.data_queue = queue.Queue()self.stop_event = threading.Event()self.get_focus_window()self.listener = None# queue 上報線程用def start(self, start_time):'''打開SurfaceStatsCollector'''self._clear_fps_data()self.collector_thread = threading.Thread(target=self._collector_thread)self.collector_thread.start()self.calculator_thread = threading.Thread(target=self._calculator_thread, args=(start_time,))self.calculator_thread.start()def stop(self):'''結(jié)束SurfaceStatsCollector'''if self.collector_thread:self.stop_event.set()self.collector_thread.join()self.collector_thread = Nonedef set_listener(self, listener):self.listener = listenerdef get_focus_window(self):'''通過adb shell dumpsys activity | findstr "mResume"'''cmd = "adb -s " + self.device + " shell dumpsys activity | findstr mResume"# print(cmd)windowInfo = os.popen(cmd)windowInfo = str(windowInfo.readline())# print(windowInfo)if windowInfo is "":self.package_name = Noneself.focus_window = NonereturnpackageNameinfo = windowInfo.split(" ")[7]packageName = packageNameinfo.split("/")[0]if "/." in packageNameinfo:windowName = packageName + "/" + packageName + "." + packageNameinfo.split("/.")[1]else:windowName = packageNameinfoself.package_name = packageNameself.focus_window = windowNamedef _calculate_results(self, timestamps):"""Returns a list of SurfaceStatsCollector.Result.FPS 丟幀率 卡頓次數(shù) 總幀數(shù)"""frame_count = len(timestamps)jank_list, caton, vsyncOverTimes = self._calculate_janky(timestamps)fps = frame_count / (frame_count + vsyncOverTimes) * 60return fps, jank_list, catondef _calculate_janky(self, timestamps):# 統(tǒng)計丟幀卡頓 ,和需要垂直同步次數(shù)jank_list = []caton = 0vsyncOverTimes = 0for timestamp in timestamps:if timestamp > self.jank_threshold:# 超過16.67msjank_list.append(timestamp)if timestamp % self.jank_threshold == 0:vsyncOverTimes += ((timestamp / self.jank_threshold) - 1)else:vsyncOverTimes += floor(timestamp / self.jank_threshold)if timestamp > self.jank_threshold * 10:# 超過166.7ms 明顯卡的幀,用戶會覺得卡頓caton += 1return jank_list, caton, vsyncOverTimesdef _calculator_thread(self, start_time):'''處理surfaceflinger數(shù)據(jù)'''while True:try:data = self.data_queue.get()# print(data)if isinstance(data, str) and data == 'Stop':break# before = time.time()refresh_time = int(data[0])# print(refresh_time)timestamps = data[1]fps, jank_list, caton = self._calculate_results(timestamps)fps_info = FpsInfo(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(refresh_time)), len(timestamps),fps,self.package_name, self.focus_window, jank_list, len(jank_list), caton)self.listener.report_fps_info(fps_info)# print('\n')# print("當(dāng)前設(shè)備是:" + self.device)# print("當(dāng)前進程是:" + self.package_name)# print("當(dāng)前窗口是:" + self.focus_window)# print("當(dāng)前手機窗口刷新時間:" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(refresh_time)))# print("當(dāng)前窗口fps是:" + str(fps))# print("當(dāng)前2s獲取總幀數(shù):" + str(len(timestamps)))# print("當(dāng)前窗口丟幀數(shù)>16.67ms)是:" + str(jank_list))# print("當(dāng)前窗口卡頓數(shù)(>166.7ms)是:" + str(caton))# print('\n')except Exception as e:print(e)print("計算fps數(shù)據(jù)異常")self.data_queue.put('Stop')if self.calculator_thread:self.stop_event.set()self.calculator_thread = Nonereturndef _collector_thread(self):'''收集FPS數(shù)據(jù)shell dumpsys gfxinfo 《 window》 framestats3'''last_refresh_time = 0while not self.stop_event.is_set():# 此處進行獲取,并將數(shù)據(jù)存放在data_quue里try:before = time.time()# print("開始獲取fps信息:" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(before)))self.get_focus_window()new_timestamps, now_refresh_time = self._get_fps_data()# 此處需要檢查是否獲取數(shù)據(jù)成功if now_refresh_time is None or new_timestamps is None:# 這里可能就是清楚數(shù)據(jù)后,沒有做界面操作,所以會拿不到數(shù)據(jù),跳過,我們獲取下一次的continue# print(new_timestamps)# 大于則證明有幀信息刷新,無則不需要更新信息if self.last_timestamp > last_refresh_time:last_refresh_time = self.last_timestamp# print(last_refresh_time)self.data_queue.put((now_refresh_time, new_timestamps))time_consume = time.time() - beforedelta_inter = self.frequency - time_consumeif delta_inter > 0:time.sleep(delta_inter)# print('\n')# print("結(jié)束獲取fps信息:" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))except Exception as e:print("獲取fps數(shù)據(jù)異常")print(e)self.data_queue.put('Stop')if self.collector_thread:self.stop_event.set()self.collector_thread = Nonereturnif self.stop_event.is_set():self.data_queue.put('Stop')def _clear_fps_data(self):os.popen("adb -s " + self.device + " shell dumpsys gfxinfo " + self.package_name + " reset")# 清除數(shù)據(jù)后,直接獲取fps會有異常,我們最好等待一段時間print("已經(jīng)清除FPS數(shù)據(jù),請3秒后開始滑動界面")time.sleep(5)def _get_fps_data(self):"""isHaveFoundWindow 是否是當(dāng)前活動窗口total_frames 總幀數(shù)timestamps 每幀耗時信息:rtype::return:"""results = os.popen("adb -s " + self.device + " shell dumpsys gfxinfo " + self.package_name + " framestats")phone_time = os.popen("adb -s " + self.device + " shell date +%s")phone_time = phone_time.readlines()[0]# print(phone_time)timestamps = []each_frame_timestamps = []isHaveFoundWindow = FalsePROFILEDATA_line = 0# 行數(shù)代表當(dāng)前窗口總幀數(shù),列數(shù)是每幀耗時詳細信息# !!!注意一個進程可能存在多個窗口,所以我們只獲取當(dāng)前顯示窗口的信息for line in results.readlines():# print("test" + line)if "Window" in line and self.focus_window in line:isHaveFoundWindow = True# print("focus Window is :" + line)continueif isHaveFoundWindow and "---PROFILEDATA---" in line:PROFILEDATA_line += 1# print(PROFILEDATA_line)continueif isHaveFoundWindow and "Flags,IntendedVsync," in line:continueif isHaveFoundWindow and PROFILEDATA_line is 1:# 此處代表的是當(dāng)前活動窗口# 我們?nèi)ROFILEDATA中間的數(shù)據(jù) 最多128幀,還可能包含之前重復(fù)的幀,所以我們間隔1.5s就取一次數(shù)據(jù)fields = []fields = line.split(",")each_frame_timestamp = [float(fields[1]), float(fields[13])]each_frame_timestamps.append(each_frame_timestamp)continueif PROFILEDATA_line >= 2:break# 我們需要在次數(shù)去除重復(fù)幀,通過每幀的起始時間去判斷是否是重復(fù)的for timestamp in each_frame_timestamps:if timestamp[0] > self.last_timestamp:timestamps.append((timestamp[1] - timestamp[0]) / 1000000)self.last_timestamp = timestamp[0]return timestamps, int(phone_time)def run_adb(cmd):return os.popen(cmd)if __name__ == '__main__':sn = "9365fc0e"monitor = FPSMonitor(sn)lisenter = FpsListenserImpl()monitor.set_listener(lisenter)monitor.start(time.time())time.sleep(60)monitor.stop() #!/usr/bin/env python # coding:utf-8 """ Name : FpsInfo.py Author : Contect : Time : 2020/7/21 14:26 Desc: """class FpsInfo(object):def __init__(self, time, total_frames, fps, pkg_name, window_name, jankys_ary, jankys_more_than_16,jankys_more_than_166):# 采樣數(shù)據(jù)時的時間戳self.time = time# 2s內(nèi)取到總幀數(shù)self.total_frames = total_frames# fpsself.fps = fps# 測試應(yīng)用包名self.pkg_name = pkg_name# 窗口名self.window_name = window_name# 掉幀具體時間集合self.jankys_ary = jankys_ary# 掉幀數(shù)目,大于16.67msself.jankys_more_than_16 = jankys_more_than_16# 卡頓數(shù)目,大于166.7msself.jankys_more_than_166 = jankys_more_than_166 #!/usr/bin/env python # coding:utf-8 """ Name : FpsListener.py Author : Contect : Time : 2020/7/23 16:07 Desc: """ from abc import ABCMeta, abstractmethodclass IFpsListener(object):@abstractmethoddef report_fps_info(self, fps_info):pass from FpsListener import IFpsListenerclass FpsListenserImpl(IFpsListener):def __init__(self):passdef report_fps_info(self, fps_info):print('\n')# print("當(dāng)前設(shè)備是:" + fps_info.)print("當(dāng)前進程是:" + str(fps_info.pkg_name))print("當(dāng)前窗口是:" + str(fps_info.window_name))print("當(dāng)前手機窗口刷新時間:" + str(fps_info.time))print("當(dāng)前窗口fps是:" + str(fps_info.fps))print("當(dāng)前2s獲取總幀數(shù):" + str(fps_info.total_frames))print("當(dāng)前窗口丟幀數(shù)>16.67ms)是:" + str(fps_info.jankys_more_than_16))print(fps_info.jankys_ary)print("當(dāng)前窗口卡頓數(shù)(>166.7ms)是:" + str(fps_info.jankys_more_than_166))print('\n')總結(jié)
以上是生活随笔為你收集整理的python实时获取Android FPS的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息队列的pull与push模式理解
- 下一篇: jostudio.wechatmenu.