手機(jī)性能評(píng)測--3D場景

概述

書接上回手機(jī)性能評(píng)測--2D場景,這次講講3D評(píng)測。
隨著AR/VR方興未艾,手機(jī)勢必會(huì)成為各個(gè)廠商和開發(fā)者的一塊戰(zhàn)略要地。目前暫露頭角的要屬Pokémon GO(一款抓寵物小精靈的AR游戲)了。
那怎么知道我們的手機(jī)是否能流程的運(yùn)行3D程序呢?其實(shí)和2D測評(píng)大同小異,都是獲取每一幀的繪制時(shí)間。

疑問

根據(jù)2D場景的測評(píng)可以知道,使用gfxinfo可以抓到graphic信息,那3D場景繼續(xù)使用該方法不就可以了嗎?
當(dāng)我們滿懷信心的在3D場景下執(zhí)行adb shell dump gfxinfo后,卻無法得到任何信息。 why?!!!!
因?yàn)闇?zhǔn)確的來說,gfxinfo所對(duì)應(yīng)的service只能獲得2D view的繪制時(shí)間,要獲取3D場景的信息需要使用其他的手段.

SurfaceFlinger

android手機(jī)中,不論2D還是3D的繪制都需要surfaceflinger的參與,既然gfxinfo無法獲取3D的繪制,那我們就直搗黃龍去拿surfaceflinger里面的信息。
根據(jù) TesterHome社區(qū)中的統(tǒng)計(jì)fps文章,可以知道,循環(huán)使用

adb shell dumpsys SurfaceFlinger --latency <window name>

命令,然后處理每次命令的結(jié)果就可以得到fps

:這里是拿的fps。 即是將每幀的繪制時(shí)間轉(zhuǎn)換成了fps。

命令的運(yùn)行結(jié)果如下:

# The first line is the refresh period
# A) when the app started to draw 
# B) the vsync immediately preceding SF submitting the frame to the h/w 
# C) timestamp immediately after SF submitted that frame to the h/w
16954612 
7657467895508 7657482691352 7657493499756
7657484466553 7657499645964 7657511077881 
7657500793457 7657516600576 7657527404785
(...)

第一行表示:刷新時(shí)間間隔,
第二行第一列表示:app里數(shù)據(jù)(bitmap/material等)準(zhǔn)備時(shí)間
第二行第二列表示:cpu將數(shù)據(jù)傳遞給h/w(hardware)繪制時(shí)的同步時(shí)間。(這里可以理解為cpu和gpu繪制一幀時(shí),二個(gè)線程的同步時(shí)間)
第二行第三列表示:h/w(hardware)繪制完成的時(shí)間
后面的行和第二行一樣,會(huì)dump出128幀的數(shù)據(jù),也就是說一共有128行。
特別注意:這里的時(shí)間是指當(dāng)前時(shí)間距離開機(jī)的時(shí)間,并不是指的繪制的時(shí)間,單位都是nanosecond(納秒)

這些信息和gfxinfo中dump出的Draw Process Execute十分相似。
雖然有人寫了python腳本shell腳本,對(duì)以上命令進(jìn)行了包裝,可以方便的獲取fps,但是想作為測評(píng)軟件來說,是不可行的。因?yàn)槲覀兿胍慕Y(jié)果是點(diǎn)擊運(yùn)行按鈕后就可以顯示出每幀的繪制時(shí)間,而不是運(yùn)行腳本。

解決方案

既然我們已經(jīng)知道了獲取3D場景每幀繪制時(shí)間的方法,那我們就可以寫一個(gè)app來包裝這個(gè)方法,達(dá)到簡易測評(píng)的目的。
dumpsys實(shí)現(xiàn)原理可以知道,

adb shell dumpsys SurfaceFlinger --latency <window name>

命令的實(shí)現(xiàn),其實(shí)就是調(diào)用了surfaceFlinger服務(wù)的dump方法而已。那我們就先來找一下surfaceFlinger服務(wù)的dump是在哪里實(shí)現(xiàn)的

