1. 程式人生 > >Cocos2d-x 之效能檢測

Cocos2d-x 之效能檢測

OpenGL 效能指標

cocos2d-x 中有三個跟 OpenGL 相關的效能指標,遊戲執行時顯示在左下角;cocos2d-x 預設會顯示這些效能指標,可以手動在程式碼在開啟或關閉,C++ 專案在 AppDelegate 的 applicationDidFinishLaunching 函式中設定

Director::getInstance()->setDisplayStats(true);

lua 專案在配置檔案 config.lua 中設定

CC_SHOW_FPS = true
  • FPS(Frames Per Second)
    fps 是幀率,顧名思義就是每秒繪製多少幀。幀率設定得超高,畫面重新整理得越頻繁,遊戲看起來更順暢;但這也意味著每秒要做的運算更多,更加耗 CPU 或 GPU,而且如果運算量過大的話,可能會出現卡幀。一般遊戲的幀率不會低於 30 幀,實時性要求比較高的場景可以設定成 60 幀。這個指標可以幫助我們檢視遊戲在什麼時候計算量過大,然後降低計算量或分散計算到多個幀中去。

  • GL Calls
    gl call 是 opengl 渲染的次數,即每一幀呼叫 opengl 指令的次數。這個數字越小越好,優化的方向有

    1. 使用 SpriteBatchNode 來批量處理
    2. 將小圖片打包成合圖,載入到 SpriteFrameCache 中
    3. 不可見的元素設定為不可見,而不是設定透明度為 0

使用 SpriteBatchNode 是 2.x 的做法,3.0 之後官方不建議使用。這種方式要求所有 Sprite 都要先新增到 SpriteBatchNode 上,雖然能提升效率,但有很多限制,而且某些情況下反而會降低效率。比如有 Sprite 在螢幕外時,SpriteBtachNode 並不會作檢查,而是直接渲染所有的 Sprite;而直接使用 Sprite 的方式會判斷 Sprite 是否在螢幕外,如果在螢幕外則不渲染。3.0 之後直接使用 Sprite 也可批量處理,只要多個 Sprite 使用同張紋理並且使用相同的著色器和混合函式(SpriteBatchNode 也有這些要求),所以推薦直接使用 Sprite 而不是 SpriteBatchNode。

使用 SpriteBatchNode

local batch = cc.SpriteBatchNode:create("popcap.png")
for i = 1, 10 do
    local sprite = cc.Sprite:create("popcap.png")
    batch:addChild(sprite)
end
self:addChild(batch)
batch:setPosition(cc.p(win_size.width / 2, win_size.height / 2))

直接使用 Sprite

for i = 1, 10 do
    self
._icon=cc.Sprite:create("popcap.png") self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2)) self:addChild(self._icon) end

兩種情況的 gl call 都是 1

10個sprite

把圖片事先載入到精靈幀緩衝區並不影響 gl call,只是建立精靈時會快一些而已;但把小圖片打包成合圖,再載入到精靈幀緩衝區,則可以降低 gl call。

直接使用 Sprite

for i = 1, 10 do
    self._icon=cc.Sprite:create("popcap.png")
    self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
    self:addChild(self._icon)
end

for i = 1, 10 do
    self._icon=cc.Sprite:create("popcap2.png")
    self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
    self:addChild(self._icon)
end

20個sprite

使用 SpriteFrameCache

local sf = sfc:getSpriteFrameByName("popcap.png")
for i = 1, 10 do
    self._icon = cc.Sprite:createWithSpriteFrame(sf)
    self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
    self:addChild(self._icon)
end

sf = sfc:getSpriteFrameByName("popcap2.png")
for i = 1, 10 do
    self._icon = cc.Sprite:createWithSpriteFrame(sf)
    self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
    self:addChild(self._icon)
end

使用spriteframecache

第二種方式因為 popcap.png 和 popcap2.png 在同一個合圖裡,所以建立二十個精靈只需要繪製一次;而第一種方式 popcap.png 和 popcap2.png 是兩張不同的精靈,所以會繪製兩次。

