移动性能测试 Android 性能测试实践 (三) Cpu

testly · 2015年05月19日 · 最后由 angelBabyAmy 回复于 2020年09月07日 · 14680 次阅读
本帖已被设为精华帖!

Cpu 篇

关于 Android 的 Cpu 占用率需要注意以下三种情况:

1.空闲状态下的应用 CPU 消耗情况 简单说这种情况呢就是说被测应用在系统资源非常空闲的情况下的占用率,比如只开一个被测应用

2.中等规格状态下的应用 CPU 消耗情况 简单说这种情况就是后台已经有几个应用在运行已经并且消耗了系统的一些资源的情况下进行测试。

3.满规格状态下的应用 CPU 消耗情况 这个就不要说了,你们懂得!

数据采集方案:

1.

adb shell dumpsys cpuinfo

这里可以看到所有进程的 Cpu 占用率:

大家看第一个应用 CPU 占用率 68%,这个过程是在用户(user)中花 61% 的时间,并在内核空间(kernel)花费 7.1% 的时间。

如果你想筛选出你自己的应用的话可以用下面这一段:

adb shell dumpsys cpuinfo |grep packagename 

2.使用 top 命令:

进入 Adb shell

adb shell
top -m 10 -s cpu

可查看占用 cpu 最高的前 10 个程序(-t 显示进程名称,-s 按指定行排序,-n 在退出前刷新几次,-d 刷新间隔,-m 显示最大数量)

如果你想筛选出你自己的应用的话可以用下面这一段:

adb shell top -n 1| grep PackageName

拿到这些数据怎么用

1,你可以从代码里面获取:

(dumpsys)

adb shell  dumpsys  cpuinfo
    public static String GetCpu(String packageName) throws IOException {
        String str3=null;
          Runtime runtime = Runtime.getRuntime();
          Process proc = runtime.exec("adb shell dumpsys cpuinfo  $"+packageName);
          try {
              if (proc.waitFor() != 0) {
                  System.err.println("exit value = " + proc.exitValue());
              }
              BufferedReader in = new BufferedReader(new InputStreamReader(
                      proc.getInputStream()));
              StringBuffer stringBuffer = new StringBuffer();
              String line = null;
              while ((line = in.readLine()) != null) {
                  stringBuffer.append(line+" ");       
              }
          String str1=stringBuffer.toString(); 
          String str2=str1.substring(str1.indexOf(packageName),str1.indexOf(packageName)+28);
          str3=str2.substring(18,23); 


          } catch (InterruptedException e) {
              System.err.println(e);
          }finally{
              try {
                  proc.destroy();
              } catch (Exception e2) {
              }
          }
          return str3;

    }

}

(Top)


public static double cpu(String PackageName) throws IOException {      
      double Cpu = 0;
      try{           
      Runtime runtime = Runtime.getRuntime();
      Process proc = runtime.exec("adb shell top -n 1| grep "+PackageName);
      try {
          if (proc.waitFor() != 0) {
              System.err.println("exit value = " + proc.exitValue());
          }
          BufferedReader in = new BufferedReader(new InputStreamReader(
                  proc.getInputStream()));
          StringBuffer stringBuffer = new StringBuffer();
          String line = null;
          while ((line = in.readLine()) != null) {
              stringBuffer.append(line+" ");


          }
      String str1=stringBuffer.toString();  
      String  str3=str1.substring(str1.indexOf(PackageName)-43,str1.indexOf(PackageName));
      String cpu= str3.substring(0,4);
              cpu=cpu.trim(); 
              Cpu=Double.parseDouble(cpu);

      } catch (InterruptedException e) {
          System.err.println(e);
      }finally{
          try {
              proc.destroy();
          } catch (Exception e2) {
          }
      }
      }
      catch (Exception StringIndexOutOfBoundsException)
      {

          System.out.print("请检查设备是否连接");

      }

          return Cpu;

}


2,直接 adb shell cat 进去 proc/cpuinfo/下面:

public String[] getCpuInfo() {  
    String str1 = "/proc/cpuinfo";  
    String str2="";  
    String[] cpuInfo={"",""};  
    String[] arrayOfString;  
    try {  
        FileReader fr = new FileReader(str1);  
        BufferedReader localBufferedReader = new BufferedReader(fr, 8192);  
        str2 = localBufferedReader.readLine();  
        arrayOfString = str2.split("\\s+");  
        for (int i = 2; i < arrayOfString.length; i++) {  
            cpuInfo[0] = cpuInfo[0] + arrayOfString[i] + " ";  
        }  
        str2 = localBufferedReader.readLine();  
        arrayOfString = str2.split("\\s+");  
        cpuInfo[1] += arrayOfString[2];  
        localBufferedReader.close();  
    } catch (IOException e) {  
    }  
    return cpuInfo;  
}  

