Debug经验总结:优化、程序员和概率
GameRes游資網授權發(fā)布 文 /顧煜
時間有關的Bug
所有的console平臺,都有一個邪惡的要求:需要做Aging Test。簡單來說,就是這些游戲機游戲是要放在店里面賣的,可能商家會把試玩游戲放在外面,很久都沒有人玩,你的游戲不能Crash,否則顧客想玩的時候發(fā)現(xiàn)游戲Crash了,不會怪罪開發(fā)者,而是會認為這個主機不穩(wěn)定。所以游戲機廠商都要求開發(fā)商的游戲要長時間運行不能Crash,通常都要求8個小時左右。我們一般的做法就是,在很久沒有檢測到玩家的手柄輸入信息以后,就進入一個小的死循環(huán),把畫面暗下來作屏保狀,循環(huán)里面只檢測輸入,有輸入就退出這個狀態(tài)。因為主邏輯不動,復雜的代碼都不運行,自然就安全。
看似簡單的aging test,被時間溫柔的手撫過,死機了運行的游戲,愁白了開發(fā)者的頭發(fā)。
那天來了這么一個bug,描述便很科幻很文學,說在某一個場景,有山有水有敵人的地方,主角躲在某個敵人無法攻擊的地方,敵人和坦克都會不停地開火。測試兄弟做完這一切便無情地離去,留游戲主角在那里看一夜云起云落,流彈共長天一色。第二天早上一來,操作主角一轉身,就Crash了。有詞為證:驀然回首,bug卻在燈火闌珊處。
我也不驚慌,打開VC,Attach到Crash的Xbox360 kit,一看,是更新某個旗幟(softbody做的)的時候,旗幟的Bounding Box太大,被assert掉了。Bounding Box本不該這么大的,看了看所有的頂點,位置都離原點很遠。為什么呢?Softbody旗幟更新的時候,會有約束處理,每幀都會把頂點往中間拉一下,讓頂點們團結在原點周圍。
第一步自然是試著重現(xiàn),每天下班就照描述方法重現(xiàn),機器開著回家,試了幾天,終于可以穩(wěn)定重現(xiàn)了,每次Crash也是同一個地方。
靜下心來,認認真真讀了一遍Softbody的頂點更新代碼,覺得沒什么問題,只好加了些日志,打印幾個頂點的坐標。第二天果然又Crash了,輸出了1G多的文本日志,在pc查看日志。發(fā)現(xiàn)中間部分頂點位置都很正常,直到Crash前最后幾幀才急劇變大,最后觸發(fā)assert。
下班前又設好環(huán)境,第二天在觸發(fā)Crash前,加好了條件斷點,當頂點x坐標大于特定值的時候就斷下來。然后操作主角轉身,VC馬上停下了代碼執(zhí)行。仔細看看,找到了原因。原來Softbody會受到外力,比如手雷或炮彈的爆炸,然后把外力加到頂點上面,改變一下頂點的位置。另外,我們有優(yōu)化,對于看不見的Softbody,我們不會去更新它的頂點,這樣可以快一些。問題在于,每一次那輛坦克開炮,都會炸到那面旗幟,我們就不停地把那個沖量加到了旗幟受力上面。通常每次更新Softbody我們會把受力加到頂點上面,然后把那個變量清零準備接受下一幀的沖量。但這次很不幸,由于更新的優(yōu)化,這個Softbody在主角背后,沒有被更新,那個記錄受力的矢量沒有清零。經過一個晚上的炮轟,積累了很大的值,主角一轉身,Softbody被看見,就更新,巨大沖量的矢量呼嘯而來,更新了頂點數(shù)據,導致頂點被更新到很遙遠的地方了。
知道原因就好辦了,在加沖量的時候,設個上限,超過上限部分一律忽視即可。改動,測了幾個晚上,似乎正常,收工。
可得結論:優(yōu)化靠不住
造成最大損失的bug
2003年,PS2時代,我們用Unreal做一個FPS游戲。PS2性能太低,導致我們游戲多人玩的時候,作Server的那個玩家?guī)瑪?shù)很低,幾乎無法玩。
我們針對這個問題作了AI高層、物理底層、網絡通信層的代碼優(yōu)化,最后,在開發(fā)人員這里,似乎能夠支持8個玩家了。
于是我們讓測試人員來測4v4,可是他們每次都說性能不理想。在發(fā)布最終版本前兩天,我們緊急決定,不支持4v4了,改成3v3,這樣性能就沒問題了。程序員總是這么睿智,老板總是這么英明。
在做Master版本前的最后一天晚上,游戲賬號拍賣平臺遠處傳來某個程序員撕心裂肺的慘叫:"Release版本下面的代碼優(yōu)化沒有打開!"原來如此,某人某次為了便于調試,把Release里面的代碼優(yōu)化關了,然后他不小心又上傳了這個項目配置文件。我們測試的版本比較老,都是開著優(yōu)化的,所以4v4沒有問題,做版本給測試人員測的時候用了最新版本,性能就不行了。
既然沒打開優(yōu)化,打開不就皆大歡喜了?沒那么簡單,打開以后優(yōu)化的執(zhí)行文件會多占用2M的內存,PS2上面內存本來就很少,我們的運行時留的內存只有1M。如果早些發(fā)現(xiàn),還可以讓關卡制作和美工去省點內存出來。都快發(fā)版本了,我們到哪兒找這多出來的2M?
最后,我們很屈辱地放出了一個本可以支持4v4,但陰差陽錯變成只支持3v3的版本,而且PS2的游戲,你也沒有機會出Patch來彌補。
可得結論:程序員靠不住
概率
開篇說的Gamesutra上的Dirty Coding Tricks,里面有一篇特別神。
他們有一次準備發(fā)布版本了,臨發(fā)前手賤,加了一個文本文件打包,結果就一直在游戲加載時 Crash。查了一下,發(fā)現(xiàn)資源管理里面的文件標識符沖突了,新改的文本文件和另一個文件標識符一樣了。神奇的地方在于,那個標識符是64位的,前32位是文件名和相對路徑的CRC32,后32位是整個文件內容的CRC32,這都能沖突...修改方法很簡單,打開文本文件,加一個空格,存盤退出。
我看后深受啟發(fā),得出結論是,概率也靠不住。
總結
綜上所述,我們順利得出了結論,什么都靠不住。
但那也不意味著面對bug,程序員就手足無措。為了要修復bug,我們需要的,并不是愛和正義,而是你,最勤勞勇敢的程序員。對于Debug,我們有這樣一些看法:
- 不要懷疑工具、SDK和OS,先懷疑自己的代碼有沒有問題。以前做PS1游戲的時候,Sony的編譯器經常會編譯錯代碼,搞得我們開發(fā)人員都迷信了,碰到詭異問題無法解釋就歸于迷信活動,燒個香再rebuild一下...可是這些年來這類情況越來越少,99.999的情況下那些奇怪的bug都事出有因。承認這一點,并耐心的去看這個bug,而不是到處亂改亂試,能省下好多時間。
- 善用工具 Vtune, Perfhud等等等等工具都能給你很大幫助。前面說的那個多線程降速Bug,如果有目前常用的Windows Performance Toolkit,加上GPUView,應該是秒殺的級別。很多時候問題不好解決,是沒有好的工具。
- 在游戲里多留Debug輔助代碼和profile代碼
- 日志是你的好朋友,太多bug無法直接斷下程序來重現(xiàn),等重現(xiàn)了往往現(xiàn)場又沒了,只有日志才能幫助你追蹤bug。
- 多線程是魔鬼,我遇到過最難查的bug有80%和多線程有關,不要低估多線程程序的調試難度。
- 易重現(xiàn)是Debug的第一步,很多bug之所以難查,是因為重現(xiàn)條件苛刻,可能是非常隨機,可能是要玩非常久才能重現(xiàn)。如果一個bug重現(xiàn)概率是25%,那修復它的難度比重現(xiàn)概率是100%的bug不是難4倍。對于100%重現(xiàn)bug,為了驗證一個想法,你只需要嘗試1次;可對于25%重現(xiàn)概率的bug,你嘗試4次是遠遠不夠的,萬一這4次都沒重現(xiàn)呢?你并不知道是你的改動生效了,還是根本這幾次就沒重現(xiàn),所以你必須試上10多次,保證那25%的情況被觸發(fā)到了。如果可能,盡量試圖簡化bug重現(xiàn)條件。這是第一步,也往往是最重要的一步。
- bug產生的地方和爆發(fā)地方越近越容易調試,因為現(xiàn)場都容易看見。很多AI行為難調試,就是出問題的地方離實際能看見的bug差很遠,時間無法回溯,現(xiàn)場已然消失。所以不要吝嗇assert,一個成功的Crash在現(xiàn)場會讓你省很多力。注意積累,多思考多總結。比如像我這篇文章,記下來,分享之。一點點運氣 運氣是必需的,運氣也是實力的一部分,而且運氣會光臨執(zhí)著的程序員。
- 多人協(xié)同工作可以幫助你。叫幾個同事一起看,很多思路都是交談的時候整理出來的,哪怕你只是給別人復述一下某些代碼的邏輯都有可能讓你豁然開朗。
- 了解匯編,底層,執(zhí)行Script的虛擬機 對于一個難重現(xiàn)的bug,一個Crash現(xiàn)場很難得,往往是自己或是測試同事數(shù)小時到一天的努力成果。對于這里難重現(xiàn)的bug,每一個現(xiàn)場都要珍惜,很多信息往往不容易找到,特別是Crash在Script虛擬機里或者在高度優(yōu)化過的Release版本里面。平時要注意多積累底層的知識,這樣才能在每一次Crash后充分利用不完整的現(xiàn)場,不浪費重現(xiàn)bug的工作量。
- 保持良好心態(tài) Debug是一件很艱苦的事情,尤其當你幾天都找不到線索的時候。以前Leader講過,他覺得Debug很有意思,因為每個Bug都是一個謎題,都有原因,把它看成是一個挑戰(zhàn)。追查一個問題多日,沉浸其中,終于有一天找到原因,由此而得到巨大成就感,這不就是吸引我們做程序員的一大原因?
我始終覺得,一個程序員Debug能力和優(yōu)化能力的高低,很能體現(xiàn)他的水平,越強的程序員,越能在不可能處柳暗花明。Debug時那些靈光一閃的頓悟,需要長期浸淫在問題中,需要廣博的知識面,需要充分的想象力,長期調試疑難bug后,你會發(fā)現(xiàn)你對系統(tǒng)底層,對效率,對其他模塊,都會有更深入的了解。
希望大家都能在debug中有所收獲。
總結
以上是生活随笔為你收集整理的Debug经验总结:优化、程序员和概率的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 游戏服务端的逻辑分服与物理分服
- 下一篇: 那些年,我在游戏开发中改过的bug:坑爹