對於螢幕外或者被隱藏的 UI,將其 visible 設為 false,這樣就不會繪製;如果設定透明度為 0,則還是會繪製。

self._icon = cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self._icon:setOpacity(0)
self:addChild(self._icon)

設定透明度

self._icon = cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self._icon:setVisible(false)
self:addChild(self._icon)

設定不可見

  • GL Verts
    gl verts 是指傳送給顯示卡的頂點數,這個數也是越小越好。頂點數直接與遊戲的顯示物件相關,一張矩形圖片一般繪製 6 個頂點,像上面的例子建立 10 個 Sprite 的時候頂點數是 60,建立 20 個 Sprite 的時候頂點數是 120。使用 SpriteBatchNode 或 SpriteFrameCache 都不能降低頂點數,只能實現批量渲染,減少繪製次數,但該繪製多少精靈就得繪製多少精靈,即使這些精靈使用同樣的貼圖。降低頂點數的方法是將看不見的元素設為不可見,不是設定透明度為 0,這點和 gl call 一樣,參見上面的例子執行結果。

總結

  1. 不使用 SpriteBatchNode
  2. 把小圖打包成合圖並載入到 SpriteFramecache
  3. 不需要的元素及時從顯示列表移除
  4. 看不見的元素設定 visible 為 false

整合 android-ndk-profiler

首先,從 android-ndk-profiler 上下載,直接 download zip 壓縮包或者使用 git

git clone [email protected].com:richq/android-ndk-profiler.git

下下來之後的目錄結構

|-android-ndk-profiler
    |-docs
    |-example
    |-jni
    |-test

我們要用的就是 jni 目錄下的檔案,在特定的目錄下新建一個資料夾 android-ndk-profiler,把 jni 目錄下的所有檔案拷到新建的資料夾下面。這裡說的特定的目錄是指 ndk 能搜尋到的目錄,我用的 cocos2d-x3.10,有兩種建立專案的方式,原始碼方式和預編譯庫方式,使用原始碼方式建立的專案 ndk 能搜尋到的目錄如下:

原始碼

使用預編譯庫建立的專案 ndk 能搜尋到的目錄如下:

編譯庫

總結起來就是 \%COCOS_ROOT%; %COCOS_ROOT%/cocos; %COCOS_ROOT%/external; %COCOS_ROOT%/scripting 這四個路徑。只不過原始碼的方式會在專案的根目錄下建立一個 cocos2d-x 目錄,然後把引擎的原始碼拷貝過來,因此 ndk 搜尋的目錄基於專案路徑。而預編譯庫的方式不會拷貝任何原始碼,因此 ndk 搜尋的路徑基於引擎安裝的目錄。
把 android-ndk-profiler/jni 下面的檔案拷貝到這四個路徑之一,比如拷貝到 %COCOS_ROOT%/external/android-ndk-profiler 目錄下,然後修改 android.mk 檔案,新增下面的程式碼

APP_DEBUG := $(strip $(NDK_DEBUG))
ifeq ($(APP_DEBUG),1)
  LOCAL_CFLAGS := -pg
  LOCAL_STATIC_LIBRARIES += android-ndk-profiler
endif
ifeq ($(APP_DEBUG),1)
  $(call import-module,android-ndk-profiler)
endif

然後以 debug 方式進行編譯,編譯成功說明 android-ndk-profiler 已經成功整合到專案了。編譯方式有

編譯方式

預設工程的編譯方式和 ndk 的編譯方式都是 debug,所以直接使用下面命令即可

cocos compile -p android

如果不想把 android-ndk-profiler/jni 下面的檔案拷貝到這四個路徑之一,而是想放在其它地方,則要擴充套件 ndk 路徑,在 android.mk 中新增

ANDROID_NDK_PROFILER_PATH := D:/work/project/frameworks
$(call import-add-path,$(ANDROID_NDK_PROFILER_PATH))
LOCAL_C_INCLUDES += $(ANDROID_NDK_PROFILER_PATH)

這樣就可以把檔案放在 D:/work/project/frameworks 目錄下了。

接下來就是在程式碼中使用 android-ndk-profiler 了,開啟 AppDelegate.cpp,新增下面程式碼