取完你可以这么用》:

配合一些场景去采集数据:

这样可以看到每个步骤消耗的资源情况

然后汇总数据分析(最好多取几次求平均值):

欢迎一起交流,一起进步 可以关注我的微信公众号:“测试开发进阶” - 点我关注

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 47 条回复 时间 点赞

话说

String  str3=str1.substring(str1.indexOf(PackageName)-43,str1.indexOf(PackageName));
       String cpu= str3.substring(0,4);
               cpu=cpu.trim(); 
               Cpu=Double.parseDouble(cpu);

这个规则是啥。。。

#1 楼 @monkey 截取转换

#2 楼 @testly 我知道。。你怎么保证,每个机器都能够准确的找到?

#3 楼 @monkey 设备不一样 包名一样啊

#3 楼 @monkey 我是拿包名前面位标准的

#4 楼 @testly 。。。每个设备的 top 数据矩阵都不同的。。。。明白我的意思?

#6 楼 @monkey 明白!那用 Cpuinfo 来取,怎样?

#6 楼 @monkey 我试过 5 台机器 三星 中兴 华为 HTC 谷歌 都测试过没有问题。。。所以其他机器我也没有去试过!也不敢保证可以取到

#8 楼 @testly 肯定有不一样的。之前看到过好多了。。。。

#7 楼 @testly cpuinfo 没有尝试过。应该会好点吧

testly #11 · 2015年05月19日 Author

#9 楼 @monkey 恩,dumpsy cpuinfo 里面的标准应该要好一点!

挺复杂的

@testly

我想问下,如何在 window 下 如何调用 adb shell 的命令,我使用 runtime.exec("adb shell dumpsys ") ;这个命令,一直在报错,也试过在前面街上 cmd.exe 但是还是不行呢,请教下,window 写如何通过 java 调用 adb 命令???

testly #14 · 2015年05月20日 Author

#13 楼 @felixtest Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec(Command);
报什么错?

我想问一下,文中提到的三种规格:空规格,中等规格和满规格是说手机状态,而不是说对应用的操作吗?比如,空规格是指启动程序后按 Home 不进行任何操作,中等规格是正常操作 App,满规格是执行 Monkey。当然这可能会按实际需求去定,但一般情况是用哪种采样更合理呢?

testly #16 · 2015年05月20日 Author

#15 楼 @emily 既然是性能测试最好都涉及到为好咯!优先级的话!中》高》低

@testly
1、在 windows 下,开始在没有输入 str1 的时候,提示检查连接设备,我就把修改了 grep --> findstr ,发现提示如下:

2、根据提示,我又将 findstr 修改为 grep,打印如下:但是提示依然是设备连接问题,这个提示不友好哈,此时是可以获取到设备的信息的,如下:

总结:以上问题,认为 java 中的 runtime.exec() 方法是执行 windows 系统下的命令,所以我使用了 findstr,但是实际上 Runtime 获取当前的系统程序应是指 Android,也就是 Linux,我修改了 grep,可以获取 cpu 的值,但是取 子字符中的角标越界问题我还在想,哈哈· 还是谢谢你哈~

testly #19 · 2015年05月20日 Author

#18 楼 @felixtest 恩恩,这句是将 String 转 double 然后切入 Jfreechart 进行统计

@testly ,是的 这就 Cpu=Double.parseDouble(cpu);,是不是需要结合 jfreechart 用的哈,单独用会报错,我直接使用 String,就 OK 了~谢谢

testly #21 · 2015年05月20日 Author

#20 楼 @felixtest 恩,不客气

请问,你们执行性能测试的机器会用什么?会针对不同的机器做性能测试么?有必要么?

testly #23 · 2015年05月20日 Author

#22 楼 @shixue33 看你们的需求呢,要求不高的话可以拿一个普通机器看看数据跟别的应用对比对比就好啦! 我自己的话是有 5 个机器,但是呢真正测试的 就三个 一个低配,一个非主流、一个主流中高端机器

学习了,牛人。这两天学习一下 jfreechart 搞一下,遇到困难时,还望大神多多帮忙,O(∩_∩) O~

@testly dumpsy cpuinfo 中进程的 cpu 占用会跟 top 基本一样么?平常使用这个命令的时候 cpu 信息更新的比较慢,知道这个命令数据更新的规则么?

testly #26 · 2015年05月25日 Author

#25 楼 @raowm520 不好意思,我没有注意到你的疑问!不会一样, dumpsys cpuinfo 里面是描述 Cpu 的使用详情 且里面的 cpu 占比是指 Cpu 所花的时间比比如用户活动消耗时间占比和内耗消耗时间占比,top 是实际单进程的 Cpu 占用!这是我的理解!

