騰訊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);
        }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM