APP性能測試中如何獲取CPU和PSS數據

本人在最近手機APP性能數據的過程當中,又從新看了一些Android的內存相關知識,對以前寫過的一篇APP性能的線程類的方法作了優化,總得來講,就是增長了PSS數據和增長了數據獲取以後的數據整理工做。java

獲取PSS的方法原理是經過adb shell dumpsys命令獲取到的,以前放棄了這個方法,由於內存數據太細分了,後來發現細分的更準確。這裏沒有統計Native Heap和Dalvik Heap,感受統計數據的話並無多大的必要。對這塊也不是很是瞭解若是有不對的地方,還請指正。sql

方法以下:shell

/**
	 * 獲取應用信息 利用Android系統dumpsys命令獲取
	 * 命令能統計到java虛擬的堆內存和棧內存的使用狀況
	 * 
	 * @return 返回內存佔用
	 */
	public int getMemResult() {
		String cmd1 = Common.ADB_PATH + "adb shell dumpsys meminfo " + package_name;
		int mem_result = 0;
		try {
			Process p = Runtime.getRuntime().exec(cmd1);// 經過runtime類執行cmd命令
			// 正確輸出流
			InputStream input = p.getInputStream();// 建立並實例化輸入字節流
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String line = "";
			while ((line = reader.readLine()) != null) {// 循環讀取
				if (line.startsWith("        TOTAL")) {
					mem_result = getMemInfo(line);
				}
			}
			reader.close();// 此處reader依賴於input,應先關閉
			input.close();
			// 錯誤輸出流
			InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流
			BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String eline = "";
			while ((eline = errorReader.readLine()) != null) {// 循環讀取
				System.out.println(eline);// 輸出
			}
			errorReader.close();// 此處有依賴關係,先關閉errorReader
			errorInput.close();
		} catch (IOException e) {
			output("執行" + cmd1 + "失敗!", e);
		}
		return mem_result;
	}

下面是增長的統計方法,主要是在每次新建進程的時候都會記錄一個mark,統計方法寫在結束線程的方法裏:數據庫

public void stopRecord() {
		AppLocalMySql.getInstance().ClearUpPerformaceData(mark);//整理數據
		PerformanceThread.key = false;//結束線程
	}
/**
	 * 整理一次性能數據收集
	 * 
	 * @param mark
	 *            統計mark
	 */
	public void ClearUpPerformaceData(int mark) {
		getConnection();
		int cpu = 0, pss = 0, rss = 0, vss = 0, total = 0;
		String device = null, packages = null, test_name = null;
		try {
			if (!connection.isClosed()) {
				outputSuccess();
				Statement statement = connection.createStatement();
				String sql = "SELECT AVG(cpu),AVG(pss),AVG(rss),AVG(vss),COUNT(*),device,package,test_name FROM app_result WHERE mark = "
						+ mark;
				ResultSet resultSet = statement.executeQuery(sql);
				while (resultSet.next()) {
					cpu = resultSet.getInt(1);
					pss = resultSet.getInt(2);
					rss = resultSet.getInt(3);
					vss = resultSet.getInt(4);
					total = resultSet.getInt(5);
					device = resultSet.getString("device");
					packages = resultSet.getString("package");
					test_name = resultSet.getString("test_name");
				}
				String sql2 = "INSERT INTO app_report (mark,test_name,package,device,cpu,pss,rss,vss,total) VALUES ("
						+ mark + ",'" + test_name + "','" + packages + "','" + device + "'," + cpu + "," + pss + ","
						+ rss + "," + vss + "," + total + ")";
				statement.executeUpdate(sql2);
				statement.close();
				connection.close();
			}
		} catch (SQLException e) {
			output("統計方法出錯!", e);
		}
	}

多線程實現:編程

package source;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
 * @author ··-·塵
 * @E-mail:Fhaohaizi@163.com
 * @version 建立時間:2017年8月23日 下午2:56:22
 * @alter 修改時間:2017年8月24日 10:02:19 類說明:測試內存和cpu信息
 */
public class PerformanceThread extends Thread {
	public int mark = Common.getInstance().getMark();
	public static boolean key = true;
	public static String device_id;
	public static String package_name;
	public static String test_name;
	// 建立實例
	private static PerformanceThread performanceTest;
 
