您的位置:首页 > 其它

Emmagee(一)-Cpu读取的实现分析

2015-12-18 10:01 417 查看

介绍

目前测试android性能的工具有很多,如腾讯的GT,网易的Emmagge以及安测试。其中网易的Emmagee是开源的,所以我们主要是来分析Emmagge的实现原理来确定软件获取到的数据的可靠性。这样子我们才能够放心的使用它。

Emmagee(机关枪)是网易杭州研究院QA团队开发的一个简单易上手的Android性能监测小工具,主要用于监控单个App的CPU,内存,流量,启动耗时,电量,电流等性能状态的变化,且用户可自定义配置监控的频率以及性能的实时显示,并最终生成一份性能统计文件。我们可以通过Emmagge 查看到对应的源代码。



通过点击开始测试即可跳转到对应的测试程序进行统计数据了。

原理

这次主要是分析下Emmagge获取cpu数据的原理。 首先在我们选中测试的应用程序点击开始测试时,Emmagge会通过ActivityManager获取到对应程序的包名,进程名等

ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
//通过am的getRunningAppProcesses方法获取到运行的进程信息
List<RunningAppProcessInfo> run = am.getRunningAppProcesses();
PackageManager pm = context.getPackageManager();
List<Programe> progressList = new ArrayList<Programe>();
//遍历进程的列表将进程名,进程id赋值到programe对象上。
for (ApplicationInfo appinfo : getPackagesInfo(context)) {
Programe programe = new Programe();
if (((appinfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0) || ((appinfo.processName != null) && (appinfo.processName.equals(PACKAGE_NAME)))) {
continue;
}
for (RunningAppProcessInfo runningProcess : run) {
if ((runningProcess.processName != null) && runningProcess.processName.equals(appinfo.processName)) {
programe.setPid(runningProcess.pid);
programe.setUid(runningProcess.uid);
break;
}
}
programe.setPackageName(appinfo.processName);
programe.setProcessName(appinfo.loadLabel(pm).toString());
programe.setIcon(appinfo.loadIcon(pm));
progressList.add(programe);
}
Collections.sort(progressList);


通过比较我们选择的应用的包名以及后台运行的进程的包名来判断app是否已经正常运行起来了。现在我们就正式来看看获取cpu使用率吧,首先cpu使用率需要分为设备总的cpu使用率以及当前进程的cpu占用率,我们首先看看总的cpu的使用率:

try {
// monitor total and idle cpu stat of certain process
RandomAccessFile cpuInfo = new RandomAccessFile(CPU_STAT, "r");
String line = "";
while ((null != (line = cpuInfo.readLine())) && line.startsWith("cpu")) {
String[] toks = line.split("\\s+");
idleCpu.add(Long.parseLong(toks[4]));
totalCpu.add(Long.parseLong(toks[1]) + Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4])
+ Long.parseLong(toks[6]) + Long.parseLong(toks[5]) + Long.parseLong(toks[7]));
}
cpuInfo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}


在proc/stat下有详细的CPU使用情况,由于考虑到有多核的情况所以进行了while循环读取,但是实际看到后面发现,使用的数据只是使用了第一个总的cpu的时间就可以了.文件的详细格式如下:

CPU 152342 1421 28562 1600830 12389 553 273 0 0

CPU后面的几位数字分别是

user 从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含 nice值为负进程。

nice 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间

system 从系统启动开始累计到当前时刻,处于核心态的运行时间

idle 从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间

iowait 从系统启动开始累计到当前时刻,IO等待时间

irq 从系统启动开始累计到当前时刻,硬中断时间

softirq 从系统启动开始累计到当前时刻,软中断时间

所以CPU总数用率的算法是:100*((totalCpuTimeS-totalCpuTimeF) -(idelS-idelF))/ (totalCpuTimeS-totalCpuTimeF)

当前进程cpu的占用率

String processPid = Integer.toString(pid);
String cpuStatPath = "/proc/" + processPid + "/stat";
try {
// monitor cpu stat of certain process
RandomAccessFile processCpuInfo = new RandomAccessFile(cpuStatPath, "r");
String line = "";
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.setLength(0);
while ((line = processCpuInfo.readLine()) != null) {
stringBuffer.append(line + "\n");
}
String[] tok = stringBuffer.toString().split(" ");
processCpu = Long.parseLong(tok[13]) + Long.parseLong(tok[14]);
processCpuInfo.close();
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "FileNotFoundException: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}


因为android设备对应的pid的CPU使用情况实在/proc/pid/stat路径下。并且文本的内容为

9978 (o.easicare.demo) S 152 152 0 0 -1 4202816 12650 0 0 0 70 68 0 0 ...


后面的四位分别代表的是

utime 该任务在用户运行状态的时间

stime 该任务在核心运行的时间

cutime 所有已死线程在用户状态运行状态的时间

cstime 所有已死线程在核心的运行时间

所以当前进程所占CPU的算法是:100*(processCpuTimeS-processCpuTimeF)/(totalCpuTimeS-totalCpuTimeF)

现在我们进入到真正计算cpu使用率的方法中

//这里首先判断上一次获取的数据是否有值,如果没有可能是第一次获取所以调到else中给totalCpu2复制
if (null != totalCpu2 && totalCpu2.size() > 0) {
// (应用占用的cpu时间-上次应用占用cpu时间)/(设备总的cpu时间-上次设备总的cpu时间)
processCpuRatio = fomart.format(100 * ((double) (processCpu - processCpu2) / ((double) (totalCpu.get(0) - totalCpu2.get(0)))));
//以下是计算cpu的总的使用率
for (int i = 0; i < (totalCpu.size() > totalCpu2.size() ? totalCpu2.size() : totalCpu.size()); i++) {
String cpuRatio = "0.00";
if (totalCpu.get(i) - totalCpu2.get(i) > 0) {
cpuRatio = fomart
.format(100 * ((double) ((totalCpu.get(i) - idleCpu.get(i)) - (totalCpu2.get(i) - idleCpu2.get(i))) / (double) (totalCpu
.get(i) - totalCpu2.get(i))));
}
totalCpuRatio.add(cpuRatio);
totalCpuBuffer.append(cpuRatio + Constants.COMMA);
}
} else {
processCpuRatio = "0";
totalCpuRatio.add("0");
totalCpuBuffer.append("0,");
totalCpu2 = (ArrayList<Long>) totalCpu.clone();
processCpu2 = processCpu;
idleCpu2 = (ArrayList<Long>) idleCpu.clone();
}


虽然上面程序都遍历计算了每个cpu的占用率,但是最后返回的仍然是第一个,也就是总的cpu时间。

cpuUsedRatio.add(processCpuRatio);
cpuUsedRatio.add(totalCpuRatio.get(0));


结论

Emmagee获取cpu的数据大体就是如此,后续会继续研究其他的cpu值是否有意义,如果没有回将这部分代码去掉。

参考

Android获取cpu使用率,剩余内存和硬盘容量
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: