一、实现方案
1、安卓通过adb获取冷启动时长和内存
2、ios基于Instruments协议获取冷启动时长和内存,通过开源框架py-ios-device获取
3、通过循环冷启动100次,取平均冷启动时长和内存
二、实现代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: lihang
@file: startperf.py
@time: 2024/3/20 10:28
@desc:
"""
import os
import re
import subprocess
import time
from ios_device import py_ios_device
from ios_device.cli.base import InstrumentsBase
def startperf_android():
for i in range(100):
cmd_close = 'adb shell am force-stop xxxx包名'
subprocess.Popen(cmd_close, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[
0].decode("utf-8").strip()
cmd = 'adb shell am start -W xxxx包名.component.startup.main.MainActivity'(app主main页面的activity)
result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[
0].decode("utf-8").strip()
# print(result)
launchtype = result.split('\n')[2].split(':')[-1].strip()
launchtime = result.split('\n')[-3]
launchmem = getMem()
if launchtype == 'COLD':
print("第{}次安卓冷启动时长为{},启动内存为{}M".format(i + 1, launchtime, launchmem))
else:
print("当前启动为非冷启动,不统计时长/内存")
time.sleep(3)
def getMem():
pid = getPid()
cmd_mem = f'adb -s MQS0220707000474 shell dumpsys meminfo {pid}'.format(pid=pid)
output_mem = subprocess.Popen(cmd_mem, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[
0].decode("utf-8").strip()
m_total = re.search(r'TOTAL\s*(\d+)', output_mem)
totalPass = round(float(float(m_total.group(1))) / 1024, 2)
return totalPass
def getPid():
"""Get the pid corresponding to the Android package name"""
result = os.popen(f"adb -s MQS0220707000474 shell ps -ef | grep xxxx包名").readlines()
flag = len(result) > 0
try:
pid = (0, result[0].split()[1])[flag]
except Exception:
pid = None
return pid
class StartPerf_Ios:
def __init__(self, udid=None):
self.udid = udid
self.pid = None
self.launchtime = None
self.bundle_id = 'xxxx包名'
self.instb = InstrumentsBase(udid=self.udid, )
# self.channels = py_ios_device.get_channel()
# self.ios = Ios().driver(udid=self.udid)
def get_startinfo(self):
"""Get the launtchmemery and launtchtime of the app"""
self.instb.app_launch_lifecycle(bundleid=self.bundle_id, )
print(f"{self.instb.startinfo=}")
if self.instb.startinfo:
pid = self.instb.startinfo[0][0]
launtchtime = self.instb.startinfo[0][2]
self.pid, self.launchtime = pid, launtchtime
def callback(resp):
"""['memVirtualSize', 'cpuUsage', 'procStatus', 'appSleep', 'uid', 'vmPageIns', 'memRShrd','ctxSwitch',
'memCompressed', 'intWakeups', 'cpuTotalSystem', 'responsiblePID','physFootprint', 'cpuTotalUser',
'sysCallsUnix', 'memResidentSize', 'sysCallsMach','memPurgeable', 'diskBytesRead', 'machPortCount',
'__suddenTerm', '__arch', 'memRPrvt','msgSent', 'ppid', 'threadCount', 'memAnon', 'diskBytesWritten',
'pgid', 'faults','msgRecv', '__restricted', 'pid', '__sandbox']},"""
for value in resp:
if 'Processes' in value.keys():
mem = value['Processes'].get(pid)[12] / 1024 / 1024
print(f"当前冷启动时长为{launtchtime},app启动内存为{mem}M")
channel = py_ios_device.start_get_system(callback=callback)
time.sleep(1)
py_ios_device.stop_get_system(channel)
# channel.stop()
else:
print("未获取到冷启动数据📊")
def kill_app(self):
"""Kill the app by pid"""
pid = str(self.instb.get_pid(self.bundle_id))
self.instb.kill_app(pid) if pid else print("未获取到app的pid")
def close(self):
self.instb.lockdown.close()
self.instb.instruments.stop()
self.instb.instruments_rcp.stop()
if __name__ == '__main__':
startperf_android()
for i in range(3):
print("当前第{}次ios冷启动".format(i + 1))
spi = StartPerf_Ios(udid='00008101-001864910A40001E')
spi.kill_app()
spi.get_startinfo()