	@Override
	public void run() {
		while (key) {// 循環執行該方法
			try {
				sleep(15 * 1000);// 線程休眠
			} catch (InterruptedException e) {
				e.printStackTrace();// 打印異常
			}
			getCpuAndMemDate();// 執行手機數據的方法
		}
	}
 
	public static PerformanceThread getInstance() {
		if (performanceTest == null) {
			performanceTest = new PerformanceThread();
		}
		return performanceTest;
	}
 
	public PerformanceThread() {
		getDevicesId();
		PerformanceThread.package_name = Common.PAGEKAGE;
		output("歡迎使用手機性能監控線程!");
	}
 
	public PerformanceThread(String package_name) {
		getDevicesId();
		PerformanceThread.package_name = package_name;
		output("歡迎使用手機性能監控線程!");
	}
	
	public PerformanceThread(String testname, String package_name) {
		getDevicesId();
		PerformanceThread.package_name = package_name;
		PerformanceThread.test_name = testname;
		output("歡迎使用手機性能監控線程!");
	}
	
	/**
	 * 結束線程方法
	 */
	public void stopRecord() {
		AppLocalMySql.getInstance().ClearUpPerformaceData(mark);
		PerformanceThread.key = false;
	}
	/**
	 * 獲取devicesID
	 */
	public void getDevicesId() {
		String cmd = "adb devices";
		String OSname = System.getProperty("os.name");
		try {
			Process p = null;
			if (OSname.contains("Mac")) {
				p = Runtime.getRuntime().exec(Common.ADB_PATH + cmd);
			} else {
				p = Runtime.getRuntime().exec("cmd /c " + cmd);
			}
			// 正確輸出流
			InputStream input = p.getInputStream();// 建立並實例化輸入字節流
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String line = "";
			while ((line = reader.readLine()) != null) {// 循環讀取
				if (line.contains("device")) {
					PerformanceThread.device_id = line.replaceAll("device", "");
				}
				// System.out.println(line);// 輸出
			}
			reader.close();// 此處reader依賴於input,應先關閉
			input.close();
		} catch (IOException e) {
			output("執行" + cmd + "失敗!");
			e.printStackTrace();
		}
	}
 
	/**
	 * 獲取cpu和mem數據,此方法用的是top命令
	 */
	public void getCpuAndMemDate() {
		int pss = getMemResult();// 獲取內存數據
		int[] result = getPerformanceResult();// 獲取數據
		int cpu_result = result[0];// 獲取cpu
		int vss = result[1];// 獲取虛擬內存數據
		int rss = result[2];// 獲取物理內存數據
		output("CPU:" + cpu_result, "VSS:" + vss, "RSS:" + rss, "PSS:" + pss);
		AppLocalMySql.getInstance().saveMemAndCpuResult(mark, package_name, device_id, cpu_result, vss, rss, pss,
				test_name);// 寫入數據庫
	}
 
	/**
	 * 獲取統計結果 利用Linux系統top命令 -m表示個數,-n表示獲取次數此處寫爲1
	 * 
	 * @return 返回int數組,包含rss,vss,cpu百分比
	 */
	public int[] getPerformanceResult() {
		String cmd = Common.ADB_PATH + "adb shell top -m 8 -n 1";
		int cpu_result = 0, vss = 0, rss = 0;
		try {
			Process p = Runtime.getRuntime().exec(cmd);// 經過runtime類執行cmd命令
			// 正確輸出流
			InputStream input = p.getInputStream();// 建立並實例化輸入字節流
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String line = "";
			while ((line = reader.readLine()) != null) {// 循環讀取
				if (line.contains(package_name)) {// 獲取行
					cpu_result = getCpuDate(line);
					vss = getVss(line);
					rss = getRss(line);
				}
			}
			reader.close();// 此處reader依賴於input,應先關閉
			input.close();// 關閉流
			// 錯誤輸出流
			InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流
			BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String eline = "";
			while ((eline = errorReader.readLine()) != null) {// 循環讀取
				System.out.println(eline);// 輸出
			}
			errorReader.close();// 此處有依賴關係,先關閉errorReader
			errorInput.close();// 關閉流
		} catch (IOException e) {
			output("執行" + cmd + "失敗!");
			e.printStackTrace();
		}
		int[] result = { cpu_result, vss, rss };// 新建數組保存數據
		return result;// 返回數組
	}
 
