性能测试工具 python+monkey+ 监控 crash,性能统计

lose · 发布于 2017年07月12日 · 最后由 hlfang 回复于 2017年07月25日 · 2187 次阅读
本帖已被设为精华帖!

之前写过monkey方面的测试,这次刚好有项目用到,并且需要监控性能信息,所以重构了一次

monkey 压力测试android

  • python3
  • 统计性能信息cpu,men,fps,battery,flow
  • 支持wifi,gprs统计
  • 统计crash信息
  • 查看源码

monkey.ini 配置文件


cmd=adb shell monkey -p com.jianshu.haruki --throttle 500 --ignore-timeouts --ignore-crashes   --monitor-native-crashes -v -v -v 200 >
package_name=com.jianshu.haruki
activity = com.baiji.jianshu.account.SplashScreenActivity
net = wifi 
  • throttle 每次事件等待500毫秒
  • net 支持gprs和wifi

代码分析

主要监控代码

def get_cpu(pkg_name):
    cmd = "adb  shell dumpsys cpuinfo | findstr " + pkg_name
    print(cmd)
    output = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
    for info in output:
        if info.split()[1].decode().split("/")[1][:-1] == pkg_name:  # 只有包名相等
            # print("cpu=" + info.split()[2].decode())
            cpu.append(float(info.split()[2].decode().split("%")[0]))
            print("----cpu-----")
            print(cpu)
            return cpu


def get_men(pkg_name):
    cmd = "adb shell  dumpsys  meminfo %s" % (pkg_name)
    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()) and info.split()[0].decode() == "TOTAL":
            # print("men="+info.split()[1].decode())
            men.append(int(info.split()[1].decode()))
            print("----men----")
            print(men)
            return men


# 得到fps
'''
@author fenfenzhong
'''


def get_fps(pkg_name):
    _adb = "adb shell dumpsys gfxinfo %s" % pkg_name
    print(_adb)
    results = os.popen(_adb).read().strip()
    frames = [x for x in results.split('\n') if validator(x)]
    frame_count = len(frames)
    jank_count = 0
    vsync_overtime = 0
    render_time = 0
    for frame in frames:
        time_block = re.split(r'\s+', frame.strip())
        if len(time_block) == 3:
            try:
                render_time = float(time_block[0]) + float(time_block[1]) + float(time_block[2])
            except Exception as e:
                render_time = 0


        if render_time > 16.67:
            jank_count += 1
            if render_time % 16.67 == 0:
                vsync_overtime += int(render_time / 16.67) - 1
            else:
                vsync_overtime += int(render_time / 16.67)

    _fps = int(frame_count * 60 / (frame_count + vsync_overtime))
    fps.append(_fps)
    # return (frame_count, jank_count, fps)
    print("-----fps------")
    print(fps)
    return fps


def get_battery():
    _batter = subprocess.Popen("adb shell dumpsys battery", shell=True, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE).stdout.readlines()
    for info in _batter:
        if info.split()[0].decode() == "level:":
            battery.append(int(info.split()[1].decode()))
            print("-----battery------")
            print(battery)
            return int(info.split()[1].decode())


def get_pid(pkg_name):
    pid = subprocess.Popen("adb shell ps | findstr " + pkg_name, shell=True, stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE).stdout.readlines()
    for item in pid:
        if item.split()[8].decode() == pkg_name:
            return item.split()[1].decode()


def get_flow(pkg_name, type):
    pid = get_pid(pkg_name)
    if pid is not None:
        _flow = subprocess.Popen("adb shell cat /proc/" + pid + "/net/dev", shell=True, stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).stdout.readlines()
        for item in _flow:
            if type == "wifi" and item.split()[0].decode() == "wlan0:":  # wifi
                # 0 上传流量,1 下载流量
                flow[0].append(int(item.split()[1].decode()))
                flow[1].append(int(item.split()[9].decode()))
                print("------flow---------")
                print(flow)
                return flow
            if type == "gprs" and item.split()[0].decode() == "rmnet0:":  # gprs
                print("--------------")
                flow[0].append(int(item.split()[1].decode()))
                flow[1].append(int(item.split()[9].decode()))
                return flow
    else:
        flow[0].append(0)
        flow[1].append(0)
        return flow

  • 代码入口:
if ba.attached_devices():
       mc = BaseMonkeyConfig.monkeyConfig(PATH("monkey.ini"))
       # 打开想要的activity
       ba.open_app(mc["package_name"], mc["activity"])
       temp = ""
        # monkey开始测试
       start_monkey(mc["cmd"], mc["log"])
       time.sleep(1)
       starttime = datetime.datetime.now()
       while True:
           with open(mc["monkey_log"], encoding='utf-8') as monkeylog:
               BaseMonitor.get_cpu(mc["package_name"])
               BaseMonitor.get_men(mc["package_name"])
               BaseMonitor.get_fps(mc["package_name"])
               BaseMonitor.get_battery()
               BaseMonitor.get_flow(mc["package_name"], mc["net"])
               time.sleep(1) # 每1秒采集检查一次
               if monkeylog.read().count('Monkey finished') > 0:
                   endtime = datetime.datetime.now()
                   print("测试完成咯")
                   app = {"beforeBattery": BaseMonitor.get_battery(), "net": mc["net"], "monkey_log": mc["monkey_log"]}
                   report(app, str((endtime - starttime).seconds) + "秒")
                   bo.close()
共收到 42 条回复
B1836c

先学习下~

E74998

感谢分享,学习了!

104 seveniruby 将本帖设为了精华贴 07月13日 19:48
96

非常好 谢谢

—— 来自TesterHome官方 安卓客户端

7549



github上面,是不是漏了 configparser

6504
7549466895041 回复

自带的,你确定下是不是环境问题,我用的py3

7e59e0

这个很不多,尝试用用

3295

不错,我有个建议,如果做成,不需要monkey,可以自己手动操作,进行性能数据收集的会更好。配上monkey还是有局限性的~

214

楼主你好,电量测试曲线y轴是电量百分比吗?看起来是越来越高,是因为测试过程中连接数据线导致的吗?

3295

试了下,我这边存在这个问题

6504
214oscar 回复

是的,一直连着电脑充电

6504
3295an168ge 回复

你自己调试下:

  • 打印下pid为多少
  • 打印下获取电量那里的split信息
  • 手动命令获取电量信息
10200

开始跑monkey等的命令,是否需要+&

7549
6504lose 回复

好吧,我是py2

854941
3295an168ge 回复

同样问题,你解决了吗?

14997

首先感谢楼主,真的很好用,我已经跑起来了,但是发现ftp的值一直是60,是不是因为我没有打开开发者模式里面显示掉帧的按钮尼???

6504
10200UDLD 回复

不用的

14997
6504lose 回复

那为什么一直是60尼?这样子不科学,实际应该掉帧应该是挺严重的哦~

6504
14997jierong01 回复

对的,打开开发者里面的GPU呈现模式分析-在adb shell dumpsys gcxinfo中

14997
6504lose 回复

那我有空再去试试,谢谢啦~

91335c

测试完成后,形成的图表怎么没有变化?还是楼主之前的demo图表

91335c
14997jierong01 回复

一直是60,这个我测试出来的也是这种情况

14997
91335cfeng_test 回复

你解决了这个问题了吗????

428

想请教下:
1、adb shell dumpsys cpuinfo | findstr " + pkg_name 这种形式获取cpu经常会超过100%,这是为什么?
2、dumpsys cpuinfo和top取cpu使用率的区别是什么?

6504
42875281920 回复

你打印下取值情况,或者你用下面的方式排除下:

6504
14997jierong01 回复
  • 打开开发者里面的GPU呈现模式分析-在adb shell dumpsys gcxinfo中
  • 生成的excel报告数据没有变化?应该不可能,你清空下excel里面的所有数据,看看生成结果
15929

Mac 下报错的小伙伴看过来啦!
Mac下运行会报这个错误:

提示文件路径错误,解决办法为在BaseMonkeyConfig.py文件中的下段:

替换为图中显示的字样😊

0674fc
3295an168ge 回复

打印一下 print(item.split())
[b'u0_a186', b'27282', b'880', b'1276836', b'106252', b'0000000000', b'R', b'com.roobo.pudding']
只有8个 你取if item.split()[8].decode() == pkg_name: 肯定超出边界值了。改成7就可以了

91335c
0674fcsven 回复

边界值的问题,想请教下,是开始执行ok,执行到后面,数据多了,就报边界问题了

428
6504lose 回复

top和dumpsys cpuinfo取值都能针对pid取值,但是后者的取值往往大于前者,而且后者还有大于100%的情况存在,这两个的区别是什么?

6504
42875281920 回复

都是一样的,我这里试过了没有100%,看图自己分析下:

A972e5
6504lose 回复

你好,fps 一直显示的是60?这个是什么问题?开发者里面的GPU呈现模式分析-在adb shell dumpsys gcxinfo中 这个已经打开

A972e5

您好,为什么内存会是151%,超过100%

6504

@aecho 如果是长时间跑,可以先把采集数据设置时间长一点,还有现在长时间跑回出现上面朋友说的边界和数据统计问题,后续我看看怎么优化下

A972e5
6504lose 回复

def avgMen(men, total):
if len(men):
_men = [math.ceil(((men[i]) / total) * 1024) for i in range(len(men))]
return str(math.ceil(sum(_men) / len(_men))) + "%"
return "0%"

百分比的话 为什么要*1024?这里应该不需要*1024吧

8814

你好,请问为什么经常跑到这个地方经常会报错

出错时,在cmd中查看这条命令,打印的值显示好像也是正常的

6504
8814hlfang 回复

关闭excel试试

6504
42875281920 回复

dumpsys 拿到的是几个cpu的值,所以可能得到100+%的值,还是proc/pid/stat 靠谱点,后续我优化下

6504
A972e5aecho 回复

你确定是打开了吗?我这边试过了几天华为手机都是正常的,,你是用是什么型号手机?

14997
6504lose 回复

这个问题,好像是不同的手机查询出来的信息不一样,我这边查询出来有4列,分别是
Draw Prepare Process Execute,这4列的数据,有的只有3列

8814
6504lose 回复

关闭了还是会出现诶

6504
8814hlfang 回复

打印一下 print(item.split())
[b'u0_a186', b'27282', b'880', b'1276836', b'106252', b'0000000000', b'R', b'com.roobo.pudding']
只有8个 你取if item.split()[8].decode() == pkg_name: 肯定超出边界值了。改成7就可以了

楼上是这样回复的,我这边重现不了。。。奇怪,应该是不同手机取值可能不一样

8814
6504lose 回复

有时候行,有时候不行,这比较纠结

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册