Skip to content

Commit 07c2a80

Browse files
committed
APP流量使用情况、电量消耗情况和内存数据获取分析的脚本
1 parent 931af71 commit 07c2a80

File tree

9 files changed

+35997
-3
lines changed

9 files changed

+35997
-3
lines changed

README.md

Lines changed: 197 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# AndroidTestByPython
2-
Android APP使用Python进行性能测试
2+
3+
Android APP使用Python进行性能测试以及测试框架
4+
5+
## APP性能测试
36

47
### APP启动时间
58

@@ -32,7 +35,7 @@ adb shell am force-stop package
3235
- 停止App命令
3336

3437
```shell
35-
// 模拟点击back键
38+
# 模拟点击back键
3639
adb shell input keyevent 3
3740
```
3841

@@ -145,5 +148,197 @@ adb shell dumpsys cpuinfo | grep packagename
145148

146149

147150

151+
### 流量
152+
153+
##### 命令
154+
155+
- 获取进程ID指令
156+
157+
```shell
158+
# windows下用findstr代替grep,否则拿不到结果
159+
adb shell ps | grep packagename
160+
```
161+
162+
- 获取进程ID的流量指令
163+
164+
```shell
165+
# pid就是上面指令获取的进程ID
166+
adb shell cat /proc/pid/net/dev
167+
```
168+
169+
##### 脚本实现
170+
171+
```python
172+
# 单次测试过程
173+
def test_process(self):
174+
# 执行获取进程ID的指令 window 下用findstr,Mac下用grep
175+
cmd = "adb shell ps | findstr org.chromium.webview_shell"
176+
result = os.popen(cmd)
177+
# 获取进程ID
178+
pid = result.readlines()[0].split(" ")[5]
179+
180+
# 获取进程ID使用的流量
181+
traffic = os.popen("adb shell cat /proc/" + pid + "/net/dev")
182+
for line in traffic:
183+
# 第一个网卡的数据
184+
if "eth0" in line:
185+
# 将所有空行换成#
186+
line = "#".join(line.split())
187+
# 然后按#号进行拆分,获取到收到和发出的流量值
188+
receive = line.split("#")[1]
189+
transmit = line.split("#")[9]
190+
# 第二个网卡的数据
191+
elif "eth1" in line:
192+
line2 = "#".join(line.split())
193+
# 然后按#号进行拆分,获取到收到和发出的流量值
194+
receive2 = line2.split("#")[1]
195+
transmit2 = line2.split("#")[9]
196+
197+
# 计算所有流量之和
198+
all_traffic = string.atoi(receive) + string.atoi(transmit) + string.atoi(receive2) + string.atoi(transmit2)
199+
# 按KB计算流量值
200+
all_traffic = all_traffic / 1024
201+
# 获取当前时间
202+
current_time = self.get_current_time()
203+
# 将获取到的数据存到数组中
204+
self.all_data.append((current_time, all_traffic))
205+
```
206+
207+
运行后的结果:
208+
209+
```
210+
timestamp,traffic
211+
2020-03-13 11:35:36,136535
212+
2020-03-13 11:35:41,136791
213+
2020-03-13 11:35:47,166458
214+
2020-03-13 11:35:52,264812
215+
2020-03-13 11:35:57,380940
216+
```
217+
218+
##### 数据分析
219+
220+
用最后一条流量值减去第一条流量值,得到本次测试运行时消耗掉的流量,然后和以往版本以及竞品进行对比,然后发现流量消耗的问题。
221+
222+
### 电量
223+
224+
##### 获取电量
225+
226+
```shell
227+
adb shell dumpsys battery
228+
```
229+
230+
但是手机连接USB之后,会进入充电状态,测试电量需要在非充电的情况下,所以可以使用下面的命令切换充电状态
231+
232+
```shell
233+
# 切换到非充电状态,status = 2 代表充电,非2就是非充电
234+
adb shell dumpsys battery set status 1
235+
```
236+
237+
##### 脚本实现
238+
239+
```python
240+
# 单次测试过程
241+
def test_process(self):
242+
cmd = "adb shell dumpsys battery"
243+
result = os.popen(cmd)
244+
245+
for line in result:
246+
if "level" in line:
247+
power = line.split(":")[1]
248+
249+
# 获取当前时间
250+
current_time = self.get_current_time()
251+
# 将获取到的数据存到数组中
252+
self.all_data.append((current_time, power))
253+
254+
# 多次执行测试过程
255+
def run(self):
256+
cmd = "adb shell dumpsys battery set status 1"
257+
os.popen(cmd)
258+
while self.counter > 0:
259+
self.test_process()
260+
self.counter = self.counter - 1
261+
# 每5秒采集一次数据, 真实测试场景建议在0.5-1小时
262+
time.sleep(5)
263+
```
264+
265+
### 内存
266+
267+
##### 获取内存
268+
269+
```shell
270+
adb shell top
271+
# -d 刷新频率, 1 代表多久刷新一次,单位秒
272+
adb shell top -d 1
273+
# 输出到指定文件,测试完终止命令就可以分析指定文件
274+
adb shell top -d 1 > meminfo
275+
# 筛选指定包名,进行分析, windows上可以用type代替cat, findstr代替grep
276+
cat meminfo | grep packagename
277+
```
278+
279+
> VSS - Virtual Set Size 虚拟消耗内存
280+
>
281+
> RSS - Resident Set Size 实际使用物理内存
282+
283+
##### 脚本实现
284+
285+
脚本负责对命令行中测试后生成的meminfo文件进行分析,然后生成分析数据到csv文件,然后可以利用该csv文件进行图表绘制,内存数据获取时,建议测试时间长一点,方便分析使用过程中内存数据是否稳定,vss和rss分别分析。
286+
287+
```python
288+
# 控制类
289+
class Controller(object):
290+
def __init__(self):
291+
# 定义收集数据的数组
292+
self.all_data = [("id", "vss", "rss")]
293+
294+
# 分析数据
295+
def analyze_data(self):
296+
content = self.read_file()
297+
i = 0
298+
for line in content:
299+
if "org.chromium.webview_shell" in line:
300+
print line
301+
line = "#".join(line.split())
302+
# 角标7和8不是固定的,要看你生成的meminfo文件里vss和rss出现的位置来确定
303+
vss = line.split("#")[7].strip("K")
304+
rss = line.split("#")[8].strip("K")
305+
306+
# 将获取到的数据存到数组中
307+
self.all_data.append((i, vss, rss))
308+
i = i + 1
309+
310+
# 读取数据文件
311+
@staticmethod
312+
def read_file():
313+
mem_info = file("meminfo", "r")
314+
content = mem_info.readlines()
315+
mem_info.close()
316+
return content
317+
318+
# 数据的存储
319+
def save_data_to_csv(self):
320+
csv_file = file('meminfo.csv', 'wb')
321+
writer = csv.writer(csv_file)
322+
writer.writerows(self.all_data)
323+
csv_file.close()
324+
325+
326+
if __name__ == '__main__':
327+
controller = Controller()
328+
controller.analyze_data()
329+
controller.save_data_to_csv()
330+
```
331+
332+
### FPS&过度渲染
333+
334+
##### FPS
335+
336+
frames per second - 每秒的帧数
337+
338+
> Android中每一帧的绘制时间大于16秒,则可能会产生卡顿的现象,可以借助设置-开发者选项-GPU呈现模式分析,选择在屏幕上呈现为条形图,屏幕中横着的绿线就是16ms的基准线,高于绿线的条形图就是发生卡顿的帧
339+
340+
##### 过度渲染
148341

