本篇文章是继《基础工作》后,我们对性能测试过程中数据的一个获取。一改我们常用的定时获取数据的方式,我觉得要想更好的对应用进行性能测试,我们不止要知道何时性能数据会升高,还要知道什么操作会使性能数据上升,所以我将会在每次点击之后触发一次性能数据的获取,之后可以日志系统对操作进行定位。那么现在我将会获取“内存”“CPU”数据进行获取,至于流量及电量本篇文章暂时不进行说明。
一,内存数据
我这里将使用系统的memoryInfo 进行数据的获取,首先我们要获取一个进程的性能数据,首先我们要获取到这个进程的PID,也就是进程编号,由于进行编号是不固定的,所以为保证准确行,我们要通过packageName来保证PID的准确性:
private int getPid(){
int mPID = 0;
//获取全部的PID,通过遍历对比PackageName
List<AndroidAppProcess> processes = AndroidProcesses.getRunningAppProcesses();
for(AndroidAppProcess appProcess : processes){
if(appProcess.name.equals(PackageName)){
mPID=appProcess.pid;
}
}
return mPID;
}
获取到PID后我们要进行性能数据的获取,首先我们先简单的了解一下我们可以获取到哪些新年数据:
dalvik:是指dalvik所使用的内存。
native:是被native堆使用的内存。应该指使用C\C++在堆上分配的内存。
other:是指除dalvik和native使用的内存。比如分配在栈上的内存。
private:是指私有的。非共享的。
share:是指共享的内存。
Pss:它是把共享内存根据一定比例分摊到共享它的各个进程来计算所得到进程使用内存。
PrivateDirty:它是指非共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使你的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。
SharedDirty:参照PrivateDirty我认为它应该是指共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使所有共享它的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。
为了数据返回的方便性我们将所有的数据都装在一个list里面,当然你们愿意的话也可是使用元组。
private List<Integer> naviStatus() {
Debug.MemoryInfo[] memoryInfo = activityManager.getProcessMemoryInfo(new int[]{getPid()});
String androidVersion = Build.VERSION.RELEASE;
List<Integer> Memorys=new ArrayList<>() ;
int sdkVersion = Build.VERSION.SDK_INT;
Memorys.add(memoryInfo[0].dalvikPss);
Memorys.add(memoryInfo[0].nativePss);
Memorys.add(memoryInfo[0].otherPss);
Memorys.add(memoryInfo[0].dalvikPrivateDirty);
Memorys.add(memoryInfo[0].dalvikSharedDirty);
Memorys.add(memoryInfo[0].nativePrivateDirty);
Memorys.add(memoryInfo[0].nativeSharedDirty);
Memorys.add(memoryInfo[0].otherPrivateDirty);
Memorys.add(memoryInfo[0].otherSharedDirty);
return Memorys;
}
那么现在内存数据就获取完成了,当然如果要将这些数据进行计算也是可以的,至于怎么用就是下一步的事情了。
二,CPU
首先我们了解一下获取单进程cpu的原理,我们要对/proc/[pid]/stat文件进行分析:先通过adb命令查看一下文件的内容:adb shell cat /proc/"pid"/stat 其中“pid”是指进程的PID 获取的信息我们截个图。
分析如下:
5832 <ncent.wecarnavi> S 396 395 0 0 -1 1077936448 757469 1051 165 0 7796 1229 0 1 20 0 100 0 1925666 1934348288 53203
在对图片中的数据进行解析
1.pid=5832进程(包括轻量级进程,即线程)号
2.comm=ncent.wecarnavi 应用程序或命令的名字
3.task_state=S 任务的状态,R:runnign, S:sleeping , D:disk sleep, T: stopped, T:tracing stop,Z:zombie, X:dead
4.ppid=396父进程ID
5.pgid=395线程组号
6.sid=0c该任务所在的会话组ID
7.tty_nr=0(pts/3) 该任务的tty终端的设备号,INT(34817/256)=主设备号,(34817-主设备号)=次设备号
8.tty_pgrp=-1终端的进程组号,当前运行在该任务所在终端的前台任务(包括shell 应用程序)的PID。
9.task->flags=1077936448 进程标志位,查看该任务的特性
10.min_flt=757469 该任务不需要从硬盘拷数据而发生的缺页(次缺页)的次数
11.cmin_flt=1051累计的该任务的所有的waited-for进程曾经发生的次缺页的次数目
12.maj_flt=165该任务需要从硬盘拷数据而发生的缺页(主缺页)的次数
13.cmaj_flt=0 累计的该任务的所有的waited-for进程曾经发生的主缺页的次数目
14.utime=7796该任务在用户态运行的时间,单位为jiffies
15.stime=1229该任务在核心态运行的时间,单位为jiffies
16.cutime=0 累计的该任务的所有的waited-for进程曾经在用户态运行的时间,单位为jiffies
17.cstime=1 累计的该任务的所有的waited-for进程曾经在核心态运行的时间,单位为jiffies
18.priority=20任务的动态优先级
19.nice=0 任务的静态优先级
20.num_threads=100 该任务所在的线程组里线程的个数
21.it_real_value=0 由于计时间隔导致的下一个 SIGALRM 发送进程的时延,以 jiffy 为单位.
22.start_time=1925666 该任务启动的时间,单位为jiffies
23.vsize=1934348288(page) 该任务的虚拟地址空间大小
24.rss=53203(page) 该任务当前驻留物理地址空间的大小
以下只解释对我们计算Cpu使用率有用相关参数(第 14-17位)
参数 | 解释 |
pid=5832 | 进程号 |
utime=7796 | 该任务在用户态运行的时间,单位为jiffies |
stime=1229 | 该任务在核心态运行的时间,单位为jiffies |
cutime=0 | 所有已死线程在用户态运行的时间,单位为jiffies |
cstime=1 | 所有已死在核心态运行的时间,单位为jiffies |
进程的总Cpu时间processCpuTime = utime + stime + cutime + cstime,该值包括其所有线程的cpu时间。
public long getAppCpuTime() { // 获取应用占用的CPU时间
String[] cpuInfos = null;
try
{
int pid = getPid();
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/" + pid + "/stat")), 1000);
String load = reader.readLine();
reader.close();
cpuInfos = load.split(" ");
}
catch (IOException ex)
{
ex.printStackTrace();
}
long processCpuTime = Long.parseLong(cpuInfos[13])
+ Long.parseLong(cpuInfos[14]) + Long.parseLong(cpuInfos[15])
+ Long.parseLong(cpuInfos[16]);
return processCpuTime;
}
获取到了进程使用CPU总时间后,我们需要考虑如何计算:进程Cpu使用率 那么我们需要三步走:
1.采样两个足够短的时间间隔的cpu快照与进程快照,
1.1每一个cpu快照均为(user、nice、system、idle、iowait、irq、softirq、stealstolen、guest)的9元组;
1.2每一个进程快照均为 (utime、stime、cutime、cstime)的4元组;
2.分别根据(进程的总Cpu时间,总的CPU时间)计算出两个时刻的总的cpu时间与进程的cpu时间,分别记作:totalCpuTime1、totalCpuTime2、processCpuTime1、processCpuTime2
3.计算该进程的cpu使用率pcpu = 100*( processCpuTime2 – processCpuTime1) / (totalCpuTime2 – totalCpuTime1) (按100%计算,如果是多核情况下还需乘以cpu的个数);
下面我将对总的CPU时间进行获取及计算:首先我们需要解析proc/sta。 我们先通过adb命令查看一下文件的内容:adb shell cat /proc/stat 获取的信息我们截个图。
cpu 212510 10540 132215 399620 3781 0 18 0 0 0
在对图片中的数据进行解析
1.(cpu ) :是cpu的名称
2. (212510)user : 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies)不包含nice值为负进程。1 jiffies=0.01秒
3. (10540 )nice :从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
4.(132215)system : 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
5.(399620) idle: 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
6.(3781) iowait: 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies)
7.(0) irq :从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
8.(18) softirq: 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)
9.(0) stealstolen: 从系统启动开始累积到当前时刻,在虚拟环境运行时花费在其他操作系统的时间
10.(0) guest: 从系统启动开始累积到当前时刻,在Linux内核控制下的操作系统虚拟cpu花费的时间。
11.(0) guest_nice: 从系统启动开始累积到当前时刻,在Linux内核控制下的操作系统虚拟cpu花费在nice进程上的时间。
总的CPU时间 cpu_time = user + system + nice + idle + iowait + irq + softirq
public static long getTotalCpuTime() { // 获取系统总CPU使用时间
String[] cpuInfos = null;
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/stat")), 1000);
String load = reader.readLine();
reader.close();
cpuInfos = load.split(" ");
}
catch (IOException ex)
{
ex.printStackTrace();
}
long cpu_time = Long.parseLong(cpuInfos[2])
+ Long.parseLong(cpuInfos[3]) + Long.parseLong(cpuInfos[4])
+ Long.parseLong(cpuInfos[6]) + Long.parseLong(cpuInfos[5])
+ Long.parseLong(cpuInfos[7]) + Long.parseLong(cpuInfos[8]);
return cpu_time;
}
现在系统总CPU使用时间和应用占用的CPU时间都已经获取到了现在就可以进行“进程Cpu使用率”的计算了:
public float getProcessCpuRate()
{
float totalCpuTime1 = getTotalCpuTime();
float processCpuTime1 = getAppCpuTime();
try {
Thread.sleep(360);
} catch (InterruptedException e) {
e.printStackTrace();
}
float totalCpuTime2 = getTotalCpuTime();
float processCpuTime2 = getAppCpuTime();
float cpuRate = 100 * (processCpuTime2 - processCpuTime1)
/ (totalCpuTime2 - totalCpuTime1);
return cpuRate;
}
截止现在,内存+CPU数据就完全获取到了,以后的工作就是数据的使用及保存了,下篇文章我将对日志还有性能数据的保存进行整理,来逐步完善模拟Monkey性能测试。