#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "android-ndk-profiler/prof.h"
#endif

bool AppDelegate::applicationDidFinishLaunching()
{
    //...
#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    monstartup("libcocos2dlua.so");
#endif
}

void AppDelegate::applicationDidEnterBackground()
{
    //...
#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    moncleanup();
#endif
}

monstartup 的引數根據具體的專案型別而定,我建立的是 lua 專案,所以是 libcocos2dlua.so,可以到 proj.android/lib/\armeabi 下檢視。

然後重新進行編譯,可能會出現下面的錯誤

jni/../../Classes/AppDelegate.cpp:82: error: undefined reference to 'monstartup'

這是因為在連結 android-ndk-profiler 庫時失敗,開啟 android.mk,新增

LOCAL_STATIC_LIBRARIES := cocos2d_lua_static
LOCAL_STATIC_LIBRARIES += cocos2d_simulator_static
# 新新增
LOCAL_STATIC_LIBRARIES += android-ndk-profiler

再重新編譯,可能會出現下面的錯誤

error

這是因為使用的 ndk 版本沒有 ucontext_t 這個型別,換了 ndk 版本就可以了,像我開始用的是 ndk-r10c,改用 ndk-r10e 就可以了。

還有一點要注意的,為了能正常生成報告,我們的遊戲必須有寫入檔案的許可權,開啟 AndroidMainfest.xml 檔案,看看有沒有下面這一句,如果沒有的話則加上

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

解讀效能分析報告

把 android-ndk-profiler 整合在遊戲之後,在 android 手機上跑一遍遊戲,會生成一個 gmon.out 檔案,這個檔案就是我們需要的效能分析報告。預設生成的 gmon.out 的路徑為 /sdcard/gmon.out,即放在內部儲存的根目錄。如果想自定義存放位置,則在呼叫 moncleanup 之前指定存放位置

setenv("CPUPROFILE", "/data/data/com.example.application/files/gmon.out", 1);
moncleanup();

把 gmon.out 拷貝到電腦上,這是一個二進位制檔案,無法直接檢視內容,得先轉換成文字檔案。ndk 提供了專門的轉換工具

cd android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/

./arm-linux-androideabi-gprof \
  專案路徑/proj.android/obj/local/armeabi/libcocos2dlua.so \
  存放路徑/gmon.out > gmon.txt

下面看看 gmon.txt 的內容

Flat profile:

