我們用50次遊戲性能的深度優化,總結出了五條「毒雞湯」

原文鏈接:我們用50次遊戲性能的深度優化,總結出了五條「毒雞湯」 - Blog

今天的推文有點不一樣,可以說並不是一篇嚴格意義上的技術文章,落筆成文的此時,我們即將完成第50次性能的深度優化。這50次深度優化的經歷,讓我們侑虎團隊對性能優化有了更深刻的理解和感悟。今天我在此和大家分享,希望也能對大家自身項目的研發有所啟發。

一、答案永遠在現場

「我們遊戲一個多月後就要上線了,但現在性能問題還是很大,現在我們在這塊沒什麼頭緒,你們是否有什麼服務可以幫到我們?」

「我們知道你們侑虎為XX遊戲做過深度優化,我們項目也想來用你們這個服務,請務必幫幫忙。」

「你們的報告分析得很贊,內存終於降下來了,這下我就放心了。接下來,我們團隊會按照你們的報告繼續優化其他地方。」

「你們分析的太細了,我們已經優化很久了,沒想到還能找出這麼多問題。」

這些是創業20個月以來,我們從遊戲團隊那裡聽到最多的幾句話。上文所說的報告,是指我們侑虎科技的項目深度分析與優化方案報告。之所以寫這篇文章,是因為我們即將完成我們的第50次遊戲項目的深度優化。是的,你沒看錯,20個月50次,意味著平均一個月2.5次。平均每份報告100頁、2.3萬字。

對於一款遊戲項目的深度優化,我們一般需要10天左右的時間全身心投入,其中包括2~3天的現場排查。這是因為很多時候,只有進駐現場查看代碼,設身處地地與研發團隊進行溝通,我們才能找到問題背後的真正答案。

舉個例子,UI優化是一項非常複雜的工作。兩個視覺表現完全一致的界面,其底下的性能開銷可能完全不一樣。究其原因,是其本身在Editor中的製作手法不同導致。

「動靜分離」是我們經常提到的UI優化解決方法,但是知易行難,難在如何定位到底哪些動態元素造成了較高的開銷,如何判斷哪些開銷是可以避免的,如何分離這些UI元素等等。所以,我們駐場的一個主要工作就是檢測其UI界面的製作方式,將有問題的UI元素全部找出,並針對不同類型的UI元素給出不同的解決方案。同時,我們還會現場對UI界面進行一定的修改,告訴大家通過合理的優化後,項目的UI耗時應該是如何變化的。

下圖就是我們在一款二次元ARPG項目中,UI優化前後WaitingForJob的性能對比開銷。

再舉個例子,堆內存泄露是大家項目中經常遇到的問題,這也是我們駐場時經常花費大量氣力去解決的問題。一方面,我們需要通過閱讀研發項目中的大量代碼去定位可能存在的泄露點,因為很多時候,內存泄露都是因為Object被「到處索引」所致。另一方面,我們需要研發團隊的配合,對代碼進行完善並快速出包驗證,這樣反覆調試後,泄露問題就能基本得到解決。

下圖是我們對某項目的堆內存泄露問題優化前後的對比圖,從發現到解決,一共不到24小時。

然而,如果我們沒有到現場,會怎麼樣呢?

如果沒有到現場,我們也許到現在都不知道為什麼下圖中的賽車(紅框處)已經和外圍的圍欄和斜坡產生了碰撞,儘管實際上它們還相距很遠。

如果沒有到現場,我們也許到現在也無法告訴研發團隊,如何僅用兩小時,將下面的UI面板從38個Draw Call優化到9個Draw Call。

如果沒有到現場,我們也許至今都未發現幾個簡單的CharacterController的center賦值會如此耗時。

如果沒有到現場,我們也許至今都無法解釋,在場景切換的過程中,為何會出現如此大量的「空閑」時間。

類似的如果非常多,所以我們必須到現場。答案在哪裡,我們就在哪裡。

二、別放過任何一個可疑的地方

別放過任何一個可疑的地方,因為那很可能是提升你項目效率的絕佳機會。

舉個例子,我們在做UI優化時會做一個常規測試,就是把遊戲靜靜地放在那裡,不去操作,看看UI性能的變化。可以看到,在UI界面靜止不動時,其對應函數的CPU佔用仍然有2~3ms的開銷。雖然耗時不高,但這已屬於不正常的情況。所以,在到達現場後,我們詳細檢測了其耗時的具體根源,最後發現元兇是聊天框中的emoji表情:每隔1~2s都會轉動一次,但由於其本身掛在一個很大的Canvas上(下圖右),導致了每次emoji表情一改變,就會使得這個含有1804個頂點的Canvas完全重建一次,從而造成了較長的時間開銷。

上述這種操作,也是UI界面中動靜元素沒有分離的一種典型例子。

再舉個例子,下圖是一個MMO項目某場景的一部分性能測試數據。值得注意的是,遊戲在運行過程中改變了RenderSettings的參數,這一操作耗時巨大,703幀中耗時8600+ms,但我們在其他測試中卻沒有再發現該項耗時。這個反常的現象引起了我們的關注,所以我們在該場景中又跑了五組測試,每組大概15~20分鐘,然而都同樣沒有發現這個開銷。於是,我們請來了項目主程,通過製作上的溝通希望得到更多線索。當我們表達了我們對於這個問題的發現時,項目主程非常驚訝:「你們居然測到了這一項,但我真沒想到這塊會這麼耗時。」原來,這個操作是用來改變場景的天氣效果,而且一天只進行兩次,一次只有30秒。

三、空杯心態,經驗歸零

我們正處於一個高速發展的時代,每個人的知識和經驗在整個行業面前都可以說是微不足道。我們做過的優化越多,就越發現我們已知的渺小。有那麼幾個項目,我們在進駐團隊前以為已經大致摸清了優化的方向,但等到了現場,面對他們的代碼時,才發現我們之前推測的都是錯的,一切都要推倒重來。

舉個例子,下圖是一款競技類手游的動畫系統在真機上的CPU耗時。可以看到,其每隔幾幀,就會有一個20~30ms的CPU開銷。

這顯然是不正常的,進駐團隊前,我們認為很可能是該項目中手動調用了一些Animator的API,按照經驗來看,檢查下代碼應該很快就能定位問題。但沒有想到的是,我們花了大量時間都未發現任何一行與動畫模塊相關的可疑代碼。與項目團隊的交流也否定了我們之前的想法。我們開始懷疑是不是我們的檢測工具出了問題,但是項目中通過其他方式獲取的運行幀率卻又和這個開銷非常吻合。更詭異的是,即便我們把動畫角色屏蔽了,該耗時依然存在。這個時候,我們開始隱約覺得這個問題很可能不是出在動畫模塊上了。

既然問題不按套路出牌,那我們也就不能按照常規方法來解決了。第二天我們在開發團隊的協助下,一起逐步對項目的各個模塊進行拆分,看看這個問題到底出在哪裡。具體經過曲折坎坷,就不贅述了。結果令我們相當驚訝,該CPU耗時居然與通過Android原生代碼獲取遊戲的電量、Wifi Ping值的操作相關。當我們把該操作關閉後,一切都恢復了正常。下圖就是正常的動畫模塊開銷情況。

這個問題,我們後來在自己內部復盤時仍然覺得匪夷所思。我們也有對相關代碼嘗試進行復現,但是在我們的空項目中,一切正常。

這個例子不過是我們在現場遇到的眾多幺蛾子問題之一。隨著這些經驗的累積,我們也漸漸發現,影響性能的已經不再僅僅是大家的代碼編寫問題、引擎API的使用問題,還會和所用的引擎版本、所處的硬體、OS版本,甚至設備的運行狀態息息相關。

如果你耐著性子看到了這裡,我敢說你肯定也遇到過以下這些情況:

1)一些問題只在我的項目中出現,而在空場景的項目中則沒問題;

2)一些問題只在Android或iOS系統中出現,而在另一系統中則不會有;

3)一些問題只在某些移動設備上頻繁出現,其他設備卻都沒有。

諸如此類的不確定性問題,在當今的項目研發中比比皆是。如何解決?將心態放空,將經驗歸零,多做實驗,以數據說話。

四、沒有標準的優化方案

我們經常會被問到:渲染的耗時怎麼下降、UI模塊怎麼優化、如何提升載入效率等問題。對此,我們的回答往往是:

沒有標準的優化方案,只有最適合你項目的優化方案。一切的解決辦法都是圍繞著具體問題而產生的。

舉個例子,渲染模塊開銷高,其優化的前提是一定要定位清楚,究竟是什麼造成它這麼高的耗時,瓶頸是不透明渲染、半透明渲染、裁剪、圖像後處理還是其他?只有定位準確了,才能制定出行之有效的優化方案。正所謂,對症下藥,才能藥到病除。

再舉個例子,大家都知道Draw Call越高,開銷越大。但是否越低越好呢?當然不是。UI Draw Call就是一個很好的例子。在一個項目中,我們建議研發團隊將UI的整體Draw Call從當前的9拆成20。研發團隊很不理解,DrawCall多了不是耗時更多?確實如此。但是該團隊為了降低Draw Call將大量UI元素拼合在一起,雖然渲染開銷下降了,但UI重建的開銷卻大大提升了。在我們來看,當UI Draw Call拆到20時,雖然渲染模塊的開銷可能會平均增加1ms,但UI重建的平均開銷則會下降5ms。從整體性能而言,至少能有4ms的提升。

五、壓力越大、收穫越大

性能優化本身就是一件很難的事,它一般需要優化人員具有很紮實的功底、很全面的基礎以及很豐富的實戰經驗。而如果要在一個完全陌生的項目中,十天內就給出一份詳盡的性能優化方案,則更是難上加難。

回想我們這麼多次的現場實戰中,沒有一次是順風順水的,在每個項目中都會遇到一些意想不到的技術問題。甚至有幾次,我們內部已經做了決定:「如果今天晚上這個問題還是找不到根源,我們就退款走人」。這就是我們每一次都要面對的壓力。幸運的是,每一次我們都跨了過去。同時,每一場深度優化後,我們都會進行復盤,這次優化中哪些地方還有待提升,就嘗試能否繼續打磨我們的優化工具,縮短優化的時間;哪些地方做得很高效,就看看能否複製到線上的測評工具中去,讓更多團隊受益。

當然,我們每次收穫的不止是經驗,更重要的是又多了一些信任我們的朋友。彼此的信任,讓我們的腳步能夠涉足更多的地方,看到並解決更多的技術問題。

曾經有位朋友和我說,「優化的方法茫茫多,然而針對於我們項目的優化方法在千種萬種中可能只有一個」,這也許是大部分遊戲從業者的痛點。所謂」優化「,能夠解決「你的問題」才是優化。

PS:時間過的好快,一晃創業已經二十個月了。下圖是2015年因為一個感觸給自己加的一條夢想。現在在機場、火車站、地鐵上甚至是電梯里都可以時不時看到我們優化過的遊戲了。所以夢想還是要有的,萬一實現了呢!

這是我們第一次嘗試以故事的形式和大家分享了一些深度優化的心得,希望能對程序、策劃、美術、製作都能有所啟發。如果上述的文字有幸能契合你的某些想法,亦或許你也有一些深刻的經歷願與大家共享,我們歡迎你在下方留言。


推薦閱讀:

【求知探新】《為誰而煉金》UI界面載入性能分析
多個提高Node.js應用吞吐量的小優化技巧介紹
【譯】針對 Airbnb 清單頁的 React 性能優化
記一次冷雨寒風中的UWA優化日(內附技術PPT)
Unity優化技巧(上)

TAG:Unity游戏引擎 | 性能优化 |