@testly 好的,我自己也再看看

testly #28 · 2015年05月26日 Author

#27 楼 @raowm520 欢迎交流

hi,大神
我在尝试着用 adb shell top -d 1 | grep + packagename 命令去读取特定 app 的 cpu 使用率。大致的想法是这样的:通过这条命令,把所有的输出写到一个文件里,然后在汇总 cpu 占用的情况。
代码是这样的:
String path = "e:/cpu.txt";
int i = 0;
/*if(! haveDevices())
{
System.out.println("device not existing,please check ");
return ;
}
*/
try
{
Runtime rt = Runtime.getRuntime();

File myFilePath = new File(path);
if (! myFilePath.exists())
myFilePath.createNewFile();

FileWriter file = new FileWriter(myFilePath,true);
Process proc = rt.exec("adb shell top -d 1 | grep " + packagename ); //得到的 CPU 信息写到文件中
try{

if(proc.waitFor() != 0)
{
System.err.println("exit value = " + proc.exitValue()); //waitfor 返回值 0 正常结束
}
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
StringBuffer strBuff = new StringBuffer();
while((line = reader.readLine()) != null)
{
//if(line != null)
//file.write(line + "\n") ; //仅保存含包名的
System.out.println(line);
}
}

运行之后发现 cpu.txt 为空,应该是 reader 也为空,不知道是什么鬼

testly #30 · 2015年05月28日 Author

#29 楼 @best1196 首先给你一点思路,你可以分两步,第一步先把想要的值取出来赋给一个对象!第二 把新建文件和输入的内容封装一下,再调用这个方法把对象传过去!

#30 楼 @testly 本来想完全自动化的,不过被那个问题卡住了,现在的思路:先手动执行下那个命令,把他重定向到文件里,然后在读文件,这样就好处理了

对于 best1196 提出的这个问题,还是自己来解答下。
代码里需要添加 InputStream is = process.getErrorStream(); // 获取错误输出流
由于错误输出流一直没有被清空导致程序被阻塞,添加这行代码之后错误输出流就被清空了,当然就不会被阻塞了。
详细的内容可参考 http://249wangmang.blog.163.com/blog/static/52630765201261334351635/
多谢大神 @testly 不吝赐教,:D

testly #33 · 2015年05月28日 Author

#32 楼 @best1196 解决了就好!

hello 有查看到 android5.0 如果需要使用 runtime 去执行 dumpsys 命令的话,添加 android.permission.DUMP 权限需要 app 是系统应用或赋予 signatureOrSystem 等级,但是添加了之后依然没作用,不知道有没有什么解决办法

testly #35 · 2015年05月29日 Author

#34 楼 @bh01251859 两个思路:第一个,你先手去获取一下 adb shell dumpsys cpuinfo 或者 adb shell top 如果手工获取不到
那就更不要提 runtime 了! 第二个,检查下手机 root 权限

很想问问大神最后的 html 的报告是怎么实现的啊??

匿名 #38 · 2016年01月23日

半夜了,新手加入,根本停不下来!感谢 testerhome 这个平台啊啊啊!坚持坚持!

—— 来自 TesterHome 官方 安卓客户端

dumpsys 拿到的是几个 cpu 的值,所以可能得到 100+% 的值,还是 proc/pid/stat 靠谱点

#39 楼 @jira xxxxxx:~ xxxxxxx$ adb shell dumpsys cpuinfo |grep com.xxx.xxx
107% 15524/com.xxx.xxx: 84% user + 23% kernel / faults: 2098 minor

请问,如何确定所取到的值是在操作该场景时的值呢,而且,场景应该都是一段时间的,您最后取到的这个场景的值是说进入该场景时的值么?

@testly 大神,我问一个小白问题,为什么我执行 top -n 1 这一句话需要 3300+ 毫秒;还有就是我这手机没找到 su 文件,执行 dumpsys cpuinfo 会保存;

testly #43 · 2016年09月14日 Author

#42 楼 @tiger07706 top load 的数据比较多 不过 3 秒有点夸张了

大神,我在执行 exec(top -n 1|grep 包名) 时 exitvalue 为 1,reader.readline() 也无法获取数据,请帮忙看一下吧,谢谢了

在 “配合一些场景去采集数据” 这一节里面,你用的是 jenkins 吗?jenkins 里面的脚本怎么写的,另外,手机要连上 jenkins 所在的服务器吧?

请问 cpu 这些数据取出来后,是否需要优化的判断标准是啥呢?

testly 回复

那请问一下,楼主,那我们在手机数据的时候,使用这两个当中的哪个数据呢?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册