工具簡單介紹
前陣子公司發布一款新的安卓應用,第一個版本由于時間問題僅僅測試了主要功能,性能一點沒測,導致在發布應用市場遇到了很大麻煩。在查看百度給的監測報告時,發現報告主要包括如下幾個方面:
- 安裝用時
- 啟動耗時
- CPU占用
- 內存占用
- 流量耗用
- 電量耗用
遂嘗試自己嘗試動手做一個性能監控工具,去監測這些性能,第一個版本已經完成,主界面如下:
我自己給這個工具取名為AATT(android auto test tool),第一個版本目前做到了監控內存、CPU、流量三個維度的信息。
時間問題還有如下幾個指標沒有涉及:
- 對于啟動耗時,啟動耗時測試需要分的場景比較多,安裝后第一個啟動、冷啟動、熱啟動,線上線下采用的統計方法都不同,線下一般直接通過
adb shell am start -W packagename/activity
命令或者
adb locat | findstr Displayed
來采集,其中start主要用于首次啟動,由于是測試,所以應用肯定頻繁的開啟,推薦用adb logcat命令來采集。
線上統計的話,一般通過埋點打log,開始時間點為:
冷啟動---在 Application.attachBaseContext() 文本顯示的時候
熱啟動---在 Activity.onRestart() 即重啟 中記錄起始時間點
結束時間點:
在 Activity.onWindowFocusChanged 記錄結束時間點,即窗體事件結束后
由于我們工具主要是測試一段時間內的性能指標,不會頻繁的去啟動應用,所以感覺加上這個啟動時間很雞肋,不過后續版本還是會考慮加上
- 對于電量,由于測試過程中手機一直連著電腦,一直處于充電狀態,所以
adb shell dumpsys battery
統計出來的結果就會誤差很大。最準確的還是用硬件,電量儀等來測試,不過條件限制,暫時無法做到。
后面版本也會加上這個指標的統計
AATT工具主要使用方法:
- 連接手機----點擊檢查設備,連接成功的話會顯示設備號,沒有則顯示No device found
- 選擇更新時間----選擇后每隔這段時間實時刷新統計結果
- 打開待測設備----獲取packagename和activity
- 點開開始按鈕,測試開始,結束則結束測試
關于工具暫時就介紹這么多,后面會重開一篇文章,詳細介紹工具的詳細代碼
內存
首先數據源,這個毋庸置疑,內存的數據源是 dumpsys meminfo,命令:
adb shell dumpsys meminfo packagename
出來的結果如下所示:
內存主要分兩部分:Native和Dalvik,其中davilk就是我們說的java堆,創建的對象就是在堆中分配的,對于內存的限制是native+dalvik不能查過最大限制,否則會發生內存溢出OOM(Out Of Memory)
進程可用的最大內存,查看方法:
adb shell getprop dalvik.vm.heapgrowthlimit
數據采集方法:
#獲取mem占用情況
mem_list = []
def mem():
cmd = 'adb -s '+ get_devices() + ' shell dumpsys meminfo ' + getpackagename()
print (cmd)
men_s = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
for info in men_s:
if len(info.split())>0 and info.split()[0].decode() == "TOTAL":
mem_list.append(int(info.split()[1].decode()))
print(str(info.split()[1].decode()))
print(mem_list)
# men_list = str(info.split()[1].decode())
return mem_list
CPU
數據源,cpu的采集主要來自top命令:
adb shell top -n 1 | findstr packagename
adb shell top -h
可以查看top幫助文檔:
- -m 最多顯示多少個進程
- -n 刷新次數
- -d 刷新時間間隔(默認5s)
- -s 按哪一列排序
- -t 顯示線程而不是進程
- -h 顯示幫助文檔
其中第一組數據的含義:
- User 處于用戶態的運行時間,不包含優先值為負進程
- Nice 優先值為負的進程所占用的CPU時間
- Sys 處于核心態的運行時間
- Idle 除IO等待時間以外的其它等待時間
- IOW IO等待時間
- IRQ 硬中斷時間
- SIRQ 軟中斷時間
第二組數據的含義:
- PID 進程id
- PR 優先級
- CPU% 當前瞬時CPU占用率
- S 進程狀態:D=不可中斷的睡眠狀態, R=運行, S=睡眠, T=跟蹤/停止, Z=僵尸進程
- (#THR) 程序當前所用的線程數
- VSS Virtual Set Size 虛擬耗用內存(包含共享庫占用的內存)
- RSS Resident Set Size 實際使用物理內存(包含共享庫占用的內存)
- PCY 調度策略優先級,SP_BACKGROUND/SP_FOREGROUND
- UID 進程所有者的用戶id
- Name 進程的名稱
備注:上面這些數據含義主要參考,CSDN一篇文章,感謝原作者!!!
數據采集方法:
#獲取cpu
cpu_list=[]
def cpu():
cmd = 'adb -s '+get_devices() + ' shell top -n 1| findstr ' + getpackagename()
# print (cmd)
top_info = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
print (top_info)
if len(top_info)>=1:
cpu_list.append(int(top_info[0].split()[2][0:-1]))
print (cpu_list)
return cpu_list
流量
數據采集,同樣也是通過adb 命令來獲取,首先需要獲得被測應用的 uid 信息,然后通過
adb shell cat /proc/uid_stat/uid/tcp_rcv
adb shell cat /proc/uid_stat/uid/tcp_snd
來獲取應用接受和發送的流量,點擊操作后,再次運行命令,將得到的兩個結果相減,便可以獲得應用的整體流量消耗。
但這種命令有個弊端,值通過tcp的流量,所以可能導致流量統計不夠全面,遂換另一個命令:
adb shell cat /proc/net/xt_qtaguid/stats | findstr uid
首先獲取pid:
adb shell ps | findstr packagename
根據pid獲取uid:
adb shell cat /proc/<pid>/status
拿到uid后:
adb shell cat /proc/net/xt_qtaguid/stats | findstr uid
其中第6和8列為 rx_bytes(接收數據)和tx_bytes(傳輸數據)包含tcp,udp等所有網絡流量傳輸的統計。
一個uid可能對應多個 進程,所以這有兩行流量是累加的就求和就行。
數據采集方法
#獲取流量
receive = []
sendflow = []
all = []
def flow():
cmd = 'adb -s '+ get_devices() +' shell cat /proc/net/xt_qtaguid/stats | findstr '+ uid()
print (cmd)
flow_info = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
down = 0
up = 0
if len(flow_info)>= 1:
for flow in flow_info:
down =down + int(flow.split()[5])
up = up+ int(flow.split()[7])
receive.append(down)
sendflow.append(up)
print (receive,sendflow)
return (receive,sendflow)
總結
再次安利一波,我的工具,主界面如下:
各性能指標的采集方法,主要就是上面的方法,后續將進一步工具。
我自己想到的后續版本,可優化點:
- 1.增加設備狀態監控,設備斷開,自動結束測試
- 2.增加圖表顯示
- 3.增加清屏功能
關于工具的時間,下一篇文章再介紹,如果好的建議,歡迎指教。