饑荒遊戲掃雷筆記(五) | 性能分析篇——原來問題不止那麼多

系列文章鏈接:

饑荒遊戲掃雷筆記(一)|腳本引擎篇——LuaJIT的救贖(合集) - paintsnow的文章 - 知乎專欄

饑荒遊戲掃雷筆記(二) | 腳本引擎篇——偷懶的高溫陷阱 - paintsnow的文章 - 知乎專欄

饑荒遊戲掃雷筆記(三) | 渲染篇—— 當馬車駛上高速公路 - paintsnow的文章 - 知乎專欄

饑荒遊戲掃雷筆記(四) | 渲染篇——VBO緩存 - paintsnow的文章 - 知乎專欄

============================

寫了四期PATCH的實現,本期來一次性能分析,看看優化的效果究竟如何。

0x01 測試計劃

我採用Visual Studio 2015自帶的Performance Profiler來跟蹤饑荒遊戲的運行情況。遊戲配置如下:

1. 存檔:一個Shipwrecked DLC的存檔,季節為颶風季,測試時間從遊戲時間的入夜到第二天天亮,伴有狂風、大雨和高頻率的閃電。之所以選擇這樣的設定,是因為在我的正常遊戲體驗中,這種情況下是最卡的。以前我往往通過控制台在屏幕上刷出大量生物來製造卡頓,但是這種卡頓瓶頸單一,不能有效檢測出其他卡頓的原因,而且這種卡也一般不是正常遊戲過程中所能遇到的。

2. 遊戲版本:新下載的某網站盜版饑荒遊戲172748版(大約是2016年6月份左右的版本)。選用這個版本也是沒有辦法,因為我的Steam正版饑荒在啟動時,如果不是由Steam啟動的,將會退出並通知Steam來啟動自己。這樣Visual Studio 2015的Profiler就沒辦法測到遊戲運行過程中的數據了。由於正版饑荒在運行時還會和Steam之間有通信(比如ALT+TAB打開的界面),因此通過hack的辦法讓它無視父進程而進入遊戲可能會有問題。

3. MODS:一般的常用mods,包括幾何學、行為隊列、智能鍋、小地圖、建築標記等。

4. 測試計劃:分為四種情況進行測試:

1) 不開啟luajit以及gl優化

2) 只開啟gl優化

3) 只開啟luajit

4) 開啟luajit以及gl優化

5. 為了有效對比lua和luajit的性能,在測試原版lua的時候,我也像luajit那樣進行了hook,只不過把lua51.dll重命名為luajit.dll,這樣所有的lua請求就可以重定向到原版lua里了。

6. Visual Studio 2015 Performance Profiler: CPU sampling

0x02 小地圖要壞大事情

在最初的測試中,我發現一個比較奇怪的情況,那就是dontstarve_steam.exe的佔用有點異常地高,而gles和luajit的佔比較低,只有個位數。經檢查發現:

dontstarve_steam.exe有個名字為0x1035A6的函數居然佔用了總CPU採樣的45.77%!這個函數是做什麼的呢?

打開OllyDBG看一下:

(由於每次dontstarve_steam.exe載入的基地址不一樣,所以0x1035A6得先加上基地址差才能得到本次的地址)

這並不是一個函數的開頭,但是卻像是一個返回地址。我們知道函數首地址在堆棧中是不存的,存的是調用時的返回地址。因此這個0x1035A6(0x9135A6)實際上代表的是上一行call指令調用的函數。

那麼進入這個函數看看:

這個函數比較長,而且充斥著大量浮點和循環指令。從這點推測應該是一個比較複雜的CPU端的計算函數。果然在函數的最後,一條用於列印調試信息的字元串透露出這個函數所在的源文件名叫MiniMapRenderer.cpp。也就是說,這個負責在CPU上渲染小地圖的函數佔去了大量CPU時間。

在原版饑荒中,按TAB鍵可以呼出小地圖。但是按道理它不應該這麼頻繁地被調用,唯一的可能就是小地圖MOD使用了這個函數來頻繁渲染Minimap(因為要實時更新地圖上的單位變化情況),並且以HUD的方式常顯在了遊戲界面。

進入遊戲後關掉小地圖顯示,果然再測時這個函數就不佔用那麼高的CPU了。以後會考慮優化這個函數,畢竟Minimap MOD還是非常方便好用的~

0x03 性能報告

重新測試並輸出報告如下:

(從左到右分別為不啟用luajit及gl優化、只啟用gl優化、只啟用luajit、啟用luajit及gl優化)

可以看出,在啟用luajit之前,腳本引擎部分使用的樣本數為15.7%左右,啟用後為11.2%左右,也就是腳本部分的性能提升約40%。當然在我的測試場景為了能檢測到儘可能多的性能問題,活動腳本所佔用的比例並不高。

GL的優化在這張圖上似乎看不到效果。因為我只優化了buffer數據的傳輸,沒有實質地減少glDrawArrays的調用,因此nvd3dum的佔用還是非常高。

比較意外的是fmodex.dll居然佔用了12%的採樣。fmodex.dll是FMOD音效引擎的模塊,用於播放和實時混縮fsb格式的音樂。測試場景中的雨聲和雷聲不斷,導致此模塊被頻繁調用。雖然fmodex在非雷雨場景中CPU比例幾乎為0,但是在雷雨中能佔到12%的CPU採樣比重還是比較神奇的,有空再研究。

dontstarve_steam.exe中指向的入口地址為0x8B4560函數佔用了其幾乎全部的採樣,用OllyDBG看了一眼,這個就是饑荒遊戲的主消息循環。

0x04 小結

這次的性能測試發現了很多以前沒注意到的細節,就目前而止,性能問題主要有以下幾個:

1. glDrawArrays等GL函數頻繁調用,使得nvd3dum.dll的使用率很高。

2. Minimap MOD在繪製小地圖HUD時頻繁調用饑荒的DrawMinimap函數,導致性能急劇下降。我後來專門針對它測試了幾次,它佔用的時間甚至是luajit的1.5倍,和lua引擎本身的耗時都差不多。

3. FMODEX音效模塊在雷雨天氣時非常吃CPU。

4. Lua自身的性能問題。

推薦閱讀:

TAG:性能测试 | DontStarve游戏 | luajit |