├── .idea ├── .name ├── AppPerformance.iml ├── misc.xml ├── modules.xml └── vcs.xml ├── PerConfig.py ├── README.md ├── lib ├── AppAdbCom.py ├── AppDevInfo.py ├── AppMonitor.py ├── AppOperateFile.py ├── AppOperatePick.py ├── AppReport.py └── __init__.py ├── monkey_stop.py ├── report.png ├── report ├── APU0215C08002952_com.aliyun.alink_Medium_report.html └── __init__.py └── testCase ├── ManualTest.py ├── MonkeyTest.py └── __init__.py /.idea/.name: -------------------------------------------------------------------------------- 1 | AppPerformance -------------------------------------------------------------------------------- /.idea/AppPerformance.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PerConfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | 4 | import random,os 5 | 6 | class AppPerCon(object): 7 | # apk包名 8 | package_name = "com.aliyun.alink" 9 | # 活动名 10 | alink_Activity = 'com.aliyun.alink/.page.main.MainActivity' 11 | # 默认设备列表 12 | device_dict = {} 13 | #手机安装应用默认UID,通过adb进行查询可获得 14 | appuid = {'MATE8':{'com.robam.roki':'10274','com.UCMobile':'10156','com.aliyun.alink':'10222'}, 15 | 'MATE10':{'com.robam.roki': '10164', 'com.UCMobile':'10138','com.aliyun.alink':'10145'} 16 | } 17 | # 网络 18 | net = "wifi" 19 | # monkey seed值,随机产生 20 | # monkey_seed = str(random.randrange(1, 1000)) 21 | monkey_seed = 200 22 | # monkey 参数 23 | monkey_parameters_full = "--throttle 50 --ignore-crashes --ignore-timeouts --pct-touch 80 --pct-trackball 5 --pct-appswitch 9 --pct-syskeys 1 --pct-motion 5 -v -v -v 1000" 24 | monkey_parameters_medi = "--throttle 150 --ignore-crashes --ignore-timeouts --pct-touch 80 --pct-trackball 5 --pct-appswitch 9 --pct-syskeys 1 --pct-motion 5 -v -v -v 2500" 25 | #monkey_parameters = "--throttle 500 -v -v -v 500" 26 | # log保存地址 27 | log_location = os.path.dirname(os.path.realpath(__file__))+"\log" 28 | #性能数据存储目录 29 | info_path = os.path.dirname(os.path.realpath(__file__))+"\info" + "\\" 30 | # report保存地址 31 | report_path = os.path.dirname(os.path.realpath(__file__)) + "\\report\\" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 需要安装依赖包pyecharts,安装方法百度即可 2 | 3 | 打开PerConfig,修改pack_name为你需要测试的APP包名,如要测试UC浏览器即改为'com.UCMobile',xxx_Activity为APP主活动,比如UC浏览器的主活动名称为'com.UCMobile/.main.UCMobile',这里改为你自己的活动名称即可,使用adb命令即可查看,详细步骤可上网百度一下 4 | # AppPerformance 5 | 6 | Android移动端性能测试工具 7 | 8 | 连接上手机直接运行testcase下的MonkeyTest.py 即可,自动生成测试报告 9 | 10 | devicename_com.aliyun.alink_Medium_report 11 | 12 | 效果如下: 13 | 14 | ![Alt text](https://github.com/jtmaxzhu/AppPerformance/blob/master/report.png) 15 | -------------------------------------------------------------------------------- /lib/AppAdbCom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,time,subprocess 4 | from PerConfig import AppPerCon 5 | 6 | class AdbDebug(object): 7 | #adb通用处理函数 8 | # def adbCommon(self,target): 9 | # list = self.checkDevices() 10 | # count = len(list) 11 | # if target + 1 > count: 12 | # print "请确认连接手机数量,输入正确的序号,0为第一台,依此类推" 13 | # return 14 | # return list 15 | 16 | 17 | def call_adb(self, command): 18 | result = '' 19 | command_text = "adb %s" % (command) 20 | results = os.popen(command_text, "r") 21 | while True: 22 | line = results.readline() 23 | if not line: 24 | break 25 | result += line 26 | results.close() 27 | return result 28 | 29 | def checkDevices(self): 30 | res = self.call_adb("devices") 31 | devices = res.partition('\n')[2].replace('\n', '').split('\tdevice') 32 | return [device for device in devices if len(device) > 2] 33 | 34 | #停止adb服务 35 | def adbStop(self): 36 | return self.call_adb("kill-server") 37 | 38 | #开启adb服务 39 | def adbStart(self): 40 | return self.call_adb("start-server") 41 | 42 | #查看adb版本 43 | def adbVersion(self): 44 | return self.call_adb("version") 45 | 46 | #开启adb网络调试接口(需连接USB线) 47 | def adbTcp(self, target): 48 | return self.call_adb("-s %s tcpip 5555"% (target)) 49 | 50 | #网络调试连接 51 | def adbNetConOpen(self, target, address): 52 | return self.call_adb("-s %s connect %s" % (target, address)) 53 | 54 | #关闭网络调试连接 55 | def adbNetConClose(self, target, address): 56 | return self.call_adb("-s %s disconnect %s" % (target, address)) 57 | 58 | 59 | # 将电脑文件拷贝到手机里面 60 | # [电脑上的目录] < 设备里的文件路径 > 61 | def push(self, target, local, remote): 62 | result = self.call_adb("-s %s push %s %s" % (target, local, remote)) 63 | return result 64 | 65 | 66 | # 拉数据到本地 67 | # < 设备里的文件路径 > [电脑上的目录] 68 | def pull(self, target, remote, local): 69 | result = self.call_adb("-s %s pull %s %s" % (target, remote, local)) 70 | return result 71 | 72 | #电脑端安装应用 73 | # -l 将应用安装到保护目录 / mnt / asec 74 | # -r 允许覆盖安装 75 | # -t 允许安装AndroidManifest.xml里application指定android:testOnly = "true"的应用 76 | # -s 将应用安装到sdcard 77 | # -d 允许降级覆盖安装 78 | # -g 授予所有运行时权限 79 | def adbInstallApk(self, target, local): 80 | return self.call_adb("-s %s install %s"(target, local)) 81 | 82 | def adbInstallApk(self, var, local): 83 | return self.call_adb("install "+ var + local) 84 | 85 | #电脑端卸载应用 86 | # < packname > 表示应用的包名,-k 87 | # 参数可选,表示卸载应用但保留数据和缓存目录。 88 | def adbUninstallApk(self, target, packName): 89 | return self.call_adb("-s %s uninstall %s" % (target, packName)) 90 | 91 | def adbUninstallApk(self, target, var, packName): 92 | return self.call_adb("-s %s uninstall %s %s" % (target, var, packName)) 93 | 94 | 95 | #查看应用列表 96 | # 无 所有应用 97 | # -f 显示应用关联的 apk 文件 98 | # -d 只显示 disabled 的应用 99 | # -e 只显示 enabled 的应用 100 | # -s 只显示系统应用 101 | # -3 只显示第三方应用 102 | # -i 显示应用的 installer 103 | # -u 包含已卸载应用 104 | def adbGetPmlist(self, target, var): 105 | return self.call_adb("-s %s shell pm list packages %s" % (target, var)) 106 | 107 | # 清除应用数据缓存 108 | def adbCacheClear(self, target, packName): 109 | result = self.call_adb("-s %s shell pm clear %s" % (target, packName)) 110 | return result.rstrip() 111 | 112 | # 查看应用详细信息 113 | def adbGetAppInfo(self, target, packName): 114 | result = self.call_adb("-s %s shell dumpsys package %s" % (target, packName)) 115 | return result.strip() 116 | 117 | # 启动Activity 118 | def adbStartActivity(self, target, activity): 119 | result = self.call_adb("-s %s shell am start %s" % (target, activity)) 120 | return result.rstrip() 121 | 122 | # 强制停止Activity 123 | def adbStopActivity(self, target, packName): 124 | result = self.call_adb("-s %s shell am force-stop %s" % (target, packName)) 125 | return result.rstrip() 126 | 127 | # 获得设备型号 128 | def adbGetDeviceModel(self, target): 129 | result = self.call_adb("-s %s shell getprop ro.product.model" % (target)) 130 | return result.rstrip() 131 | 132 | # 获取设备品牌 133 | def adbGetDeviceBrand(self, target): 134 | result = self.call_adb("-s %s shell getprop ro.product.brand" % (target)) 135 | return result.rstrip() 136 | 137 | # 获得设备名称 138 | def adbGetDeviceName(self, target): 139 | result = self.call_adb("-s %s shell getprop ro.product.name" % (target)) 140 | return result.rstrip() 141 | 142 | 143 | # 获得设备处理器型号 144 | def adbGetDeviceBoard(self, target): 145 | result = self.call_adb("-s %s shell getprop ro.product.board" % (target)) 146 | return result.rstrip() 147 | 148 | 149 | # 设备重启 150 | def adbDeviceReboot(self, target): 151 | result = self.call_adb("-s %s reboot" % (target)) 152 | return result.rstrip() 153 | 154 | 155 | # 获取电池状况 156 | def adbGetBattery(self, target): 157 | result = self.call_adb("-s %s shell dumpsys battery" % (target)) 158 | return result.rstrip() 159 | 160 | # 获取屏幕分辨率 161 | def adbGetScreenSize(self, target): 162 | result = self.call_adb("-s %s shell wm size" % (target)) 163 | return result.rstrip() 164 | 165 | # 获取屏幕dpi 166 | def adbGetScreenDPI(self, target): 167 | result = self.call_adb("-s %s shell wm density" % (target)) 168 | return result.rstrip() 169 | 170 | # 获取屏幕参数 171 | def adbGetScreenInfo(self, target): 172 | result = self.call_adb("-s %s shell dumpsys window displays" % (target)) 173 | return result.rstrip() 174 | 175 | # 获取Android系统版本 176 | def adbGetAndroidVersion(self, target): 177 | result = self.call_adb("-s %s shell getprop ro.build.version.release" % (target)) 178 | return result.strip() 179 | 180 | # 获取IP地址 181 | def adbGetDevIP(self, target): 182 | result = self.call_adb("-s %s shell ifconfig wlan0" % (target)) 183 | if int(self.adbGetAndroidVersion(target).split(".")[0]) > 4: 184 | if result.rsplit(":")[1][19:23] == "inet": 185 | return result.rsplit(":")[2][:13] 186 | else: 187 | print "WIFI未开启,请打开WIFI开关" 188 | return 189 | else: 190 | return result.rsplit(":")[1][4:17] 191 | 192 | # 获取MAC地址 193 | def adbGetDevMac(self, target): 194 | result = self.call_adb("-s %s shell cat /sys/class/net/wlan0/address" % (target)) 195 | return result.strip() 196 | 197 | # 获取CPU信息 198 | def adbGetDevCPU(self, target): 199 | result = self.call_adb("-s %s shell cat /proc/cpuinfo" % (target)) 200 | return result.strip() 201 | 202 | 203 | # 获取系统内存信息 204 | def adbGetDevMem(self, target): 205 | result = self.call_adb("-s %s shell cat /proc/meminfo" % (target)) 206 | return result.strip() 207 | 208 | 209 | # 获取应用内存信息 210 | def adbGetDevPidMem(self, target, packname): 211 | result = self.call_adb("-s %s shell dumpsys meminfo %s" % (target, packname)) 212 | return result.strip() 213 | 214 | 215 | 216 | # 获取总的CPU使用时间 217 | def adbGetCpuTime(self, target): 218 | result = self.call_adb("-s %s shell cat /proc/stat" % (target)) 219 | return result.strip() 220 | 221 | # 获取进程CPU时间片 222 | def adbGetPidJiff(self, target, pid): 223 | result = self.call_adb("-s %s shell cat /proc/%s/stat" % (target, pid)) 224 | return result.strip() 225 | 226 | # 获取进程fps 227 | def adbGetPidfps(self, target, packname): 228 | result = self.call_adb("-s %s shell dumpsys gfxinfo %s" % (target, packname)) 229 | return result.strip() 230 | 231 | # 获取进程流量信息 232 | def adbGetPidflow(self, target, packname, flag): 233 | if int(self.adbGetAndroidVersion(target).split('.')[0]) < 8: 234 | uid = AppPerCon.appuid['MATE8'][packname] 235 | rec = self.call_adb("-s %s shell cat /proc/uid_stat/%s/tcp_rcv" % (target, uid)).strip() 236 | sen = self.call_adb("-s %s shell cat /proc/uid_stat/%s/tcp_snd" % (target, uid)).strip() 237 | # print rec, sen 238 | flow = float(rec) + float(sen) 239 | else: 240 | if flag == 1: 241 | # self.adbStartActivity(target, activity) 242 | pid = self.adbGetPid(target, packname) 243 | print pid 244 | lis = self.call_adb("-s %s shell cat /proc/%s/net/dev" % (target, pid)).strip().split() 245 | for k, v in enumerate(lis): 246 | if v == 'wlan0:': 247 | recindex = k + 1 248 | tranindex = k + 9 249 | flow = float(lis[recindex])+float(lis[tranindex]) 250 | self.adbStopActivity(target, packname) 251 | break 252 | else: 253 | lis = self.call_adb("-s %s shell cat /proc/net/dev" % (target)).strip().split() 254 | for k, v in enumerate(lis): 255 | if v == 'wlan0:': 256 | recindex = k + 1 257 | tranindex = k + 9 258 | flow = float(lis[recindex]) + float(lis[tranindex]) 259 | break 260 | 261 | return flow 262 | 263 | 264 | def adbGetPid(self, target, packname): 265 | if int(self.adbGetAndroidVersion(target).split('.')[0]) < 8: 266 | pid = self.call_adb("-s %s shell ps | findstr %s"%(target, packname)).rstrip().split("\n") 267 | if pid == ['']: 268 | print "this process doesn't exist" 269 | return None 270 | else: 271 | for item in pid: 272 | if item.split()[8] == packname: 273 | return item.split()[1] 274 | else: 275 | pid = self.call_adb("-s %s shell top -n 1 | findstr %s" % (target, packname)).strip().split() 276 | if pid == []: 277 | print "this process doesn't exist" 278 | return None 279 | else: 280 | return pid[0] 281 | 282 | 283 | 284 | def adbGetUid(self, target, packname): 285 | pid = self.adbGetPid(target, packname) 286 | lis = self.call_adb('-s %s shell cat /proc/%s/status' % (target, pid)).split() 287 | uid = 0 288 | for k, v in enumerate(lis): 289 | if v == 'Uid:': 290 | index = k + 1 291 | uid = lis[index] 292 | break 293 | return uid 294 | 295 | def adbGetAPPstartTime(self, target, activity): 296 | lis = self.call_adb('-s %s shell am start -W %s' % (target, activity)) 297 | for k, v in enumerate(lis): 298 | if v == 'TotalTime:': 299 | index = k + 1 300 | time = lis[index] 301 | break 302 | return time 303 | 304 | 305 | 306 | 307 | if __name__ == '__main__': 308 | pass 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | -------------------------------------------------------------------------------- /lib/AppDevInfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,re 4 | from lib.AppAdbCom import AdbDebug 5 | ad = AdbDebug() 6 | 7 | class DeviceMsg(object): 8 | 9 | def GetDevModel(self, dev): 10 | result = {} 11 | result["release"] = ad.adbGetAndroidVersion(dev)# Android 系统,如anroid 4.0 12 | result["phone_name"] = ad.adbGetDeviceName(dev) # 手机名 13 | result["phone_model"] = ad.adbGetDeviceBrand(dev) # 手机品牌 14 | return result 15 | 16 | #获取手机内存总数 17 | def GetDevMemTotal(self, dev): 18 | list = ad.adbGetDevMem(dev).split() 19 | for k, v in enumerate(list): 20 | if str(v) == 'MemTotal:': 21 | return int(list[k+1]) 22 | 23 | #获取手机处理器核数量 24 | def GetDevCpuCore(self, dev): 25 | resp = ad.adbGetDevCPU(dev) 26 | return str(len(re.findall("processor", resp))) 27 | 28 | #获取手机屏幕分辨率 29 | def GetDevPix(self, dev): 30 | resp = ad.adbGetScreenSize(dev).split()[2] 31 | return resp 32 | 33 | def GetDevMsg(self, dev): 34 | pix = self.GetDevPix(dev) 35 | men_total = self.GetDevMemTotal(dev) 36 | phone_msg = self.GetDevModel(dev) 37 | cpu_sum = self.GetDevCpuCore(dev) 38 | # print(dev + ":"+ pix,men_total,phone_msg,cpu_sum) 39 | return phone_msg, men_total, cpu_sum, pix 40 | 41 | 42 | if __name__ == "__main__": 43 | pass 44 | 45 | -------------------------------------------------------------------------------- /lib/AppMonitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,subprocess,time,re,time 4 | import AppAdbCom 5 | from lib.AppOperatePick import OperatePick 6 | from PerConfig import AppPerCon 7 | from wsgiref.validate import validator 8 | 9 | 10 | PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(os.path.realpath('__file__')), p)) #os.path.realpath(path) 返回path的真实路径 11 | dev_list =[] 12 | ad = AppAdbCom.AdbDebug() 13 | pick = OperatePick() 14 | Config = AppPerCon() 15 | 16 | class AppMoni(object): 17 | 18 | # 判断传入的dev字符串是否是ip地址 19 | def IsIP(self, dev): 20 | if dev == '': 21 | return False 22 | index = dev.find(':') 23 | if index != -1: 24 | ip = dev[:index] 25 | addr = ip.split('.') 26 | if len(addr) != 4: 27 | return False 28 | for i in addr: 29 | if int(i) < 255 and int(i) >= 0: 30 | return True 31 | else: 32 | return False 33 | 34 | 35 | def get_device(self): 36 | rt = os.popen('adb devices').readlines() # os.popen()执行系统命令并返回执行后的结果 37 | n = len(rt) - 2 38 | print("当前已连接待测手机数为:" + str(n)) 39 | for i in range(n): 40 | nPos = rt[i + 1].index("\t") 41 | dev = rt[i+1][:nPos] 42 | dev_list.append(dev) 43 | return dev_list 44 | 45 | 46 | def get_pid(self, target, pack): 47 | pid = ad.adbGetPid(target, pack) 48 | return pid 49 | 50 | def get_devSystemison(self,target): 51 | return ad.adbGetAndroidVersion(target) 52 | 53 | def get_battery(self, target): 54 | list = ad.adbGetBattery(target).split() 55 | for k,v in enumerate(list): 56 | if str(v) == "level:": 57 | battery = int(list[k+1]) 58 | print("--------battery--------") 59 | if self.IsIP(target) == True: 60 | target = target.split(':')[0].replace(".", "") 61 | print type(battery) 62 | pick.writeInfo(battery, PATH(Config.info_path + target + "_battery.pickle")) 63 | else: 64 | pick.writeInfo(battery, PATH(Config.info_path + target + "_battery.pickle")) 65 | return battery 66 | 67 | def totalCpuTime(self, dev): 68 | user = nice = system = idle = iowait = irq = softirq = 0 69 | ''' 70 | user 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒 71 | nice 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies) 72 | system 从系统启动开始累计到当前时刻,核心时间(单位:jiffies) 73 | idle 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies) 74 | iowait 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) , 75 | irq 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies) 76 | softirq 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies) 77 | ''' 78 | res = ad.adbGetCpuTime(dev).split() 79 | try: 80 | for info in res: 81 | if info == "cpu": 82 | user = res[1] 83 | nice = res[2] 84 | system = res[3] 85 | idle = res[4] 86 | iowait = res[5] 87 | irq = res[6] 88 | softirq = res[7] 89 | result = int(user) + int(nice) + int(system) + int(idle) + int(iowait) + int(irq) + int(softirq) 90 | # print("totalCpuTime=" + str(result)) 91 | return result 92 | except: 93 | return 0 94 | 95 | def pidCpuJiff(self, target, pid): 96 | ''' 97 | utime 该任务在用户态运行的时间,单位为jiffies 98 |   stime 该任务在核心态运行的时间,单位为jiffies 99 |   cutime 累计的该任务的所有的waited-for进程曾经在用户态运行的时间,单位为jiffies 100 |   cstime= 累计的该任务的所有的waited-for进程曾经在核心态运行的时间,单位为jiffies 101 | ''' 102 | utime = stime = cutime = cstime = 0 103 | try: 104 | res = ad.adbGetPidJiff(target, pid).split() 105 | utime = res[13] 106 | stime = res[14] 107 | cutime = res[15] 108 | cstime = res[16] 109 | result = int(utime) + int(stime) + int(cutime) + int(cstime) 110 | except: 111 | result = 0 112 | return result 113 | 114 | 115 | ''' 116 | 通过jiff来进行CPU计算 117 | ''' 118 | 119 | def cpu_jiffrate(self, dev, packname): 120 | pid = self.get_pid(dev, packname) 121 | processCpuTime1 = self.pidCpuJiff(dev, pid) 122 | totalCpuTime1 = self.totalCpuTime(dev) 123 | time.sleep(1) 124 | processCpuTime2 = self.pidCpuJiff(dev, pid) 125 | totalCpuTime2 = self.totalCpuTime(dev) 126 | processCpuTime3 = processCpuTime2 - processCpuTime1 127 | totalCpuTime3 = (totalCpuTime2 - totalCpuTime1) 128 | cpu = 100 * (processCpuTime3) / (totalCpuTime3) 129 | return cpu 130 | 131 | ''' 132 | 计算某进程的cpu使用率 top方式 133 | dev : 设备号 134 | packname: 应用包名 135 | flag : # 0: 空闲状态 136 | # 1:中等压力 137 | # 2:满压力 138 | ''' 139 | def pid_cpuRate(self, dev, packname, flag): 140 | pid = self.get_pid(dev, packname) 141 | if int(self.get_devSystemison(dev).split('.')[0])<8: 142 | reslist = ad.call_adb("-s %s shell top -s cpu -n 1 | findstr %s" % (dev, pid)).split() 143 | #print reslist 144 | ratelist = list(reslist[4]) 145 | strRate = '' 146 | for i in range(len(ratelist) - 1): 147 | strRate += ratelist[i] 148 | rate = int(strRate) 149 | else: 150 | rate = self.cpu_jiffrate(dev, packname) 151 | print("--------设备:%s cpurate--------") % dev 152 | if rate >= 0 and flag == 0: 153 | if self.IsIP(dev) == True: 154 | devIP = dev.split(':')[0].replace(".", "") 155 | pick.writeInfo(rate, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Free_cpu.pickle")) 156 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 157 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Free_cpu.pickle")) 158 | else: 159 | pick.writeInfo(rate, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Free_cpu.pickle")) 160 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 161 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_cpu.pickle")) 162 | elif rate >= 0 and flag == 1: 163 | if self.IsIP(dev) == True: 164 | devIP = dev.split(':')[0].replace(".", "") 165 | pick.writeInfo(rate, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Medium_cpu.pickle")) 166 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 167 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_cpu.pickle")) 168 | else: 169 | pick.writeInfo(rate, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Medium_cpu.pickle")) 170 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 171 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_cpu.pickle")) 172 | elif rate >= 0 and flag == 2: 173 | if self.IsIP(dev) == True: 174 | devIP = dev.split(':')[0].replace(".", "") 175 | pick.writeInfo(rate, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Full_cpu.pickle")) 176 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 177 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_cpu.pickle")) 178 | else: 179 | pick.writeInfo(rate, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Full_cpu.pickle")) 180 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 181 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_cpu.pickle")) 182 | elif rate >= 0 and flag == 3: 183 | if self.IsIP(dev) == True: 184 | devIP = dev.split(':')[0].replace(".", "") 185 | pick.writeInfo(rate, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Manual_cpu.pickle")) 186 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 187 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_cpu.pickle")) 188 | else: 189 | pick.writeInfo(rate, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Manual_cpu.pickle")) 190 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 191 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_cpu.pickle")) 192 | return rate 193 | 194 | #获得CPU进程时间片 195 | def pid_Jiff(self, dev, pid): 196 | processCpuTime1 = self.pidCpuJiff(dev, pid) 197 | time.sleep(1) 198 | processCpuTime2 = self.pidCpuJiff(dev, pid) 199 | processCpuTime3 = processCpuTime2 - processCpuTime1 200 | jiff = processCpuTime3 201 | print("--------jiff--------") 202 | if jiff >= 0: 203 | if self.IsIP(dev) == True: 204 | devIP = dev.split(':')[0].replace(".", "") 205 | pick.writeInfo(jiff, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "_jiff.pickle")) 206 | else: 207 | pick.writeInfo(jiff, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "_jiff.pickle")) 208 | return jiff 209 | 210 | 211 | ''' 212 | 获得指定应用内存信息 213 | # 0: 空闲状态 214 | # 1:中等压力 215 | # 2:满压力 216 | ''' 217 | def pid_mem(self, dev, pkg_name, flag): 218 | lis = ad.adbGetDevPidMem(dev, pkg_name).split() 219 | #print lis 220 | for i in range(len(lis)): 221 | if lis[i] == "TOTAL": 222 | data = lis[i+1] 223 | break 224 | mem = int(data) 225 | print("--------设备:%s mem--------") % dev 226 | if mem >= 0 and flag == 0: 227 | if self.IsIP(dev) == True: 228 | devIP = dev.split(':')[0].replace(".", "") 229 | pick.writeInfo(mem, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Free_mem.pickle")) 230 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 231 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Free_mem.pickle")) 232 | else: 233 | pick.writeInfo(mem, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Free_mem.pickle")) 234 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 235 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_mem.pickle")) 236 | 237 | elif mem >= 0 and flag == 1: 238 | if self.IsIP(dev) == True: 239 | devIP = dev.split(':')[0].replace(".", "") 240 | pick.writeInfo(mem, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Medium_mem.pickle")) 241 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 242 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_mem.pickle")) 243 | else: 244 | pick.writeInfo(mem, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Medium_mem.pickle")) 245 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 246 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_mem.pickle")) 247 | elif mem >= 0 and flag == 2: 248 | if self.IsIP(dev) == True: 249 | devIP = dev.split(':')[0].replace(".", "") 250 | pick.writeInfo(mem, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Full_mem.pickle")) 251 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 252 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_mem.pickle")) 253 | else: 254 | pick.writeInfo(mem, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Full_mem.pickle")) 255 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 256 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_mem.pickle")) 257 | elif mem >= 0 and flag == 3: 258 | if self.IsIP(dev) == True: 259 | devIP = dev.split(':')[0].replace(".", "") 260 | pick.writeInfo(mem, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Manual_mem.pickle")) 261 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 262 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_mem.pickle")) 263 | else: 264 | pick.writeInfo(mem, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Manual_mem.pickle")) 265 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 266 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_mem.pickle")) 267 | return mem 268 | 269 | 270 | # 获得指定应用FPS信息 271 | 272 | def pid_fps(self, dev, pkg_name, flag): 273 | results = ad.adbGetPidfps(dev, pkg_name) 274 | # print results 275 | frames = [x for x in results.split('\n')] 276 | jank_count = 0 277 | vsync_overtime = 0 278 | render_time = 0 279 | try: 280 | for k,v in enumerate(frames): 281 | if v == '\tDraw\tPrepare\tProcess\tExecute' or v == '\tDraw\tProcess\tExecute\r': 282 | indexstart = k+1 283 | elif v == 'View hierarchy:' or v == 'View hierarchy:\r': 284 | indexend = k-1 285 | fra = frames[indexstart:indexend] 286 | frame_count = len(fra) 287 | for frame in fra: 288 | time_block = re.split(r'\s+', frame.strip()) 289 | for k, v in enumerate(frames): 290 | if v == '\tDraw\tProcess\tExecute\r': 291 | render_time = float(time_block[0]) + float(time_block[1]) + float(time_block[2]) 292 | elif v == '\tDraw\tPrepare\tProcess\tExecute': 293 | render_time = float(time_block[0]) + float(time_block[1]) + float(time_block[2]) + float(time_block[3]) 294 | ''' 295 | 当渲染时间大于16.67,按照垂直同步机制,该帧就已经渲染超时 296 | 那么,如果它正好是16.67的整数倍,比如66.68,则它花费了4个垂直同步脉冲,减去本身需要一个,则超时3个 297 | 如果它不是16.67的整数倍,比如67,那么它花费的垂直同步脉冲应向上取整,即5个,减去本身需要一个,即超时4个,可直接算向下取整 298 | 299 | 最后的计算方法思路: 300 | 执行一次命令,总共收集到了m帧(理想情况下m=128),但是这m帧里面有些帧渲染超过了16.67毫秒,算一次jank,一旦jank, 301 | 需要用掉额外的垂直同步脉冲。其他的就算没有超过16.67,也按一个脉冲时间来算(理想情况下,一个脉冲就可以渲染完一帧) 302 | 303 | 所以FPS的算法可以变为: 304 | m / (m + 额外的垂直同步脉冲) * 60 305 | ''' 306 | if render_time > 16.67: 307 | jank_count += 1 308 | if render_time % 16.67 == 0: 309 | vsync_overtime += int(render_time / 16.67) - 1 310 | else: 311 | vsync_overtime += int(render_time / 16.67) 312 | print("-----fps------") 313 | if frame_count == 0: 314 | _fps = 60 315 | else: 316 | _fps = int(frame_count * 60 / (frame_count + vsync_overtime)) 317 | if flag == 1: 318 | if self.IsIP(dev) == True: 319 | devIP = dev.split(':')[0].replace(".", "") 320 | pick.writeInfo(_fps, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Medium_fps.pickle")) 321 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 322 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_fps.pickle")) 323 | else: 324 | pick.writeInfo(_fps, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Medium_fps.pickle")) 325 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 326 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_fps.pickle")) 327 | 328 | elif flag == 2: 329 | if self.IsIP(dev) == True: 330 | devIP = dev.split(':')[0].replace(".", "") 331 | pick.writeInfo(_fps, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Full_fps.pickle")) 332 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 333 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_fps.pickle")) 334 | else: 335 | pick.writeInfo(_fps, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Full_fps.pickle")) 336 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 337 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_fps.pickle")) 338 | elif flag == 3: 339 | if self.IsIP(dev) == True: 340 | devIP = dev.split(':')[0].replace(".", "") 341 | pick.writeInfo(_fps, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "Manual_fps.pickle")) 342 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 343 | PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_fps.pickle")) 344 | else: 345 | pick.writeInfo(_fps, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "Manual_fps.pickle")) 346 | pick.writeInfo(time.strftime("%H:%M:%S", time.localtime(time.time())), 347 | PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_fps.pickle")) 348 | return _fps 349 | except Exception as e: 350 | print "请打开开发者模式中的GPU显示" 351 | 352 | 353 | # 获得指定应用上下行流量信息 354 | def flow(self, dev, packname, activity): 355 | ad.adbStopActivity(dev, packname) 356 | flow1 = self.pid_flowSingle(dev, packname, 0) 357 | time.sleep(1) 358 | ad.adbStartActivity(dev, activity) 359 | time.sleep(15) 360 | flow2 = self.pid_flowSingle(dev, packname, 1) 361 | flow = (flow2 - flow1) / 1024 362 | if self.IsIP(dev) == True: 363 | devIP = dev.split(':')[0].replace(".", "") 364 | pick.writeInfo(flow, PATH(Config.info_path + devIP + "_"+ Config.package_name + "_" + "first_flow.pickle")) 365 | else: 366 | pick.writeInfo(flow, PATH(Config.info_path + dev + "_"+ Config.package_name + "_" + "first_flow.pickle")) 367 | return flow 368 | 369 | def pid_flowSingle(self, dev, packname, flag): 370 | flow = ad.adbGetPidflow(dev, packname, flag) 371 | return flow 372 | 373 | def pid_startTime(self, dev, packname): 374 | time = ad.adbGetPidflow(dev, packname) 375 | return int(time) 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | if __name__ == '__main__': 387 | pass -------------------------------------------------------------------------------- /lib/AppOperateFile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os 4 | 5 | ''' 6 | 操作文件 7 | ''' 8 | class OperateFile(object): 9 | def __init__(self, file, method='w+'): 10 | self.file = file 11 | self.method = method 12 | self.fileHandle = None 13 | 14 | 15 | def mkdir_file(self): 16 | if not os.path.isfile(self.file): 17 | f = open(self.file, self.method) 18 | f.close() 19 | print("创建文件成功") 20 | else: 21 | print("文件已经存在") 22 | 23 | 24 | def remove_file(self): 25 | if os.path.isfile(self.file): 26 | os.remove(self.file) 27 | print("删除文件成功") 28 | else: 29 | print("文件不存在") -------------------------------------------------------------------------------- /lib/AppOperatePick.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os 4 | import pickle 5 | 6 | ''' 7 | 操作文件 8 | ''' 9 | class OperatePick(object): 10 | 11 | def readInfo(self, path): 12 | data=[] 13 | with open(path, 'rb') as f: 14 | try: 15 | data = pickle.load(f) 16 | # print(data) 17 | except EOFError: 18 | data = [] 19 | print("读取文件错误,文件内容为空") 20 | print("------read-------") 21 | print data 22 | return data 23 | 24 | def writeSum(self, init, data=None, path="data.pickle"): 25 | if init == 0: 26 | result = data 27 | else: 28 | _read = self.readInfo(path) 29 | result = _read - _read 30 | 31 | with open(path, 'wb') as f: 32 | print("------writeSum-------") 33 | print "Sum:%s" % result 34 | pickle.dump(result, f) 35 | 36 | def readSum(self, path): 37 | data = {} 38 | with open(path, 'rb') as f: 39 | try: 40 | data = pickle.load(f) 41 | except EOFError: 42 | data = {} 43 | print("读取文件错误,文件内容为空") 44 | print("------read-------") 45 | return data 46 | 47 | def writeInfo(self, data, path): 48 | _read = self.readInfo(path) 49 | result=[] 50 | if _read: 51 | _read.append(data) 52 | result = _read 53 | else: 54 | result.append(data) 55 | with open(path, 'wb') as f: 56 | print("------writeInfo-------") 57 | print result 58 | pickle.dump(result, f) 59 | -------------------------------------------------------------------------------- /lib/AppReport.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,subprocess,time,re,time 4 | from pyecharts import Bar, Line, Scatter, EffectScatter, Grid, Page, Scatter3D, Overlap 5 | from PerConfig import AppPerCon 6 | from lib.AppAdbCom import AdbDebug 7 | from lib.AppDevInfo import DeviceMsg 8 | from lib.AppMonitor import AppMoni 9 | from lib.AppOperateFile import OperateFile 10 | from lib.AppOperatePick import OperatePick 11 | 12 | PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(os.path.realpath('__file__')), p)) #os.path.realpath(path) 返回path的真实路径 13 | pick = OperatePick() 14 | 15 | class Report(object): 16 | def __init__(self, dev, reportName, flag ): 17 | self.reportName = reportName 18 | self.dev = dev 19 | self.pack = AppPerCon.package_name 20 | self.flag = flag 21 | 22 | def createComparReport(self): 23 | pass 24 | 25 | def createReport(self, dev): 26 | lisMem = pick.readInfo(AppPerCon.info_path + self.dev + '_' + self.pack + '_' + self.flag + "_mem.pickle") 27 | lisCpu = pick.readInfo(AppPerCon.info_path + self.dev + '_' + self.pack + '_' + self.flag + "_cpu.pickle") 28 | lisFps = pick.readInfo(AppPerCon.info_path + self.dev + '_' + self.pack + '_' + self.flag + "_fps.pickle") 29 | lisDevinfo = pick.readInfo(AppPerCon.info_path + "info.pickle") 30 | 31 | 32 | pix = lisDevinfo[0][dev]['header']['pix'] 33 | net = lisDevinfo[0][dev]['header']['net'] 34 | name = lisDevinfo[0][dev]['header']['phone_name'] 35 | rom = lisDevinfo[0][dev]['header']['rom'] 36 | 37 | 38 | devinfo = "设备信息-分辨率:" + pix + "\\"\ 39 | +"网络:" + net + "\\"\ 40 | +"设备名:"+ name + "\\"\ 41 | +"内存容量:"+ str(rom)+"MB" 42 | 43 | 44 | 45 | 46 | 47 | 48 | v1 = [i for i in lisCpu if type(i) == str] 49 | v2 = [i for i in lisCpu if type(i) != str] 50 | v3 = [i for i in lisMem if type(i) == str] 51 | v4 = [i for i in lisMem if type(i) != str] 52 | v5 = [i for i in lisFps if type(i) == str] 53 | v6 = [i for i in lisFps if type(i) != str] 54 | 55 | 56 | 57 | page = Page(self.reportName.decode('utf-8')) 58 | 59 | attr = v1 60 | bar = Bar() 61 | bar.add("ROKI_bar", attr, v2) 62 | line = Line(self.reportName +"-"+"CPU占用", devinfo ,width=1200, height=400) 63 | line.add("ROKI_line", attr, v2, is_stack=True, is_label_show=True, 64 | is_smooth=False ,is_more_utils =True,is_datazoom_show=False, yaxis_formatter="%", 65 | mark_point=["max", "min"], mark_line=["average"]) 66 | 67 | overlap = Overlap(self.reportName +"-"+"CPU占用", width=1200, height=400) 68 | overlap.add(line) 69 | overlap.add(bar) 70 | page.add(overlap) 71 | 72 | attr1 = v3 73 | line1 = Line(self.reportName + "-" + "MEM消耗", width=1200, height=400) 74 | line1.add("ROKI_line", attr1, v4, is_stack=True, is_label_show=True, is_smooth=False,is_more_utils =True, is_datazoom_show=False, 75 | yaxis_formatter="MB", mark_point=["max", "min"], mark_line=["average"]) 76 | bar1 = Bar() 77 | bar1.add("ROKI_bar", attr1, v4) 78 | overlap1 = Overlap(width=1200, height=400) 79 | overlap1.add(line1) 80 | overlap1.add(bar1) 81 | page.append(overlap1) 82 | 83 | attr2 = v5 84 | line2 = Line(self.reportName + "-" + "FPS帧率", width=1200, height=400) 85 | line2.add("ROKI_line", attr2, v6, is_stack=True, is_label_show=True, is_smooth=False,is_more_utils =True, is_datazoom_show=False, 86 | yaxis_formatter="fps", mark_point=["max", "min"], mark_line=["average"]) 87 | bar2 = Bar() 88 | bar2.add("ROKI_bar", attr2, v6) 89 | overlap2 = Overlap(width=1200, height=400) 90 | overlap2.add(line2) 91 | overlap2.add(bar2) 92 | page.append(overlap2) 93 | 94 | page.render(AppPerCon.report_path + self.dev +"_"+ self.pack + "_"+self.flag+"_"+"report.html") 95 | 96 | if __name__ == '__main__': 97 | rep= Report("APU0215C08002952","Alink V2.6.17 性能测试报告", "Medium") 98 | rep.createReport("APU0215C08002952") 99 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- -------------------------------------------------------------------------------- /monkey_stop.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # coding: utf-8 3 | import subprocess 4 | from Base import BaseMonitor 5 | import time 6 | import os 7 | 8 | def stop_monkey(dev): 9 | monkey_name = "com.android.commands.monkey" 10 | pid = subprocess.Popen("adb -s " + dev + " shell ps | findstr " + monkey_name, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE).stdout.readlines() 11 | if pid =="": 12 | print("No monkey running in %s" % dev) 13 | else: 14 | for item in pid: 15 | if item.split()[8].decode() == monkey_name: 16 | monkey_pid = item.split()[1].decode() 17 | cmd_monkey = "adb -s " + dev + " shell kill %s" % (monkey_pid) 18 | os.popen(cmd_monkey) 19 | print("Monkey in %s was killed" % dev) 20 | time.sleep(2) 21 | 22 | def reboot(dev): 23 | cmd_reboot = "adb -s " + dev + " reboot" 24 | os.popen(cmd_reboot) 25 | 26 | if __name__ == '__main__': 27 | device_list = BaseMonitor.get_devices() 28 | for dev in device_list: 29 | stop_monkey(dev) 30 | #reboot(dev,dev_model) #如需要重启设备,删除注释即可 -------------------------------------------------------------------------------- /report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtmaxzhu/AppPerformance/0c90e0e1aba23ea03db3062780fd3266046773aa/report.png -------------------------------------------------------------------------------- /report/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- -------------------------------------------------------------------------------- /testCase/ManualTest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,shutil 4 | import threading 5 | import time,datetime,subprocess 6 | 7 | from PerConfig import AppPerCon 8 | from lib.AppAdbCom import AdbDebug 9 | from lib.AppDevInfo import DeviceMsg 10 | from lib.AppMonitor import AppMoni 11 | from lib.AppOperateFile import OperateFile 12 | from lib.AppOperatePick import OperatePick 13 | 14 | PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(os.path.realpath('__file__')), p)) #os.path.realpath(path) 返回path的真实路径 15 | 16 | ad = AdbDebug() 17 | apm = AppMoni() 18 | devMs = DeviceMsg() 19 | pick = OperatePick() 20 | Config = AppPerCon() 21 | 22 | #全局变量 23 | MemTestFlag = 0 24 | monkey_log='' 25 | path_log='' 26 | 27 | 28 | 29 | # 手机信息 30 | def get_phone(dev): 31 | phone_info = devMs.GetDevMsg(dev) 32 | # print phone_info 33 | app = {} 34 | app["phone_name"] = phone_info[0]["phone_name"] + "_" + phone_info[0]["phone_model"] + "_" + phone_info[0]["release"] 35 | app["rom"] = phone_info[1] 36 | app["kel"] = phone_info[2] 37 | app["pix"] = phone_info[3] 38 | return app 39 | 40 | def Create_pickle(dev, app, data): 41 | print("创建持久性文件...") 42 | if apm.IsIP(dev) == True: 43 | devIP = dev.split(':')[0].replace(".","") 44 | Manualmen = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_mem.pickle") 45 | Manualcpu = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_cpu.pickle") 46 | Manualjiff = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_jiff.pickle") 47 | Manualfps = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Manual_fps.pickle") 48 | 49 | else: 50 | Manualmen = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_mem.pickle") 51 | Manualcpu = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_cpu.pickle") 52 | Manualjiff = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_jiff.pickle") 53 | Manualfps = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Manual_fps.pickle") 54 | 55 | # time.sleep(2) 56 | # app[dev] = {"freemen": freemen, "medimen": medimen, "fullmen": fullmen, 57 | # "freecpu": freecpu, "medicpu": medicpu, "fullcpu": fullcpu, 58 | # "header": get_phone(dev)} 59 | OperateFile(Manualmen).mkdir_file() 60 | OperateFile(Manualcpu).mkdir_file() 61 | OperateFile(Manualjiff).mkdir_file() 62 | OperateFile(Manualfps).mkdir_file() 63 | OperateFile(PATH(Config.info_path + "sumInfo.pickle")).mkdir_file() # 用于记录是否已经测试完毕,里面存的是一个整数 64 | OperateFile(PATH(Config.info_path + "info.pickle")).mkdir_file() # 用于记录统计结果的信息,是[{}]的形式 65 | pick.writeSum(0, data, PATH(Config.info_path + "sumInfo.pickle")) # 初始化记录当前真实连接的设备数 66 | 67 | #log生成函数 68 | def logProcess(dev, runtime): 69 | # logcat日志 70 | logcat_log = path_log + "\\" + runtime + "logcat.log" 71 | cmd_logcat = "-s " + dev + " logcat -d > %s" % (logcat_log) 72 | ad.call_adb(cmd_logcat) 73 | print 'logcat 完成' 74 | 75 | # "导出traces文件" 76 | traces_log = path_log + "\\" + runtime + "traces.log" 77 | cmd_traces = "-s " + dev + " shell cat /data/anr/traces.txt > %s" % (traces_log) 78 | ad.call_adb(cmd_traces) 79 | print 'traces_log 完成' 80 | 81 | def start(dev): 82 | rt = os.popen('adb devices').readlines() # os.popen()执行系统命令并返回执行后的结果 83 | num = len(rt) - 2 84 | print(num) 85 | app = {} 86 | Create_pickle(dev, app, num) 87 | signal = raw_input("现在是手动测试部分,是否要开始你的测试,请输入(y or n): ") 88 | if signal == 'y' or 'Y': 89 | print("测试即将开始,请打开需要测试的app并准备执行您的操作....") 90 | time.sleep(5) 91 | run_time = time.strftime("%Y-%m-%d_%H%M%S", time.localtime(time.time())) 92 | logProcess(dev, run_time) 93 | while True: 94 | try: 95 | time.sleep(1) # 每1秒采集一次 96 | print("----------------数据采集-----------------") 97 | apm.pid_mem(dev, Config.package_name, 3) 98 | apm.pid_cpuRate(dev, Config.package_name, 3) 99 | #fps 测试需要打开开发者模式GPU模式 100 | apm.pid_fps(dev, Config.package_name, 3) 101 | except: 102 | break 103 | 104 | elif signal == 'n': 105 | print('用户主动放弃测试,测试结束!') 106 | else: 107 | print("测试结束,输入非法,请重新输入y or n!") 108 | 109 | #启动多线程 110 | class MonkeyTestThread(threading.Thread): 111 | def __init__(self, dev): 112 | threading.Thread.__init__(self) 113 | self.dev = dev 114 | self.thread_stop = False 115 | 116 | def run(self): 117 | time.sleep(2) 118 | start(self.dev) 119 | 120 | 121 | 122 | def create_threads_monkey(device_list): 123 | Thread_instances = [] 124 | if device_list != []: 125 | for id_instance in device_list: 126 | dev = id_instance 127 | testInstance = MonkeyTestThread(dev) 128 | Thread_instances.append(testInstance) 129 | for instance in Thread_instances: 130 | instance.start() 131 | 132 | 133 | if __name__ == '__main__': 134 | device_dir = os.path.exists(AppPerCon.info_path) 135 | if device_dir: 136 | print ("持久性目录info已存在,继续执行测试!") 137 | else: 138 | #os.mkdir(AppPerformanceConfig.info_path) # 创建持久性目录,需要在文件存在的情况下创建二级目录 139 | os.makedirs(AppPerCon.info_path) # 使用makedirs可以在文件夹不存在的情况下直接创建 140 | device_list = apm.get_device() 141 | if ad.checkDevices(): 142 | print("设备存在") 143 | create_threads_monkey(device_list) 144 | else: 145 | print("设备不存在") 146 | 147 | 148 | -------------------------------------------------------------------------------- /testCase/MonkeyTest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | import os,shutil 4 | import threading 5 | import time,datetime,subprocess 6 | 7 | from PerConfig import AppPerCon 8 | from lib.AppAdbCom import AdbDebug 9 | from lib.AppDevInfo import DeviceMsg 10 | from lib.AppMonitor import AppMoni 11 | from lib.AppOperateFile import OperateFile 12 | from lib.AppOperatePick import OperatePick 13 | from lib.AppReport import Report 14 | 15 | PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(os.path.realpath('__file__')), p)) #os.path.realpath(path) 返回path的真实路径 16 | 17 | ad = AdbDebug() 18 | apm = AppMoni() 19 | devMs = DeviceMsg() 20 | pick = OperatePick() 21 | Config = AppPerCon() 22 | 23 | #全局变量 24 | MemTestFlag = 0 25 | monkey_log='' 26 | path_log='' 27 | 28 | 29 | 30 | # 手机信息 31 | def get_phone(dev): 32 | phone_info = devMs.GetDevMsg(dev) 33 | # print phone_info 34 | app = {} 35 | app["phone_name"] = phone_info[0]["phone_name"] + "_" + phone_info[0]["phone_model"] + "_" + phone_info[0]["release"] 36 | app["rom"] = phone_info[1] 37 | app["kel"] = phone_info[2] 38 | app["pix"] = phone_info[3] 39 | return app 40 | 41 | def Create_pickle(dev, data): 42 | print("创建持久性文件...") 43 | if apm.IsIP(dev) == True: 44 | devIP = dev.split(':')[0].replace(".","") 45 | freemen = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Free_mem.pickle")#空闲状态 46 | medimen = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_mem.pickle")#中等压力 47 | fullmen = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_mem.pickle")#满压力 48 | freecpu = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Free_cpu.pickle")#空闲状态 49 | medicpu = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_cpu.pickle")#中等压力 50 | fullcpu = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_cpu.pickle")#满压力 51 | freejiff = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Free_jiff.pickle")#空闲状态 52 | medijiff = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_jiff.pickle")#中等压力 53 | fulljiff = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_jiff.pickle")#满压力 54 | medifps = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Medium_fps.pickle")#中等压力 55 | fullfps = PATH(Config.info_path + devIP + "_" + Config.package_name + "_" + "Full_fps.pickle")#满压力 56 | ''' 57 | freemenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_memTime.pickle")#空闲状态测试采样时间记录 58 | medimenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_memTime.pickle") 59 | fullmenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_memTime.pickle") 60 | freecpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_cpuTime.pickle") 61 | medicpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_cpuTime.pickle") 62 | fullcpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_cpuTime.pickle") 63 | freejiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_jiffTime.pickle") 64 | medijiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_jiffTime.pickle") 65 | fulljiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_jiffTime.pickle") 66 | medifpsTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_fpsTime.pickle") 67 | fullfpsTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_fpsTime.pickle") 68 | ''' 69 | else: 70 | freemen = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_mem.pickle")#空闲状态 71 | medimen = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_mem.pickle")#中等压力 72 | fullmen = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_mem.pickle")#满压力 73 | freecpu = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_cpu.pickle")#空闲状态 74 | medicpu = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_cpu.pickle")#中等压力 75 | fullcpu = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_cpu.pickle")#满压力 76 | freejiff = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_jiff.pickle")#空闲状态 77 | medijiff = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_jiff.pickle")#中等压力 78 | fulljiff = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_jiff.pickle")#满压力 79 | medifps = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_fps.pickle")#中等压力 80 | fullfps = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_fps.pickle")#满压力 81 | ''' 82 | freemenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_memTime.pickle")#空闲状态测试采样时间记录 83 | medimenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_memTime.pickle") 84 | fullmenTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_memTime.pickle") 85 | freecpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_cpuTime.pickle") 86 | medicpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_cpuTime.pickle") 87 | fullcpuTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_cpuTime.pickle") 88 | freejiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Free_jiffTime.pickle") 89 | medijiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_jiffTime.pickle") 90 | fulljiffTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_jiffTime.pickle") 91 | medifpsTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Medium_fpsTime.pickle") 92 | fullfpsTime = PATH(Config.info_path + dev + "_" + Config.package_name + "_" + "Full_fpsTime.pickle") 93 | ''' 94 | 95 | # time.sleep(2) 96 | OperateFile(freemen).mkdir_file() 97 | OperateFile(medimen).mkdir_file() 98 | OperateFile(fullmen).mkdir_file() 99 | OperateFile(freecpu).mkdir_file() 100 | OperateFile(medicpu).mkdir_file() 101 | OperateFile(fullcpu).mkdir_file() 102 | OperateFile(freejiff).mkdir_file() 103 | OperateFile(medijiff).mkdir_file() 104 | OperateFile(fulljiff).mkdir_file() 105 | OperateFile(medifps).mkdir_file() 106 | OperateFile(fullfps).mkdir_file() 107 | ''' 108 | OperateFile(freemenTime).mkdir_file() 109 | OperateFile(medimenTime).mkdir_file() 110 | OperateFile(fullmenTime).mkdir_file() 111 | OperateFile(freecpuTime).mkdir_file() 112 | OperateFile(medicpuTime).mkdir_file() 113 | OperateFile(fullcpuTime).mkdir_file() 114 | OperateFile(freejiffTime).mkdir_file() 115 | OperateFile(medijiffTime).mkdir_file() 116 | OperateFile(fulljiffTime).mkdir_file() 117 | OperateFile(medifpsTime).mkdir_file() 118 | OperateFile(fullfpsTime).mkdir_file() 119 | ''' 120 | OperateFile(PATH(Config.info_path + "sumInfo.pickle")).mkdir_file() # 用于记录是否已经测试完毕,里面存的是一个整数 121 | OperateFile(PATH(Config.info_path + "info.pickle")).mkdir_file() # 用于记录统计结果的信息,是[{}]的形式 122 | pick.writeSum(0, data, PATH(Config.info_path + "sumInfo.pickle")) # 初始化记录当前真实连接的设备数 123 | 124 | def unlockScreen(dev): 125 | cmd_openScreen = "-s %s shell input keyevent 224" % (dev) 126 | cmd_slide = "-s %s shell input swipe 300 500 1000 500" % (dev) 127 | ad.call_adb(cmd_openScreen) # 点亮屏幕 128 | time.sleep(0.5) 129 | ad.call_adb(cmd_slide) # 滑动解锁 130 | 131 | #log生成函数 132 | def logProcess(dev, runtime): 133 | # logcat日志 134 | logcat_log = path_log + "\\" + runtime + "logcat.log" 135 | cmd_logcat = "-s " + dev + " logcat -d > %s" % (logcat_log) 136 | ad.call_adb(cmd_logcat) 137 | print 'logcat 完成' 138 | 139 | # "导出traces文件" 140 | traces_log = path_log + "\\" + runtime + "traces.log" 141 | cmd_traces = "-s " + dev + " shell cat /data/anr/traces.txt > %s" % (traces_log) 142 | ad.call_adb(cmd_traces) 143 | print 'traces_log 完成' 144 | 145 | 146 | # monkey启动函数 147 | def monkeyStart(dev, runtime, flag): 148 | global path_log 149 | if apm.IsIP(dev) == True: 150 | devIP = dev.split(':')[0].replace(".", "") 151 | path_log = Config.log_location + '-' + devIP 152 | else: 153 | path_log = Config.log_location + '-' + dev 154 | device_dir = os.path.exists(path_log) 155 | if device_dir: 156 | print("log已存在,继续执行测试!") 157 | else: 158 | os.mkdir(path_log) 159 | if flag == 2: 160 | adb_monkey = "shell monkey -p %s -s %s %s" % (Config.package_name, Config.monkey_seed, Config.monkey_parameters_full) 161 | elif flag == 1: 162 | adb_monkey = "shell monkey -p %s -s %s %s" % (Config.package_name, Config.monkey_seed, Config.monkey_parameters_medi) 163 | global monkey_log 164 | monkey_log = path_log + "\\" + runtime + "monkey.log" 165 | cmd_monkey = "adb -s %s %s > %s" % (dev, adb_monkey, monkey_log) 166 | subprocess.Popen(cmd_monkey, shell=True) 167 | 168 | 169 | def mediMemTest(dev, app): 170 | print("--------------开始执行测试----------------") 171 | print("--------------设备:%s 场景2:中等压力下APP性能指标----------------") % dev 172 | ad.adbStopActivity(dev, Config.package_name) 173 | run_time = time.strftime("%Y-%m-%d_%H%M%S", time.localtime(time.time())) 174 | monkeyStart(dev, run_time, 1) 175 | logProcess(dev, run_time)#放在monkeystart之后作为缓冲,否则程序运行失败 176 | while True: 177 | try: 178 | with open(monkey_log, 'rb') as monkeylog: 179 | time.sleep(2) # 每2秒采集一次 180 | apm.pid_mem(dev, Config.package_name, 1) 181 | apm.pid_cpuRate(dev, Config.package_name, 1) 182 | apm.pid_fps(dev, Config.package_name, 1) 183 | if monkeylog.read().count('Monkey finished') > 0: 184 | app[dev] = {"header": get_phone(dev)} 185 | app[dev]["header"]["net"] = Config.net 186 | pick.writeInfo(app, PATH(Config.info_path + "info.pickle")) 187 | print "--------------设备:%s 场景2:中等压力下测试完成----------------" % dev 188 | break 189 | except: 190 | break 191 | 192 | def fullMemTest(dev): 193 | print("--------------开始执行测试----------------") 194 | print("--------------设备:%s 场景3:满压力下APP性能指标----------------") % dev 195 | ad.adbStopActivity(dev, Config.package_name) 196 | run_time = time.strftime("%Y-%m-%d_%H%M%S", time.localtime(time.time())) 197 | monkeyStart(dev, run_time, 2) 198 | logProcess(dev, run_time) 199 | while True: 200 | try: 201 | with open(monkey_log, 'rb') as monkeylog: 202 | time.sleep(2) # 每2秒采集一次 203 | apm.pid_mem(dev, Config.package_name, 2) 204 | apm.pid_cpuRate(dev, Config.package_name, 2) 205 | #fps测试需要事先开启手机开发者模式里的GPU显示,否则运行出错 206 | apm.pid_fps(dev, Config.package_name, 2) 207 | if monkeylog.read().count('Monkey finished') > 0: 208 | print "--------------设备:%s 场景3:满压力下测试完成----------------" % dev 209 | break 210 | except: 211 | break 212 | 213 | def start(dev): 214 | rt = os.popen('adb devices').readlines() # os.popen()执行系统命令并返回执行后的结果 215 | num = len(rt) - 2 216 | app = {} 217 | Create_pickle(dev, num) 218 | unlockScreen(dev) 219 | # 中等压力下测试 220 | mediMemTest(dev, app) 221 | print '生成测试报告......' 222 | rep = Report(dev, "Alink V2.6.17 性能测试报告", "Medium") 223 | rep.createReport(dev) 224 | print '测试报告生成完毕' 225 | 226 | #启动MONKEY多线程 227 | class MonkeyTestThread(threading.Thread): 228 | def __init__(self, dev): 229 | threading.Thread.__init__(self) 230 | self.dev = dev 231 | self.thread_stop = False 232 | 233 | def run(self): 234 | time.sleep(2) 235 | start(self.dev) 236 | 237 | 238 | 239 | def create_threads_monkey(device_list): 240 | Thread_instances = [] 241 | if device_list != []: 242 | for id_instance in device_list: 243 | dev = id_instance 244 | MontestInstance = MonkeyTestThread(dev) 245 | Thread_instances.append(MontestInstance) 246 | for instance in Thread_instances: 247 | instance.start() 248 | 249 | 250 | 251 | if __name__ == '__main__': 252 | device_dir = os.path.exists(AppPerCon.info_path) 253 | if device_dir: 254 | print ("持久性目录info已存在,继续执行测试!") 255 | else: 256 | #os.mkdir(AppPerformanceConfig.info_path) # 创建持久性目录,需要在文件存在的情况下创建二级目录 257 | os.makedirs(AppPerCon.info_path) # 使用makedirs可以在文件夹不存在的情况下直接创建 258 | device_list = apm.get_device() 259 | if ad.checkDevices(): 260 | print("设备存在") 261 | create_threads_monkey(device_list) 262 | else: 263 | print("设备不存在") 264 | 265 | 266 | -------------------------------------------------------------------------------- /testCase/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- --------------------------------------------------------------------------------