	/**
	 * 獲取應用信息 利用Android系統dumpsys命令獲取 命令能統計到java虛擬的堆內存和棧內存的使用狀況
	 * 
	 * @return 返回內存佔用
	 */
	public int getMemResult() {
		String cmd1 = Common.ADB_PATH + "adb shell dumpsys meminfo " + package_name;
		int mem_result = 0;
		try {
			Process p = Runtime.getRuntime().exec(cmd1);// 經過runtime類執行cmd命令
			// 正確輸出流
			InputStream input = p.getInputStream();// 建立並實例化輸入字節流
			BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String line = "";
			while ((line = reader.readLine()) != null) {// 循環讀取
				if (line.startsWith("        TOTAL")) {
					mem_result = getMemInfo(line);
				}
			}
			reader.close();// 此處reader依賴於input,應先關閉
			input.close();
			// 錯誤輸出流
			InputStream errorInput = p.getErrorStream();// 建立並實例化輸入字節流
			BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先經過inputstreamreader進行流轉化,在實例化bufferedreader,接收內容
			String eline = "";
			while ((eline = errorReader.readLine()) != null) {// 循環讀取
				System.out.println(eline);// 輸出
			}
			errorReader.close();// 此處有依賴關係,先關閉errorReader
			errorInput.close();
		} catch (IOException e) {
			output("執行" + cmd1 + "失敗!", e);
		}
		return mem_result;
	}
 
	/**
	 * 獲取內存信息
	 * 
	 * @param info
	 *            截取到的APP信息
	 * @return 返回內存蠶蛹
	 */
	public int getMemInfo(String info) {
		int result = 0;
		Pattern r = Pattern.compile(" [0-9]+ ");
		Matcher m = r.matcher(info);
		if (m.find()) {
			// output(m.group());
			result = changeStringToInt(m.group().trim());
		}
		return result;
	}
 
	/**
	 * 獲取cpu運行信息
	 * 
	 * @param info
	 *            截取到的APP信息
	 * @return 返回CPU佔用率,採起double數據格式
	 */
	public double getCpuInfo(String info) {
		String percent = info.substring(0, info.indexOf("%"));
		double result = changeStringToDouble(percent.trim());
		return result;
	}
 
	/**
	 * 獲取cpu運行信息
	 * 
	 * @param info
	 *            截取到的APP信息
	 * @return 返回CPU佔用率,採起int數據格式
	 */
	public int getCpuDate(String info) {
		Pattern pattern = Pattern.compile(" [0-9]*%");
		Matcher matcher = pattern.matcher(info);
		matcher.find();
		String date = matcher.group().trim();
		return changeStringToInt(date.substring(0, date.length() - 1));
	}
 
	public int getVss(String info) {
		Pattern pattern = Pattern.compile(" [0-9]+K");
		Matcher matcher = pattern.matcher(info);
		matcher.find();
		String date = matcher.group().trim();
		return changeStringToInt(date.substring(0, date.length() - 1));
	}
 
	public int getRss(String info) {
		Pattern pattern = Pattern.compile("K +[0-9]+K");
		Matcher matcher = pattern.matcher(info);
		matcher.find();
		String date = matcher.group().substring(1, matcher.group().length() - 1);
		return changeStringToInt(date.trim());
	}
 
	// 把string類型轉化爲double
	public Double changeStringToDouble(String text) {
		// return Integer.parseInt(text);
		return Double.valueOf(text);
	}
 
	// 把string類型轉化爲int
	public int changeStringToInt(String text) {
		// return Integer.parseInt(text);
		return Integer.valueOf(text);
	}
 
	public void output(String text) {// 明顯輸出
		System.out.println(text);
	}
 
	public void output(Object... object) {
		if (object.length == 1) {
			output(object[0].toString());
			return;
		}
		for (int i = 0; i < object.length; i++) {
			System.out.println("第" + (i + 1) + "個:" + object[i]);
		}
	}
}

往期文章精選

  1. java一行代碼打印心形
  2. Linux性能監控軟件netdata中文漢化版
  3. 接口測試代碼覆蓋率(jacoco)方案分享
  4. 性能測試框架
  5. 如何在Linux命令行界面愉快進行性能測試
  6. 圖解HTTP腦圖
  7. 寫給全部人的編程思惟
  8. 測試之JVM命令腦圖
  9. 將json數據格式化輸出到控制檯
  10. 如何測試機率型業務接口
  11. 「雙花」BUG的測試分享

公衆號地圖 ☢️ 一塊兒來~FunTester

相關文章
相關標籤/搜索