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使用率,剩余内存和硬盘容量相关文章推荐
- cocos2d-x TestLua 之 CCMenuItemLabel CCMenuItemSprite CCMenuItemFont 菜单类
- 生前想故人
- ==与===区别
- ios触摸事件一 :UIEvent
- Javascript Window Location
- 设置背景透明
- 中科院专家董传仪:安存是中国互联网安全事业的好朋友
- 通过 EWS JAVA API读取exchange邮件
- Eclipse 安装 Valgrind 插件(解决安装完找不到的问题)
- SRM675 medium ShortestPathWithMagic(DP+Dijkstra)
- JQueryMobile+融云webSDK创建的聊天室有多余空白
- iOS学习路线图
- 创建模式
- VirtualBox安装中遇到的问题
- java——Arrays.asList()方法
- 高斯过程分类原理
- Linux下制作ubuntu系统的u盘启动版LiveCD和直接硬盘启动LiveCD
- 安卓分享
- Arrays.asList java.lang.UnsupportedOperationException 异常
- iOS学习路线 iOS框架图 UI框架