该方案旨在解决批量跑FreeSDK压力测试脚本的同时自动监控每个压测方法CPU、内存信息并存到指定文件中的问题,替换原先人工观察CPU、内存再做记录的繁琐工作,给予测试工作提供更大的方便。
1.计算CPU的占用率:
CPU占用率:指进程在一个时间段内消耗的CPU时间与该时间段长度的比值。
所以的CPU的计算公式如下:
T:某个时间段(就是要计算这个时间段的CPU使用率)
W:在这个时间段中CPU处于工作状态的时间
I:在这个时间段中CPU处于空闲状态的时间
CPU%=W/T*100% 或
CPU%=(T-I)/T*100%
CPU的时间分为用户态和内核态即userTime和kernelTime。其中还有空闲态idleTime,,但是当CPU在空闲状态时,kernelTime包含了idleTime。所以一段时间内CPU的总时间SystemTime=kernelTime+userTime,CPU的工作时间为BusyTime=kernelTime+userTime-idleTime。
CPU%=BusyTime/SystemTime。
获取CPU系统的占用率即获取windows平台各个CPU的时间状态并计算。
2.代码操作流程:
通过Windows的wmic命令下读取进程的CPU各个状态(注:通过wmic命令获取的进程的是系统的进程,而不是单独的javaw.exe进程),具体操作如下图:
可以打开Perfmon.exe性能监视器观察到,CPU占用率先逐渐升高,再平稳一段时间,最后逐渐下降。
1. 在上升期,CPU上升到正常值后由于算法第一帧的原因,会有一小段持续升高,所以在上升期过滤的时间比下降期过滤的时间多。
2. 过滤掉上升期的时间后即开启一个线程,读取CPU的kernelTime,userTime,idleTime。读取一次后给该线程加锁进入等待。
3. 在过滤下降期时间前再开启一个线程,释放第一个线程的锁,使第一个线程再次读取过滤前的CPUkernelTime,userTime,idleTime各个时间并计算。计算公式为:CPU占用率= (BusyTime(第二次读取)-BusyTime(第一次读取))/(SystemTime(第二次读取)-SystemTime(第一次读取))。计算出的CPU占用率即开启第一个线程后中间等待时间的CPU占用率。
4. 由于无法获取单独的Javaw.exe进程的CPU占用率,只能获取系统的CPU占用率,图中红色部分为该系统不运行Javaw.exe进程时的CPU占用,所以最后CPU占用率应该再减去其他进程的CPU占用率。(注:以该方式跑批量压测方法时不能运行浏览电脑任何软件或网页,否则其他进程的CPU占用会大幅升高影响结果)
具体代码
public class JavaInformations {
public static final double BENCHMARK_ZERO_VALUE = Math.pow(10, -6);
private static final int CPUTIME = 30;
private static final int PERCENT = 100;
private static final int FAULTLENGTH = 10;
static double[] c0;
static double[] c1;
public static double CPU=0.0;
public static boolean flag=false;
static List<Double> nums=new ArrayList<Double>();
public static double avg=0;
static double amount=0;
static int i=0;
static String procCmd=System
.getenv("windir") + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,KernelModeTime,ReadOperationCount,"
+ "ThreadCount,UserModeTime,WriteOperationCount";
static ThreadCPUstart mt=new ThreadCPUstart();
static ThreadCPUstop ms=new ThreadCPUstop();
static ThreadMemory mm=new ThreadMemory();
public static void ThreadStart() {
ThreadCPUstart mt=new ThreadCPUstart();
mt.start();
}
public static void ThreadStop() {
ThreadCPUstop ms=new ThreadCPUstop();
ms.start();
}
public static class ThreadMemory extends Thread{
public void run() {
try {
while(true) {
Thread.sleep(2000);
amount=GetMemory.getMemoryRate()+amount;
i++;
}
}catch(Exception e) {e.printStackTrace();}
}
}
// 以下部分属于详细信息部分
public static class ThreadCPUstart extends Thread{
public void run() {
try {
// 取进程信息
synchronized (mt) {
getCpuRatioForWindowsBeforeRun();
mt.wait();
avg=GetMemory.getMemoryRate();
getCpuRatioForWindowsAfterRun();
mt.stop();
ms.stop();
}
} catch (Exception e) {
System.out.println("cannot load monitor info: cpu ratio in windows"+e);
}
}
}
public static class ThreadCPUstop extends Thread{
public void run() {
try {
synchronized (mt) {
mt.notify();
}
}catch(Exception e) {e.printStackTrace();}
}
}
public static void getCpuRatioForWindowsBeforeRun() {
// 取进程信息
try {
// Process pro=Runtime.getRuntime().exec(procCmd);
// pro.getOutputStream();
c0 = readCpu(Runtime.getRuntime().exec(procCmd));
}catch(Exception e) {e.printStackTrace();}
}
public static double getCpuRatioForWindowsAfterRun() {
try {
c1 = readCpu(Runtime.getRuntime().exec(procCmd));
if (c0 != null && c0.length > 0 && c1 != null && c1.length > 0) {
double idletime = c1[0] - c0[0];
double busytime = c1[1] - c0[1];
CPU=PERCENT * (busytime) / (busytime + idletime);
return PERCENT * (busytime) / (busytime + idletime);
}
} catch (Exception e) {
System.out.println("cannot load monitor info2: cpu ratio in windows"+e);
}
return 0;
}
public static double[] readCpu(Process proc) {
double[] retn = new double[2];
try (InputStream inputStream = proc.getInputStream()) {
proc.getOutputStream().close();
InputStreamReader ir = new InputStreamReader(inputStream);
LineNumberReader input = new LineNumberReader(ir);
String line = input.readLine();
if (line == null || line.length() < FAULTLENGTH) {
return new double[0];
}
int capidx = line.indexOf("Caption");
int cmdidx = line.indexOf("CommandLine");
int rocidx = line.indexOf("ReadOperationCount");
int umtidx = line.indexOf("UserModeTime");
int kmtidx = line.indexOf("KernelModeTime");
int wocidx = line.indexOf("WriteOperationCount");
double idletime = 10;
double kneltime = 10;
double usertime = 10;
while ((line = input.readLine()) != null) {
if (line.length() < wocidx) {
continue;
}
// 字段出现顺序:Caption,CommandLine,KernelModeTime,ReadOperationCount,
// ThreadCount,UserModeTime,WriteOperation
String caption = line.substring(capidx, cmdidx - 1).trim();
String cmd = line.substring(cmdidx, kmtidx - 1).trim();
if (cmd.contains("wmic.exe")) {
continue;
}
String s1 = line.substring(kmtidx, rocidx - 1).trim();
String s2 = line.substring(umtidx, wocidx - 1).trim();
// System.out.println("si And s2:" +s1+"::"+s2);
if(!s1.equals("0 510")) {
if (caption.equals("System Idle Process") || caption.equals("System")) {
if (s1.length() > 0) {idletime += Long.valueOf(s1);}
if (s2.length() > 0) { idletime += Long.valueOf(s2);}
continue;
}
if (s1.length() > 0) { kneltime += Long.valueOf(s1);}
if (s2.length() > 0) { usertime += Long.valueOf(s2);}
}
}
retn[0] = idletime;
retn[1] = kneltime + usertime;
return retn;
} catch (Exception e) { System.out.println("cannot load monitor info2: read cpu info"+e);}
return new double[0];
}
}
获取内存:
1 进程占用的内存概念:
工作集内存:该进程实际再物理内存中的大小。
工作集内存=专用内存+共享内存
所以由定义,本次方案获取的内存为进程的工作集内存。
2 代码操作
通过Java getRuntime方法获取JVM运行环境,得到进程的pid,再通过tasklist的Linux命令获得javaw.exe进程,解析并读取该进程信息工作集内存。
具体流程看详细代码 。
获取内存代码:
public class GetMemory {
public static String pid=null;
public static long Memory=0;
public static boolean ThreadFlag=false;
static long Average=0;
static List<Double> nums=new ArrayList<Double>();
public static double getMemoryRate() {
long memRate=0;
memRate=getMemoryRateForWindows();
return memRate;
}
public static String getJvmPIDOnWindows() {
RuntimeMXBean runtime=ManagementFactory.getRuntimeMXBean();
pid=runtime.getName().split("@")[0];
return pid;
}
public static long getMemoryRateForWindows() {
pid=getJvmPIDOnWindows();
String command="TASKLIST /NH /FO CSV /FI \"PID EQ "+pid+"\"";
String remCount="";//jvm??àí?ú′???ó?á?
String remshare="";
String remUse="";
BufferedReader in=null;
String result="";
String physicalJvmMem = null;
String shareJvmMem = null;
String UseJvmMem = null;
try {
Process pro=Runtime.getRuntime().exec(command);
in=new BufferedReader(new InputStreamReader(pro.getInputStream()));
StringTokenizer ts=new StringTokenizer(in.readLine(),"\"");
int i=1;
while(ts.hasMoreTokens()) {
i++;
ts.nextToken();
if(i==9) {
remCount=ts.nextToken().replace(",", "").replace("K", "").trim();
}
}
Memory=Long.parseLong(remCount)/1024;
in.close();
pro.destroy();
}catch(Exception e) {
}
return Memory ;
}
}