性能收集分析相關工具總覽
? 收集、分析、展示移動應用性能數據的工具很多,大致可以分為如下幾類。例如可收集多項性能指標的移動性能工具,perfdog,Solopi,其中Solopi開源,pefdog商業工具。可進行Crash分析的工具,例如商業的Firebase Crashlytics和開源的Sentry工具。如果需要對網絡相關數據進行分析,可以使用Charles或者Wireshark。除此之外,還有綜合性的性能管理工具,例如Dynatrace等。總體來說,商業工具能力,準確性,用戶體驗肯定強于開源工具,作為個人學習研究,更多只有從開源工具出發。所以,此篇博客在編寫中,也會以開源工具進行舉例。
移動端性能測試工具:
PerfDog:用于監控應用性能、CPU、內存、電量消耗等數據的工具,支持移動應用的性能測試和實時監控。
Solopi:專注于移動應用性能的測試和監控,包括幀率、CPU、內存等指標的實時監測。
Crash分析工具:
Firebase Crashlytics:Google提供的強大的崩潰報告和分析工具,可實時監控應用的崩潰情況。
Sentry:開源的錯誤追蹤工具,支持多種平臺,包括移動應用的錯誤報告和性能監控。
網絡性能測試工具:
Charles Proxy:網絡調試代理工具,可以捕獲和分析移動應用的網絡請求和響應數據。
Wireshark:開源的網絡分析工具,支持捕獲和分析移動應用的網絡數據包。
APM工具(應用性能管理):
Dynatrace:云原生的全棧性能監控解決方案,支持移動應用性能監控和用戶體驗分析。
收集哪些性能指標以及如何收集
? 進行性能分析前,首先要明白每個性能指標含義,以solopi收集的性能指標為例,我們來展開看看移動應用性能常見指標,以及可以通過哪些方式收集這些指標。
幀率
? 幀率的計算公式是:幀率=繪制的幀數/時間段,大多數應用程序和游戲開發者的目標幀率是60FPS(幀/每秒),為什么目標幀率是60FPS呢?因為大多數現代智能手機和平板電腦的屏幕刷新率為60Hz,所以,只要幀率達到60FPS,即每秒繪制的幀數是60,那么用戶視覺效果就比較流暢,不會有卡頓的感覺。最低不能低于30FPS,這是因為顯示器在等待新的幀時,重復顯示上一幀的圖像,導致畫面不流暢。高的可以達到90FPS(例如,對于高刷新頻率的設備而言)。
如何收集幀率信息
? 收集幀率的方式有兩種,一種是利用Choreographer類統計幀率,這種需要在應用內部寫代碼實現,只能收集該應用的幀率信息。另外一種方式是使用gfxinfo工具。以Solopi為例,也是通過gfxinfo工具信息計算1秒內超時幀時間,從而反推出實際幀率,所以在接近靜止的情況下, 部分幀率可能顯示有誤。推薦在滑動或頁面切換等動態場景下進行幀率測試。gfxinfo的方式,可以收集所有應用的幀率信息,非常適合做性能數據收集工具,所以,這里,也重點介紹如何通過gfxinfo收集幀率信息。
? 收集幀率信息主要有兩個步驟,步驟一:通過adb命令獲取gfxinfo信息,步驟二:對信息進行解析,計算得出幀率信息。gfxinfo信息內容大致如下所示:
Stats since: 統計開始時間,單位為納秒。
Total frames rendered: 總渲染幀數。
Janky frames: 卡頓幀數,即超過16ms(每秒60幀的刷新間隔)的幀數。
Janky frames percentage: 卡頓幀占比,即卡頓幀數與總幀數的比例。
90th percentile: 90分位數,表示90%的幀的渲染時間低于該值(以毫秒為單位)。
95th percentile: 95分位數,表示95%的幀的渲染時間低于該值(以毫秒為單位)。
99th percentile: 99分位數,表示99%的幀的渲染時間低于該值(以毫秒為單位)。
Number Missed Vsync: 未同步垂直同步次數,即由于未能及時渲染而導致的丟幀次數。
Number High input latency: 高輸入延遲次數,表示輸入事件處理時間過長而導致的延遲次數。
Number Slow UI thread: UI線程響應緩慢次數,即UI線程處理時間過長的次數。
以Solopi為例子,就是通過gfxinfo信息中的超時幀時間,來反推幀率的,具體項目的代碼可以查看solopi source code。
卡頓率/卡頓次數
卡頓次數:在測試周期內,檢測到幀率低于閾值的時間段數。每當幀率低于閾值并持續一段時間,就計為一次卡頓。這里的閥值,可以進行自定義設置,例如低于目標幀率60FPS,就可以記為一次卡頓。即幀渲染時間大于16ms,就計算為卡頓。
卡頓率:卡頓時間占總測試時間的百分比。假設在一次測試中,應用運行了120秒,期間總共有4次幀率低于16 FPS的情況,總計卡頓時間為8秒,那么:卡頓次數:4次。卡頓率:8/120*100%=6.7%。在上面的gfxinfo中,也有卡頓率的數據信息。
cpu/內存
? 以solopi為例,cpu是包含應用頂層Activity所在進程的CPU占用百分比與全局CPU占用百分比,對于單進程應用,該數據表示該應用的CPU占用情況;對于多進程進程應用,該數據表示頂層UI進程的CPU占用情況,當發生進程切換時,Soloπ能夠自動切換到新的進程數據。
import subprocessdef get_memory_info(pid):try:# Run adb shell command to read /proc/<pid>/statmcommand = f"adb shell cat /proc/{pid}/statm"result = subprocess.check_output(command, shell=True)statm_data = result.decode('utf-8').strip().split()# Parse statm datasize, resident, shared, text, lib, data, dt = map(int, statm_data)memory_info = {'size': size, # total program size (pages)'resident': resident, # resident set size (pages)'shared': shared, # shared pages (pages)'text': text, # text (code) size (pages)'lib': lib, # library (unused since Linux 2.6; always 0)'data': data, # data + stack (pages)'dt': dt # dirty pages (unused since Linux 2.6; always 0)}return memory_infoexcept subprocess.CalledProcessError as e:print(f"Error executing command: {e}")return Noneexcept Exception as e:print(f"Error: {e}")return None# Replace with your application's PID
pid = '12345'
memory_info = get_memory_info(pid)
if memory_info:print(f"Memory info for PID {pid}:")print(f"Size: {memory_info['size']} pages")print(f"Resident set size (RSS): {memory_info['resident']} pages")print(f"Shared pages: {memory_info['shared']} pages")print(f"Text (code) size: {memory_info['text']} pages")print(f"Data + stack size: {memory_info['data']} pages")
網絡
? 以solopi為例,網絡包含應用上下行速率與累計流量以及全局上下行速率與累計流量。屬于應用維度數據,具體數據如下圖所示:
如何獲取網絡數據?
? 獲取網絡數據和獲取cpu/內存數據一樣,可以直接讀取/proc/pid/net/dev文件獲取網絡數據,或者通過adb命令獲取(命令:adb shell cat /proc/pid/net/dev)。下圖是solopi部分源碼,可以看到這里統計了wlan0的網絡數據情況,具體邏輯可以查看solopi source code下面的NetworkTools.java代碼。當然,關于網絡流量統計,網上也提交了bug,因為這里grep wlan0,只統計了網絡wifi的流量,沒有統計到移動流量。bug詳細信息見這里。
響應時間
? 以solopi為例,包含應用點擊的響應耗時與刷新耗時數據。屬于應用維度數據。從用戶點擊開始,到系統第一次發出界面更新時間為響應耗時,到系統停止界面刷新的時間為刷新耗時。統計響應時間的邏輯是錄屏分幀,solopi官網介紹是實現了自動識別開始幀和結束幀來統計響應時間,實際使用solopi會發現,統計的頁面響應時間并不正確,例如用戶點擊開始,到點擊應用的頁面,這中間本身有人的手速操作時間在內,這部分被統計到響應時間里面了。所以,如果要計算準備的頁面響應時間,還是只有錄屏,人工識別頁面的開始、結束幀,會更準確。具體錄屏分幀的步驟如下所示:
? 以上就是對于移動應用中常見性能指標含義理解,以及如何收集詳細說明。關于crash等,會在后續博客中再詳細介紹。