dump SurfaceFlinger實(shí)現(xiàn)包裝

文件:/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp中有如下代碼:

int main(int, char**) {
  ...
  // instantiate surfaceflinger
  sp<SurfaceFlinger> flinger = new SurfaceFlinger();
  ....
  // publish surface flinger
  sp<IServiceManager> sm(defaultServiceManager());
  sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
  ...
}

文件: /frameworks/native/services/surfaceflinger/SurfaceFlinger.h

    static char const* getServiceName() ANDROID_API {
        return "SurfaceFlinger";
    }

可以得知的是main_surfaceflinger的main函數(shù)運(yùn)行(也就是SurfaceFlinger服務(wù)啟動(dòng)前的入口)的時(shí)候,調(diào)用了ServiceManager的addService方法,將SurfaceFlinger.cpp注冊(cè)為了名字為"SurfaceFlinger"的服務(wù)。
所以最后的實(shí)現(xiàn)其實(shí)是SurfaceFlinger.cpp的dump方法。
等等??。urfaceFlinger.cpp??.cpp??
根本沒有辦法像封裝gfxInfo一樣,使用java的反射機(jī)制來實(shí)現(xiàn)SurfaceFlinger的dump方法啊,并且surfaceflinger服務(wù)和我們的app屬于不同進(jìn)程。
所以試圖包裝SurfaceFlinger的dump方法走不通。

shell腳本

網(wǎng)上有很多app demo可以執(zhí)行shell腳本,那我們可以寫一個(gè)類似的demo來執(zhí)行

dumpsys SurfaceFlinger --latency <window name>

命令嗎?不妨先試一試。

  1. 先寫一個(gè)shell腳本,hly.sh
#!/system/bin/sh 
dumpsys SurfaceFlinger --latency 
  1. push到data/local/tmp/目錄
adb push xxx/xxx/hly.sh data/local/tmp/

確保獲得了執(zhí)行權(quán)限

ls -l data/local/tmp/hly.sh
  1. 寫一個(gè)app來執(zhí)行hly.sh腳本。核心代碼如下
 process = Runtime.getRuntime().exec("sh");
 dos = new DataOutputStream(process.getOutputStream());
 for (String command : commands) {
       if (command == null) {
            continue;
       }
       dos.write(command.getBytes());
       dos.writeBytes("\n");
       dos.flush();
 }
 dos.writeBytes("exit\n");
  dos.flush();

其中commands的值是: /data/local/tmp/hly.sh

當(dāng)你滿心歡喜的期待正確結(jié)果的時(shí)候,卻得到如下輸出

Permission Denial: can't dump SurfaceFlinger from pid=26821, uid=10169

wtf?!!!!!!,只好再回過頭來看看SurfaceFlinger.cpp中的dump方法

status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
{
     ...
     if ((uid != AID_SHELL) &&
           !PermissionCache::checkPermission(sDump, pid, uid)) {
       result.appendFormat("Permission Denial: "
                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
     } else {
        ...
     }
     ...
}

原來只能有SHELL或者配置得有android.Manifest.permission.DUMP權(quán)限的app才可以dump surfaceflinger的信息。又因?yàn)镈UMP權(quán)限的配置必須是系統(tǒng)級(jí)別app,所以這條路也走不通

柳暗花明

至此,能想到的辦法都走不通了。
正當(dāng)陷入三方app到底能否獲取3D場景每幀繪制時(shí)間的時(shí)候,發(fā)現(xiàn)了一款十分厲害的三方軟件Gamebench,不需要root,能獲取4.1以上所有android系統(tǒng)的各類硬件,軟件,性能信息。
其中當(dāng)然包括3D場景的fps。它是如何做到的???!
由于篇幅原因,請(qǐng)點(diǎn)擊Gamebench 3D場景FPS獲取猜想。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容