前言
本文將整理騰訊GT各個性能測試項的測試方法,目的是為了幫助移動性能專項測試同學(xué)快速過一遍騰訊GT各個性能數(shù)據(jù)是如何獲取的。
一.GT性能測試方案之CPU測試
1.簡要流程
2.代碼流程
public?CpuUtils()?{initCpuData();}private?void?initCpuData()?{pCpu?=?o_pCpu?=?0.0;aCpu?=?o_aCpu?=?0.0;}
public?String?getProcessCpuUsage(int?pid)?{String?result?=?"";String[]?result1?=?null;String[]?result2?=?null;if?(pid?>=?0)?{result1?=?getProcessCpuAction(pid);if?(null?!=?result1)?{pCpu?=?Double.parseDouble(result1[1])+?Double.parseDouble(result1[2]);}result2?=?getCpuAction();if?(null?!=?result2)?{aCpu?=?0.0;for?(int?i?=?2;?i?<?result2.length;?i++)?{aCpu?+=?Double.parseDouble(result2[i]);}}double?usage?=?0.0;if?((aCpu?-?o_aCpu)?!=?0)?{usage?=?DoubleUtils.div(((pCpu?-?o_pCpu)?*?100.00),(aCpu?-?o_aCpu),?2);if?(usage?<?0)?{usage?=?0;}else?if?(usage?>?100){usage?=?100;}}o_pCpu?=?pCpu;o_aCpu?=?aCpu;result?=?String.valueOf(usage)?+?"%";}p_jif?=?pCpu;return?result;}
二.GT性能測試方案之內(nèi)存測試
1.簡要流程
內(nèi)存測試主要通過handleMessage來觸發(fā),根據(jù)msg參數(shù)來決定任務(wù)執(zhí)行
內(nèi)存數(shù)據(jù)獲取:僅僅簡單通過dumpsys meminfo來獲取內(nèi)存數(shù)據(jù),然后通過解析來得到pss_Native/naticeHeapSize/naticeAllocated/pss_OtherDev/pss_graphics/pss_gl/pss_UnKnown/pss_total數(shù)據(jù)
dumpHeap:通過am dumpheap 來獲取heap文件
GC:直接kill -10 $pid 來完成GC
2.測試方法
public?static?MemInfo?getMemInfo(String?packageName){MemInfo?result?=?null;String?resultString?=?null;try?{resultString?=?runCMD("dumpsys?meminfo?"?+?packageName);}?catch?(Exception?e)?{e.printStackTrace();return?MemInfo.EMPTY;}if(Env.API?<?14){result?=?parseMemInfoFrom2x(resultString);}else?if?(Env.API?<?19){result?=?parseMemInfoFrom4x(resultString);}else{result?=?parseMemInfoFrom44(resultString);}return?result;}
private?void?dumpHeap()?{String?pid?=?String.valueOf(ProcessUtils.getProcessPID(AUTManager.pkn.toString()));if?(!pid.equals("-1"))?{boolean?isSucess?=?true;ProcessBuilder?pb?=?null;String?sFolder?=?Env.S_ROOT_DUMP_FOLDER?+?AUTManager.pkn.toString()?+?"/";File?folder?=?new?File(sFolder);if?(!folder.exists()){folder.mkdirs();}String?cmd?=?"am?dumpheap?"?+?pid?+?"?"//?命令+?Env.S_ROOT_DUMP_FOLDER?+?AUTManager.pkn.toString()?+?"/"//?輸出路徑+?"dump_"?+?pid?+?"_"?+?GTUtils.getSaveDate()?+?".hprof";?//?輸出文件名pb?=?new?ProcessBuilder("su",?"-c",?cmd);Process?exec?=?null;pb.redirectErrorStream(true);try?{exec?=?pb.start();InputStream?is?=?exec.getInputStream();BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(is));while?((reader.readLine())?!=?null)?{isSucess?=?false;}}?catch?(Exception?e)?{e.printStackTrace();isSucess?=?false;}//?至此命令算是執(zhí)行成功if?(isSucess){handler.sendEmptyMessage(6);}}?else?{Log.d("dump?error",?"pid?not?found!");}}
private?void?gc()?{String?pid?=?String.valueOf(ProcessUtils.getProcessPID(AUTManager.pkn.toString()));if?(!pid.equals("-1"))?{boolean?isSucess?=?true;ProcessBuilder?pb?=?null;String?cmd?=?"kill?-10?"?+?pid;pb?=?new?ProcessBuilder("su",?"-c",?cmd);Process?exec?=?null;pb.redirectErrorStream(true);try?{exec?=?pb.start();InputStream?is?=?exec.getInputStream();BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(is));while?((reader.readLine())?!=?null)?{isSucess?=?false;}}?catch?(Exception?e)?{e.printStackTrace();isSucess?=?false;}//?至此命令算是執(zhí)行成功if?(isSucess){handler.sendEmptyMessage(5);}}?else?{Log.d("gc?error",?"pid?not?found!");}}
三.GT性能測試方案之內(nèi)存填充
1.簡要流程
內(nèi)存填充,主要是通過調(diào)用系統(tǒng)的malloc來分配內(nèi)存。內(nèi)存釋放,則是通過系統(tǒng)free來釋放。
2. 代碼流程
const?int?BASE_SIZE?=?1024*1024;?//?1Mint?fill(int?blockNum){int?memSize?=?blockNum?*?BASE_SIZE;p?=?(char?*)malloc(memSize);int?i;for?(i?=?0;?i?<?memSize;?i++){p[i]?=?0;}return?0;}int?freeMem(){free(p);return?0;}
public?class?MemFillTool?{public?MemFillTool()?{}public?static?MemFillTool?instance?=?null;public?static?MemFillTool?getInstance()?{if?(instance?==?null)?{System.loadLibrary("mem_fill_tool");instance?=?new?MemFillTool();}return?instance;}//?填充xxxMB內(nèi)存public?native?int?fillMem(int?blockNum);//?釋放剛才填充的內(nèi)存public?native?int?freeMem();}
四.GT性能測試方案之幀率測試
1.簡要流程
FPS數(shù)據(jù)收集是一個定時任務(wù)(4.3后1s一次),通過異步線程中不斷獲取FPS數(shù)據(jù)來刷新到前端頁面。而廣播模式調(diào)用,則直接從緩存的field中獲取數(shù)據(jù)即可。
在這里GT獲取fps數(shù)據(jù),也是通過采用surfaceflinger來獲取,但我感覺好像是有問題的。因為,一般surfaceflinger數(shù)據(jù)獲取的命令是adb shell dumpsys SurfaceFlinger --latency <window name>,在這里直接定義了把"service call SurfaceFlinger 1013"字符串寫到流里,沒看明白這個操作跟幀率獲取有什么關(guān)系。剛?cè)チ私饬讼?#xff0c;Runtime.getRuntime()原來執(zhí)行多條命令時后續(xù)只要拿到process的DataOutputStream對象,繼續(xù)writeBytes就可以保證是在同一個上下文中執(zhí)行多條命令了。
2.代碼流程
if?(!?GTFrameUtils.isHasSu()){return;}
startTime?=?System.nanoTime();if?(testCount?==?0)?{try?{lastFrameNum?=?getFrameNum();}?catch?(IOException?e)?{e.printStackTrace();}}int?currentFrameNum?=?0;try?{currentFrameNum?=?getFrameNum();}?catch?(IOException?e)?{e.printStackTrace();}int?FPS?=?currentFrameNum?-?lastFrameNum;if?(realCostTime?>?0.0F)?{int?fpsResult?=?(int)?(FPS?*?1000?/?realCostTime);defaultClient.setOutPara("FPS",?fpsResult);}lastFrameNum?=?currentFrameNum;testCount?+=?1;
public?static?synchronized?int?getFrameNum()?throws?IOException?{String?frameNumString?=?"";String?getFps40?=?"service?call?SurfaceFlinger?1013";if?(process?==?null){process?=?Runtime.getRuntime().exec("su");os?=?new?DataOutputStream(process.getOutputStream());ir?=?new?BufferedReader(new?InputStreamReader(process.getInputStream()));}os.writeBytes(getFps40?+?"\n");os.flush();String?str?=?"";int?index1?=?0;int?index2?=?0;while?((str?=?ir.readLine())?!=?null)?{if?(str.indexOf("(")?!=?-1)?{index1?=?str.indexOf("(");index2?=?str.indexOf("??");frameNumString?=?str.substring(index1?+?1,?index2);break;}}int?frameNum;if?(!frameNumString.equals(""))?{frameNum?=?Integer.parseInt(frameNumString,?16);}?else?{frameNum?=?0;}return?frameNum;}
五.GT性能測試方案之流暢度測試
1.簡要流程
騰訊的流暢度測試比較簡單粗暴,測試方式是通過初始化choreographer日志級別,生成Choreographer日志來得到當(dāng)前操作的丟幀。通過一系列計算后來計算流暢度。
2.測試方法
View.OnClickListener?button_write_property?=?new?View.OnClickListener()?{@Overridepublic?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();}}};
View.OnClickListener?button_check_status?=?new?View.OnClickListener()?{@Overridepublic?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();}}};
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();}}
while?(true)?{if?(pause)?{break;}int?x?=?count.getAndSet(0);//?卡頓大于60時,要將之前幾次SM計數(shù)做修正if?(x?>?60)?{int?n?=?x?/?60;int?v?=?x?%?60;TagTimeEntry?tte?=?OpPerfBridge.getProfilerData(key);int?len?=?tte.getRecordSize();//?補償參數(shù)int?p?=?n;//Math.min(len,?n);/**?n?>?len是剛啟動測試的情況,日志中的亡靈作祟,這種情況不做補償;*?并且本次也記為60。本邏輯在兩次測試間會清理數(shù)據(jù)的情況生效。*/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);}
六.GT性能測試方案之流量測試
1.簡要流程
流量測試有三種方案,默認采用方案1
2.代碼流程
public?void?initProcessNetValue(String?pName)?{p_t_base?=?getOutOctets(pName);p_r_base?=?getInOctets(pName);p_t_add?=?0;p_r_add?=?0;}
其中g(shù)etOutOctets/getInOctets具體對應(yīng)什么方法,需要看設(shè)備是不是支持uid流量數(shù)據(jù)獲取
public?String?getProcessNetValue(String?pName)?{StringBuffer?sb?=?new?StringBuffer();java.text.DecimalFormat?df?=?new?java.text.DecimalFormat("#.##");p_t_cur?=?getOutOctets(pName);p_r_cur?=?getInOctets(pName);p_t_add?=?(p_t_cur?-?p_t_base)?/?B2K;p_r_add?=?(p_r_cur?-?p_r_base)?/?B2K;sb.append("t");sb.append(df.format(p_t_add));sb.append("KB|r");sb.append(df.format(p_r_add));sb.append("KB");return?sb.toString();}
//?modify?on?20120616?過濾有的手機進程流量偶爾輸出負數(shù)的情況if?((nowT?!=?lastT?||?nowR?!=?lastR)?&&?nowT?>=?0?&&?nowR?>=?0)?{OpPerfBridge.addHistory(op,?value,?new?long[]{(long)?nowT,?(long)?nowR});}return?value;
七.GT性能測試方案之電量測試
1.簡單流程
關(guān)注指標:
電量測試關(guān)注的指標有四個: 電流,電壓,電量跟溫度。
數(shù)據(jù)獲取方式:
通過ReadPowerTimerTask任務(wù)去set關(guān)注的電量指標,當(dāng)update方法調(diào)用時,才把數(shù)據(jù)set進去。電量數(shù)據(jù)調(diào)用的系統(tǒng)命令/sys/class/power_supply/battery/uevent
具體流程:
接收"com.tencent.wstt.gt.plugin.battery.startTest"廣播后,update各個指標
注冊跟設(shè)置出參,并設(shè)置刷新頻率跟初始化屏幕電量
開啟定時任務(wù)ReadPowerTimerTask,這個任務(wù)的作用就是去獲取/sys/class/power_supply/battery/uevent下的電量數(shù)據(jù)并解析,最后設(shè)置出參。刷新頻率默認是250ms一次
最后stop時,銷毀異步定時任務(wù)
2.代碼流程
整個生命周期如下,當(dāng)BATTERY_START_TEST行為被捕獲時,開始執(zhí)行電量測試
String?action?=?intent.getAction();if?(action?==?null)?return;if?(action.equals(BATTERY_START_TEST))?{int?refreshRate?=?intent.getIntExtra("refreshRate",?250);int?brightness?=?intent.getIntExtra("brightness",?100);boolean?updateI?=?intent.getBooleanExtra("I",?true);GTBatteryEngine.getInstance().updateI(updateI);boolean?updateU?=?intent.getBooleanExtra("U",?false);GTBatteryEngine.getInstance().updateU(updateU);boolean?updateT?=?intent.getBooleanExtra("T",?false);GTBatteryEngine.getInstance().updateT(updateT);boolean?updateP?=?intent.getBooleanExtra("P",?false);GTBatteryEngine.getInstance().updateP(updateP);GTBatteryEngine.getInstance().doStart(refreshRate,?brightness);}?else?if?(action.equals(BATTERY_END_TEST))?{GTBatteryEngine.getInstance().doStop();}
public?void?updateI(boolean?isChecked){if?(isChecked){globalClient.registerOutPara(GTBatteryEngine.OPI,?"I");globalClient.setOutparaMonitor(GTBatteryEngine.OPI,?true);}else{globalClient.unregisterOutPara(GTBatteryEngine.OPI);}state_cb_I?=?isChecked;GTPref.getGTPref().edit().putBoolean(GTBatteryEngine.KEY_I,?isChecked).commit();for?(BatteryPluginListener?listener?:?listeners){listener.onUpdateI(isChecked);}}
timer
= new Timer
(true);timer
.schedule(new ReadPowerTimerTask
(), refreshRate
, refreshRate
);@Overridepublic void run() {BufferedReader br
= null;try {FileReader fr
= new FileReader
(f
);br
= new BufferedReader
(fr
);String line
= "";while((line
= br
.readLine()) != null){int found
= 0;if (line
.startsWith("POWER_SUPPLY_VOLTAGE_NOW=")){U
= line
.substring(line
.lastIndexOf("=") + 1);// since 2.1.1 從μV轉(zhuǎn)成mVlong volt
= Long
.parseLong(U
) / 1000;globalClient
.setOutPara(OPU
, volt
+ "mV");OutPara op
= globalClient
.getOutPara(OPU
);if (null != op
){OpPerfBridge
.addHistory(op
, U
, volt
);}found
++;}if (line
.startsWith("POWER_SUPPLY_CURRENT_NOW=")){I
= line
.substring(line
.lastIndexOf("=") + 1);// since 2.1.1 從μA轉(zhuǎn)成mA since 2.2.4 華為本身就是mAlong current
= Long
.parseLong(I
);if (isHuawei
){current
= -current
;}else if (isLGg3
){current
= current
>> 1; // 經(jīng)驗值估算LG g3的數(shù)據(jù)除以2后比較接近真實}else{current
= current
/ 1000;}globalClient
.setOutPara(OPI
, current
+ "mA");OutPara op
= globalClient
.getOutPara(OPI
);if (null != op
){OpPerfBridge
.addHistory(op
, I
, current
);}found
++;}if (line
.startsWith("POWER_SUPPLY_CAPACITY=")){String lastBattery
= POW
;POW
= ?line
.substring(line
.lastIndexOf("=") + 1);if (! lastBattery
.equals(POW
)) // 電池百分比變化了{if (startBattry
!= -1){lastBatteryChangeTime
= (System
.currentTimeMillis() - startBattry
)/1000 + "s";String tempValue
= POW
+ "% | -1% time:" + lastBatteryChangeTime
;globalClient
.setOutPara(OPPow
, tempValue
);GTLog
.logI(LOG_TAG
, tempValue
);// 將電量加入歷史記錄OutPara op
= globalClient
.getOutPara(OPPow
);if (null != op
){OpPerfBridge
.addHistory(op
, tempValue
, Long
.parseLong(POW
));}}startBattry
= System
.currentTimeMillis();}globalClient
.setOutPara(OPPow
, POW
+ "% | -1% time:" + lastBatteryChangeTime
);found
++;}if (line
.startsWith("POWER_SUPPLY_TEMP=")){TEMP
= line
.substring(line
.lastIndexOf("=") + 1);int iTemp
= Integer
.parseInt(TEMP
);iTemp
= iTemp
/10;if (iTemp
> -273){TEMP
= iTemp
+ "℃";}globalClient
.setOutPara(OPTemp
, TEMP
);OutPara op
= globalClient
.getOutPara(OPTemp
);if (null != op
&& iTemp
!= INT_TEMP
){OpPerfBridge
.addHistory(op
, TEMP
, iTemp
);GTLog
.logI(LOG_TAG
, TEMP
);INT_TEMP
= iTemp
;}found
++;}if (found
>= 4){return;}}} catch (Exception e
) {doStop
();}finally{FileUtil
.closeReader(br
);}}
總結(jié)
以上是生活随笔為你收集整理的源码解读腾讯 GT 的性能测试方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。