本篇文章是繼《基礎工作》後,我們對性能測試過程中數據的一個獲取。一改我們常用的定時獲取數據的方式,我覺得要想更好的對應用進行性能測試,我們不止要知道何時性能數據會升高,還要知道什麼操作會使性能數據上升,所以我將會在每次點擊之後觸發一次性能數據的獲取,之後可以日誌系統對操作進行定位。那麼現在我將會獲取“內存”“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性能測試。