zoukankan      html  css  js  c++  java
  • 腾讯GT的流畅度测试方案研究

    GT源码:https://github.com/TencentOpen/GT

    一.流畅度模块的代码结构

    流畅度插件总共就几个类,其实处理方式也比较简单粗暴,就是通过Choreographer输出的log信息获取跳帧数据。SMActivity.java为插件的入口类,你可以通过预设环境操作来实现log打印操作,然后通过SMLogService.java过滤出当前进程的丢帧值,最后由SMServiceHelper.java来进行数据处理。流畅度值为60减去1s内的跳帧数。

    二.流畅度测试

    1.简要流程

    • 执行setprop debug.choreographer.skipwarning 1
    • 执行getprop debug.choreographer.skipwarning判断,为1则可以进行测试
    • 执行adb logcat -v time -s Choreographer:I *:S
    • 过滤获取当前pid丢帧值
    • 数据处理得到sm值

    2.代码流程

    • 执行setprop debug.choreographer.skipwarning 1

      View.OnClickListener button_write_property = new View.OnClickListener() {
       
              @Override
              public void onClick(View v) {
                  String cmd = "setprop debug.choreographer.skipwarning 1";
                  ProcessBuilder execBuilder = new ProcessBuilder("su", "-c", cmd);
                  execBuilder.redirectErrorStream(true);
                  try {
                      execBuilder.start();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          };
    • 执行getprop debug.choreographer.skipwarning判断,为1则可以进行测试

      View.OnClickListener button_check_status = new View.OnClickListener() {
       
              @Override
              public void onClick(View v) {
                  String cmd = "getprop debug.choreographer.skipwarning";
                  ProcessBuilder execBuilder = new ProcessBuilder("sh", "-c", cmd);
                  execBuilder.redirectErrorStream(true);
                  try {
                      TextView textview = (TextView) findViewById(R.id.textviewInformation);
                      Process p = execBuilder.start();
                      InputStream is = p.getInputStream();
                      InputStreamReader isr = new InputStreamReader(is);
                      BufferedReader br = new BufferedReader(isr);
                      Boolean flag = false;
                      String line;
                      while ((line = br.readLine()) != null) {
                          if (line.compareTo("1") == 0) {
                              flag = true;
                              break;
                          }
                      }
       
                      if (flag) {
                          textview.setText("OK");
                      } else {
                          textview.setText("NOT OK");
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          };
    • 执行adb logcat -v time -s Choreographer:I *:S
    • 过滤获取当前pid丢帧值

      protected void onHandleIntent(Intent intent) {
              try {
       
                  String str = intent.getStringExtra("pid");
                  int pid = Integer.parseInt(str);
       
                  List<String> args = new ArrayList<String>(Arrays.asList("logcat", "-v", "time", "Choreographer:I", "*:S"));
       
                  dumpLogcatProcess = RuntimeHelper.exec(args);
                  reader = new BufferedReader(new InputStreamReader(dumpLogcatProcess.getInputStream()), 8192);
       
                  String line;
       
                  while ((line = reader.readLine()) != null && !killed) {
       
                      // filter "The application may be doing too much work on its main thread."
                      if (!line.contains("uch work on its main t")) {
                          continue;
                      }
                      int pID = LogLine.newLogLine(line, false).getProcessId();
                      if (pID != pid){
                          continue;
                      }
       
                      line = line.substring(50, line.length() - 71);
                      Integer value = Integer.parseInt(line.trim());
       
                      SMServiceHelper.getInstance().dataQueue.offer(value);
                  }
              } catch (IOException e) {
                  Log.e(TAG, e.toString() + "unexpected exception");
              } finally {
                  killProcess();
              }
          }
       
    • 数据处理得到sm值

       腾讯这边的处理方案是:当丢帧<60时,流畅度SM =60-frame; 当丢帧frame>60时,流畅度SM = 60-frame%60。不过这种处理方式是有问题的。在这里要先说下流畅度计算的原理:

       VSync机制可以通过其Loop来了解当前App最高绘制能力,固定每隔16.6ms执行一次,这样最高的刷新的帧率就控制在60FPS以内,Choreographer日志可以打印当前丢帧数,因此通过计算,得到当前APP的流畅度。

            而计算这样来计算可能会更加准确:

            SM= 60-丢帧frame/每两行同一线程的丢帧时间差(单位:s),如果只关心UI线程,那就只需要统计UI线程即可。

    • while (true) {
          if (pause) {
              break;
          }
          int x = count.getAndSet(0);
          // 卡顿大于60时,要将之前几次SM计数做修正
          if (x > 60) {
              int n = x / 60;
              int v = x % 60;
              TagTimeEntry tte = OpPerfBridge.getProfilerData(key);
              int len = tte.getRecordSize();
              // 补偿参数
              int p = n;
              //Math.min(len, n);
              /*
              * n > len是刚启动测试的情况,日志中的亡灵作祟,这种情况不做补偿;
              * 并且本次也记为60。本逻辑在两次测试间会清理数据的情况生效。
              */
              if (n > len) {
                  globalClient.setOutPara(key, 60);
      //          globalClient.setOutPara(SFKey, 0);
              } else {
                  for (int i = 0; i < p; i++) {
                  TimeEntry te = tte.getRecord(len - 1 - i);
                  te.reduce = 0;
                  }
              globalClient.setOutPara(key, v);
      //      globalClient.setOutPara(SFKey, 60 - v);
              }
          } else {
              int sm = 60 - x;
              globalClient.setOutPara(key, sm);
      //      globalClient.setOutPara(SFKey, x);
          }
  • 相关阅读:
    写一个工具生成数据库实体类
    自己写一个java的mvc框架吧(三)
    自己写一个java的mvc框架吧(二)
    自己写一个java的mvc框架吧(一)
    手把手教你写一个java的orm(完)
    JavaEE系列之(二)commons-fileupload实现文件上传、下载
    JavaEE系列之(一)JSP基础知识详解
    Servlet---JavaWeb技术的核心基础,JavaWeb框架的基石(二)
    Servlet---JavaWeb技术的核心基础,JavaWeb框架的基石(一)
    cygwin简介及使用
  • 原文地址:https://www.cnblogs.com/alexkn/p/6234788.html
Copyright © 2011-2022 走看看