Each sample counts as inf seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    
  6.52       inf      inf                             __addsf3
  5.98       inf      inf                             cocos2d::MathUtilC::transformVec4(float const*, float, float, float, float, float*)
  4.89       inf      inf                             inflate_fast
  3.26       inf      inf                             __mulsf3
  2.17       inf      inf                             cocos2d::Node::processParentFlags(cocos2d::Mat4 const&, unsigned int)
  1.63       inf      inf                             cocos2d::ComponentContainer::visit(float)
  1.63       inf      inf                             cocos2d::Node::visit(cocos2d::Renderer*, cocos2d::Mat4 const&, unsigned int)
  1.36       inf      inf                             cocos2d::Renderer::fillQuads(cocos2d::QuadCommand const*)
  1.36       inf      inf                             void cocos2d::Scheduler::scheduleUpdate<cocos2d::Node>(cocos2d::Node*, int, bool)::{lambda(float)#1}::operator()(float) const
  1.36       inf      inf                             adler32
  1.09       inf      inf                             std::_Deque_iterator<cocos2d::Mat4, cocos2d::Mat4&, cocos2d::Mat4*>::operator--()
  0.82       inf      inf                             cocos2d::ui::Button::adaptRenderers()
  0.82       inf      inf                             cocos2d::Director::drawScene()
  0.82       inf      inf                             cocos2d::Renderer::drawBatchedTriangles()
  0.82       inf      inf                             cocos2d::Node::isVisitableByVisitingCamera() const


             Call graph (explanation follows)


granularity: each sample hit covers 2 byte(s) for 0.17% of 5.99 seconds

index % time    self  children    called     name
                                                 <spontaneous>
[1]     19.4    1.16    0.00                 png_read_filter_row_paeth_multibyte_pixel [1]
-----------------------------------------------
                                                 <spontaneous>
[2]     15.5    0.93    0.00                 cocos2d::Image::premultipliedAlpha() [2]
-----------------------------------------------
                                                 <spontaneous>
[3]     14.5    0.87    0.00                 cocos2d::Texture2D::convertRGBA8888ToRGBA4444(unsigned char const*, int, unsigned char*) [3]
-----------------------------------------------
                                                 <spontaneous>
[4]      7.2    0.43    0.00                 profCount [4]
-----------------------------------------------
                                                 <spontaneous>
[5]      4.0    0.24    0.00                 png_read_filter_row_up [5]
-----------------------------------------------

解釋一下含義

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 函式     程式       函式       函式    函式     函式      函式名
 消耗     累計       本身       呼叫    平均     平均
 時間     執行       執行       次數    執行     執行
 佔程     時間       時間              時間     時間
 序運                                 (不      (包
 行時                                  包       括
 間的                                  括       被
 百分                                  被       調
 比                                    調       用
                                      用       時
                                      時       間)
                                      間)


           Call graph (explanation follows)


granularity: each sample hit covers 2 byte(s) for 0.17% of 5.99 seconds

index % time    self  children    called     name
 索引    函式     函式   函式的       被呼叫      函式名
 值      執行     本身   子函式        次數
        時間     執行    執行
        佔程     時間    時間
        序運
        行時
        間百
        分比

相關推薦

Cocos2d-x 效能檢測

OpenGL 效能指標 cocos2d-x 中有三個跟 OpenGL 相關的效能指標,遊戲執行時顯示在左下角;cocos2d-x 預設會顯示這些效能指標,可以手動在程式碼在開啟或關閉,C++ 專案在 AppDelegate 的 applicationDidFi

cocos2d-x淺析Hello World

source child 核心 內容 creat 哪些 項目 恢復 精靈sprite ***************************************轉載請註明出處:http://blog.csdn.net/lttree*****************

[寒江孤葉丶的Cocos2d-x旅_33]RichTextEx一款通過HTML標簽控制文字樣式的富文本控件

ast number blink js版本號 領取 size 創建 sub require RichTextEx一款通過HTML標簽控制文字樣式的富文本控件 原創文章,歡迎轉載。轉載請註明:文章來自[寒江孤葉丶的Cocos2d-x之旅系列] 博客地址

Cocos2d-xCCTouchDispatcher事件分發

使用過CCLayer的都應該知道,CCLayer的眾多父類中有CCTouchDelegate這麼一個類,他使CCLayer能接收touch事件成為可能。cocos2d-x的touch事件是由CCTouchDispatcher這個touch分發器類來進行派發的,所有需要接收to

Cocos2d-x下載安裝和配置

一、下載 1.Cococs2d-x下載地址 推薦下載cocos2d-x-v3.10版本,自帶建立專案的cococs軟體,就不用在cmd中敲命令了(不過敲命令還是顯得高大上一些)。 2.Android NDK和Android SDK的下載地址: 在

【玩轉cocos2d-x十二】plist解析工具:Anti_TexturePacker

之前拿了一些別人的圖片素材,是用TexturePacker打包合成的,結果寫程式的時候不知道每個合成前小png圖的名字是什麼,只能一個一個從plist檔案中找,然後猜測對應的名字,再進行顯示,如果不對,

【玩轉cocos2d-x三十九】Cocos2d-x 3.0截圖功能整合

3.0的截圖和2.x的截圖基本上相同,都是利用RenderTexture來處理,在渲染之前呼叫call函式,然後呼叫Cocos的場景visit函式對其進行渲染,渲染結束後呼叫end函式即可。只是3.0截圖需要在截完屏的下一幀才能處理RenderTexture,這點要注意。關

【玩轉cocos2d-x二十六】資料結構CCDictionary

CCDictionary在cocos2d-x中被大量的應用,比如CCTexureCache,CCSpriteFramCache等等。 1.實現原理 1.1.uthash CCDiction

【玩轉cocos2d-x三十四】繪圖:CCDrawingPrimitives和CCDrawNode

最近忙出翔了,這年過的也揪心。好久沒來更新部落格了,今天就來寫一寫cocos2d-x中圖形的繪製。 1.概述 其實cocos2d-x封裝了大量的opengl的繪圖函式,我們可以很輕鬆的在遊戲

【玩轉cocos2d-x三十】點九圖和輸入框的使用

登入介面一個帳號/密碼輸入框或者主角命名框是少不了的。這節就來了解一下點九圖的輸入框的使用。這裡只是介紹基礎知識,並不進行平臺的移植,也不處理跨平臺可能出現的問題。 1.點九圖CCScale9S

【玩轉cocos2d-x二十九】利用CCClipingNode做遊戲遮罩

新手引導是遊戲中必備的(除了奇葩的MT用一段動畫開始),也是玩家對遊戲的第一印象,重要性不言而喻。一般採用的遮罩的形式來突出引導重點,同時遮蔽其他功能。這裡簡單的介紹一下游戲遮罩的實現,並給出一個

【玩轉cocos2d-x二十二】多執行緒和同步02-售票

pthread有很多不同應用,官網都有相應的API解釋和Sample,這裡不再重複,本文主要介紹一個cocos2d-x多執行緒和同步示例。 1.售票 孫鑫老師的C++和Java多執行緒售票一直讓

【玩轉cocos2d-x二十三】多執行緒和同步03-圖片非同步載入

cocos2d-x中和Android,Windows都一樣,如果在主執行緒中處理一些耗時操作,那麼主執行緒就會出現阻塞現象,表現在介面上就是卡住,未響應等情況。為了避免這種情況的出現,我們需要在後

【玩轉cocos2d-x四十】如何在Cocos2d-x 3.0中使用opengl shader?

有小夥伴提出了這個問題,其實GLProgramCocos2d-x引擎自帶了。完全可以直接拿來用。先上圖吧。使用opengl前後的對比: 1.在cpp中使用openGL shader。 (1)新

【玩轉cocos2d-x三十七】粒子系統的載入優化

Cocos2d-x的粒子系統是通過載入plist生成的。plist包含兩部分內容:粒子系統屬性和粒子紋理。然而每次呼叫create都會對plist進行讀取解析,如果重複地使用同一個粒子效果,這樣的呼叫明顯是低效冗餘的。所以我們要做的是,將粒子系統屬性和粒子紋理分別抽出。 (

cocos2d-x碼農工作筆記 CCNode常用函式(2.0.4)

//版本cocos2d-x2.0.4 CCNode* node =CCNode::create();//生產一個CCNode*     node->getZOrder();//獲取節點繪製的順序     node->getPosition();//獲取節點在

cocos2d-x碼農工作筆記CCScrollView

【此文部分內容載錄 http://blog.csdn.net/xujiezhige/article/details/8558999】 近期工作中要使用CCScrollView,但是網上相對的資料比較

cocos2d-x物理引擎box2d(2)

小滿(bill man)個人原創,歡迎轉載,轉載請註明地址,小滿(bill man)的專欄地址http://blog.csdn.net/bill_man 由於box2d的內容比較多,它也有自己的testbed例子,所以關於比較深入的box2d引擎內容,我準備單開一個專題去研

Cocos2d-xLUA指令碼引擎深入分析

 另:本章所用Cocos2d-x版本為:          大家好,又是一週過去了,這一週忙的有點焦頭爛額,除了工作照例每天加班到九點外,工具箱又做了大幅改進,新的論壇遊戲兔子game2z也上線了,Cocos2d-x的學習時間被壓縮的很少了,現在是凌晨一點零六分,看著妻子睡熟的樣子,我也只能告訴自已

android ndk 崩潰捕獲(cocos2d-x android崩潰捕獲)

ndk 崩潰捕獲 ,我們可以採用 breakpad是一個跨平臺的c++崩潰處理系統。包括:dmp生成模組、 上傳模組、 伺服器儲存模組、解析dmp模組 等。 這裡我只大概說一下dmp生成模組。 1、編譯靜態庫解壓並拷貝breakpad原始碼目錄到專案中,編譯: 指令