Android專項測試監控資源


版本號 V 1.1.0

Android性能測試分為兩類:
1、一類為rom版本(系統)的性能測試
2、一類為應用app的性能測試(本次主要關注點為app的性能測試)

Android的app性能測試包括的測試項比如:

內存、adb shell dumpsys meminfo com.xxxxx.xxxx | findstr TOTAL

CPU、adb shell dumpsys cpuinfo | findstr com.xxxxx.xxxx

流量、adb shell ps | grep com.xxxxx.xxxx、獲取進程使用的流量:adb shell cat /proc/"+pid+"/net/dev

功耗、adb shell dumpsys battery

GPU、adb shell dumpsys gfxinfo com.xxxxx.xxxx

 

1、內存

本次測試以xxxxxxapp為測試對象。配合monkey測試隨機事件1000次、忽略超時、忽略崩潰

命令: monkey -p com.xxxxx.xxxx --throttle 500 --ignore-timeouts --ignore-crashes   --monitor-native-crashes -v -v -v 1000

shell命令:adb shell dumpsys meminfo com.xxxxx.xxxx | findstr TOTAL

思路:在運行monkey的過程中 每隔一段時間去取內存的數據

代碼demo

# coding:utf-8

import os
import time
import matplotlib
from matplotlib import pyplot as plt

data2 = []
def getmeminfo():
    # cmd = "adb shell monkey -p com.xxxxx.xxxx --throttle 500 --ignore-timeouts --ignore-crashes --monitor-native-crashes -v -v -v 1000"
 # os.popen(cmd)
 print("*"*20)
    for i in range(10):
        cmd = (
            "adb shell dumpsys meminfo com.xxxxx.xxxx | findstr TOTAL >>E:\mem.txt"
 )
        os.popen(cmd)
        time.sleep(2)
    with open("E:\mem.txt", "r") as f:
        lines = f.readlines()
    for i in range(0, len(lines), 2):
        data2.append(int(lines[i].split()[1]))


def drawlabe(data1, data2):
    #mainColor = (42 / 256, 87 / 256, 141 / 256, 1)
 plt.xlabel("次數")
    plt.ylabel("內存kb")
    plt.plot(data1, data2, marker="*")
    plt.title("內存波動折線圖")
    plt.show()


if __name__ == "__main__":
    number = getmeminfo()
    print(data2)
    data1 = [1,2,3,4,5,6,7,8,9,10]
    drawlabe(data1, data2)

 

拓展:

  1. 內存測試中的測試子項:
    1)空閑狀態下的應用內存消耗情況
    2)中等規格狀態下的應用內存消耗情況
    3)滿規格狀態下的應用內存消耗情況
    4)應用內存峰值情況
    5)應用內存泄露情況
    6)應用是否常駐內存
    7)壓力測試后的內存使用情況

  2. 內存問題現象:
    1)內存抖動
    2)大內存對象被分配
    3)內存不斷增長
    4)頻繁GC

  3. 內存數據獲取:
    1、各種linux命令(top、free、meminfo…)
    2、通過dumpsys
    adb shell dumpsys meminfo [pakagename | pid]

2、CPU

本次測試以xxxxxxapp為測試對象。配合monkey測試隨機事件1000次、忽略超時、忽略崩潰

命令: monkey -p com.xxxxx.xxxx --throttle 500 --ignore-timeouts --ignore-crashes   --monitor-native-crashes -v -v -v 1000

shell命令:adb shell dumpsys cpuinfo | findstr com.xxxxx.xxxx

demo代碼:

#/usr/bin/python
#encoding:utf-8
import csv
import os
import time
#控制類
class Controller(object):
    def __init__(self, count):
        self.counter = count
        self.alldata = [("timestamp", "cpustatus")]
    #單次測試過程
    def testprocess(self):
        result = os.popen("adb shell dumpsys cpuinfo | findstr com.xxxxx.xxxx")
        for line in result.readlines():
            cpuvalue =  line.split("%")[0]
        currenttime = self.getCurrentTime()
        self.alldata.append((currenttime, cpuvalue))
    #多次執行測試過程
    def run(self):
        while self.counter >0:
            self.testprocess()
            self.counter = self.counter - 1
            time.sleep(3)
    #獲取當前的時間戳
    def getCurrentTime(self):
        currentTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        return currentTime
    #數據的存儲
    def SaveDataToCSV(self):
        csvfile = file('cpustatus.csv', 'wb')
        writer = csv.writer(csvfile)
        writer.writerows(self.alldata)
        csvfile.close()
if __name__ == "__main__":
    controller = Controller(10)
    controller.run()
    controller.SaveDataToCSV()

 