342+
描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次
149343

344+
> 可以借助设置-开发者选项-调试GPU过度绘制-选择显示过度绘制区域,从最优到最差:蓝,绿,淡红,红。

launchTime/cpuStatus.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ def run(self):
2828
while self.counter > 0:
2929
self.test_process()
3030
self.counter = self.counter - 1
31+
# 每3秒采集一次数据
3132
time.sleep(3)
3233

3334
# 获取当前的时间戳
34-
def get_current_time(self):
35+
@staticmethod
36+
def get_current_time():
3537
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
3638
return current_time
3739

launchTime/mem.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# encoding:utf-8
2+
import csv
3+
4+
# 控制类
5+
class Controller(object):
6+
def __init__(self):
7+
# 定义收集数据的数组
8+
self.all_data = [("id", "vss", "rss")]
9+
10+
# 分析数据
11+
def analyze_data(self):
12+
content = self.read_file()
13+
i = 0
14+
for line in content:
15+
if "org.chromium.webview_shell" in line:
16+
print line
17+
line = "#".join(line.split())
18+
vss = line.split("#")[7].strip("K")
19+
rss = line.split("#")[8].strip("K")
20+
21+
# 将获取到的数据存到数组中
22+
self.all_data.append((i, vss, rss))
23+
i = i + 1
24+
25+
# 读取数据文件
26+
@staticmethod
27+
def read_file():
28+
mem_info = file("meminfo", "r")
29+
content = mem_info.readlines()
30+
mem_info.close()
31+
return content
32+
33+
# 数据的存储
34+
def save_data_to_csv(self):
35+
csv_file = file('meminfo.csv', 'wb')
36+
writer = csv.writer(csv_file)
37+
writer.writerows(self.all_data)
38+
csv_file.close()
39+
40+
41+
if __name__ == '__main__':
42+
controller = Controller()
43+
controller.analyze_data()
44+
controller.save_data_to_csv()

0 commit comments

Comments
 (0)