拓展:

  1. CPU測試中的測試子項:
    1)空閑狀態下的應用CPU消耗情況
    2)中等規格狀態下的應用CPU消耗情況
    3)滿規格狀態下的應用CPU消耗情況
    4)應用CPU峰值情況

  2. CPU數據獲取:
    1)adb shell dumpsys cpuinfo | grep packagename
    2)top命令
    adb shell top -m 10 -s cpu #查看占用cpu最高的前10個程序(-t 顯示進程名稱,-s 按指定行排序,-n 在退出前刷新幾次,-d 刷新間隔,-m 顯示最大數量)
    adb shell top | grep PackageName > /address/cpu.txt

3 流量篇

shell命令:adb shell ps | grep com.xxxxx.xxxx

  1. 概念:
    中等負荷:應用正常操作
    高負荷:應用極限操作

  2. demo代碼:

    #/usr/bin/python
    #encoding:utf-8
    import csv
    import os
    import string
    import time
    #控制類
    class Controller(object):
        def __init__(self, count):
            #定義測試的次數
            self.counter = count
            #定義收集數據的數組
            self.alldata = [("timestamp", "traffic")]
        #單次測試過程
        def testprocess(self):
            #執行獲取進程的命令
            result = os.popen("adb shell ps | grep com.xxxxx.xxxx")
            #獲取進程ID
            pid = result.readlines()[0].split(" ")[5]
            #獲取進程ID使用的流量
            traffic = os.popen("adb shell cat /proc/"+pid+"/net/dev")
            for line in traffic:
                if "eth0" in line:
                    #將所有空行換成#
                    line = "#".join(line.split())
                    #按#號拆分,獲取收到和發出的流量
                    receive = line.split("#")[1]
                    transmit = line.split("#")[9]
                elif "eth1" in line:
                    # 將所有空行換成#
                    line =  "#".join(line.split())
                    # 按#號拆分,獲取收到和發出的流量
                    receive2 = line.split("#")[1]
                    transmit2 = line.split("#")[9]
            #計算所有流量的之和
            alltraffic = string .atoi(receive) + string .atoi(transmit) + string .atoi(receive2) + string .atoi(transmit2)
            #按KB計算流量值
            alltraffic = alltraffic/1024
            #獲取當前時間
            currenttime = self.getCurrentTime()
            #將獲取到的數據存到數組中
            self.alldata.append((currenttime, alltraffic))
        #多次測試過程控制
        def run(self):
            while self.counter >0:
                self.testprocess()
                self.counter = self.counter - 1
                #每5秒鍾采集一次數據
                time.sleep(5)
        #獲取當前的時間戳
        def getCurrentTime(self):
            currentTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            return currentTime
        #數據的存儲
        def SaveDataToCSV(self):
            csvfile = file('traffic.csv', 'wb')
            writer = csv.writer(csvfile)
            writer.writerows(self.alldata)
            csvfile.close()
    if __name__ == "__main__":
        controller = Controller(5)
        controller.run()
        controller.SaveDataToCSV()

     

 

拓展:

  1. 流量測試中的測試子項:
    1、應用首次啟動流量值
    2、應用后台連續運行 2 小時的流量值
    3、應用高負荷運行的流量峰值
    4、應用中等負荷運行時的流量均值

  2. 獲取流量數據:
    1、tcpdump+wireshark
    2、/proc/net/目錄下相關文件
    cat /proc/net/dev 獲取系統的流量信息
    3、查詢應用的pid: adb shell ps | grep tataufo #如:31002
    通過PID獲取該應用的流量數據: adb shell cat /proc/31002/net/dev
    (wlan0代表wifi上傳下載量標識, 單位是字節可以/1024換算成KB, 打開手機飛行模式再關掉就可以將wlan0中的值初始化0)
    4、查詢應用的pid: adb shell ps | grep tataufo #如:31002
    通過PID獲取UID:adb shell cat /proc//status
    通過UID獲取:adb shell cat /proc/net/xt_qtaguid/stats | grep 31002
    5、通過adb shell dumpsys package來獲取應用的uid信息,然后在未操作應用之前,通過查看 :
    adb shell cat /proc/uid_stat/uid/tcp_rcv
    adb shell cat /proc/uid_stat/uid/tcp_snd
    獲取到應用的起始的接收及發送的流量,然后我們再操作應用,再次通過上述2條命令可以獲取到應用的結束的接收及發送的流量,通過相減及得到應用的整體流量消耗
    6、Android代碼:Android的TrafficStats類

4 功耗篇

shell命令:adb shell dumpsys battery

demo代碼:

#/usr/bin/python
#encoding:utf-8
import csv
import os
import time
#控制類
class Controller(object):
    def __init__(self, count):
        #定義測試的次數
        self.counter = count
        #定義收集數據的數組
        self.alldata = [("timestamp", "power")]
    #單次測試過程
    def testprocess(self):
        #執行獲取電量的命令
        result = os.popen("adb shell dumpsys battery")
        #獲取電量的level
        for line in result:
            if "level" in line:
                power = line.split(":")[1]
        #獲取當前時間
        currenttime = self.getCurrentTime()
        #將獲取到的數據存到數組中
        self.alldata.append((currenttime, power))
    #多次測試過程控制
    def run(self):
        #設置手機進入非充電狀態
        os.popen("adb shell dumpsys battery set status 1")
        while self.counter >0:
            self.testprocess()
            self.counter = self.counter - 1
            #每5秒鍾采集一次數據
            time.sleep(5)
    #獲取當前的時間戳
    def getCurrentTime(self):
        currentTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        return currentTime
    #數據的存儲
    def SaveDataToCSV(self):
        csvfile = file('meminfo.csv', 'wb')
        writer = csv.writer(csvfile)
        writer.writerows(self.alldata)
        csvfile.close()
if __name__ == "__main__":
    controller = Controller(5)
    controller.run()
    controller.SaveDataToCSV()

 

拓展:

  1. 功耗測試中的測試子項:
    1、手機安裝目標APK前后待機功耗無明顯差異
    2、常見使用場景中能夠正常進入待機,待機電流在正常范圍內
    3、長時間連續使用應用無異常耗電現象

  2. 功耗測試方法:
    方法一:軟件
    1、采用市場上提供的第三方工具,如金山電池管家之類的。
    2、就是自寫工具進行,這里一般會使用3種方法:
    1)基於android提供的PowerManager.WakeLock來進行
    2)比較復雜一點,功耗的計算=CPU消耗+Wake lock消耗+數據傳輸消耗+GPS消耗+Wi-Fi連接消耗
    3)通過 adb shell dumpsys battery來獲取
    3、battery-historian(google開源工具)
    方法二:硬件
    一般使用萬用表或者功耗儀安捷倫進行測試,使用功耗儀測試的時候,需要制作假電池來進行的,有些不能拔插電池的手機還需要焊接才能進行功耗測試

5 GPU(FPS)

shell:adb shell dumpsys gfxinfo com.xxxxx.xxxx

 

待完善-------------------------

拓展:

  1. 概念:
    過度繪制: 界面顯示的activity套接了多層而導致
    幀率:屏幕滑動幀速率
    幀方差: 屏幕滑動平滑度
    **FPS:**Frames Per Second 每秒顯示的幀數 根據人眼的生理結構,幀率高於24時就被認為是連貫的。對於游戲畫面30fps是最低能接受的,60fps逼真感,如果幀率高於屏幕刷新頻率就是浪費。要達到30fps,每幀所占用的時間要小於33毫秒

  2. GPU測試中的測試子項:
    1、界面過度繪制
    2、屏幕滑動幀速率
    3、屏幕滑動平滑度

  3. 過度繪制測試:(人工進行測試)
    打開開發者選項中的顯示GPU過度繪制(Debug GPU overdraw)
    驗收的標准:
    1、不允許出現黑色像素
    2、不允許存在4x過度繪制
    3、不允許存在面積超過屏幕1/4區域的3x過度繪制(淡紅色區域)

  4. 屏幕滑動幀速率測試:
    方法一:
    1.手機端打開開發者選項中的啟用跟蹤后勾選Graphics和View
    2.啟動SDK工具Systrace,勾選被測應用,點擊Systrace,在彈出的對話框中設置持續抓取時間,在trace taps下面勾選gfx及view選項
    3.手工滑動界面可以通過節拍來進行滑動或者掃動,幀率數據會保存到默認路徑下,默認名稱為trace.html
    4.將trace.html文件拷貝到linux系統下通過命令進行轉換,生成trace.csv文件
    grep 'postFramebuffer' trace.html | sed -e 's/.]\W//g' -e 's/:.*$//g' -e 's/.//g' > trace.csv
    5.用excel打開文件計算得到幀率
    方法二:
    硬件的方法,打開高速相機,開啟攝像模式,錄制手工滑動或者掃動被測應用的視頻,再通過人工或者程序數幀的方法對結果進行計算得到幀率

  5. 屏幕滑動平滑度的測試:
    方法如同幀率測試,唯一的差異就是最后的結果計算公式的差異

  6. 捕獲app幀率(android流暢度FPS測試):
    1、打開手機開發者選項,勾選GPU顯示配置文件(系統會記錄保留每個界面最后128幀圖像繪制的相關時間信息)
    2、adb shell dumpsys gfxinfo com.xxx.xxx > zinfo.txt
    3、結果數據分析
    Profile data in ms部分:
    Draw: 創建顯示列表的時間(DisplayList),所有View對象OnDraw方法占用的時間
    Process: Android 2D渲染引擎執行顯示列表所花的時間,View越多時間越長
    Execute:將一幀圖像交給合成器(compsitor)的時間,較小

  7. 其他工具:
    GameBench 測試android app的FPS工具
    Gfxinfo 查看app繪制性能工具

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM