大概就是,一個if迴圈19.8億次,而且7年沒人敢動....
真事,就出現在知名遊戲大廠R星的知名大作 GTA 5 中。
而且,19.8億次的if迴圈,今天仍然在世界各地的玩家cpu上跑著。
————————————————————————————————————————————
3月16日更新:
GTA 5「屎山」程式碼後續來了。
R星終於官宣準備修復了!
主動改善玩家遊戲體驗?不存在的。
要主動,哪裏還要等七年?
這篇揭R星老底的貼文在全網大火後,R星不得不出面應對。
在和黑客大哥聯系後,R星認可了他的改進方法,宣布在後續更新中修復相關問題,並且還慷慨的給他付了一筆 1萬美元 的獎金。
鑒於R星失誤實在太低階太離譜,而這位老哥的方法又太有效,以致無數玩家稱他「功德無量」。
如果平均給每個玩家節省10秒,全球500萬玩家一天就能節約5000萬秒,一年中,節約的總時間大概能有數十年。相當於挽救了十多個人的生命!「事了拂衣去,不留功與名」,這位黑客大哥被無數玩家膜拜。當然大家也不忘再把R星拖出來「鞭屍」。
有人吐槽,GTA 5僅2020年就買了2000萬份,累計銷量更是達到1.4億份,R星每年都能從這個計畫上賺數億美元,但是卻不肯花幾分鐘去解決這麽一個低階錯誤,實在可恥。
還有人抨擊R星幾乎從不與玩家社群互動,玩家提的意見也從來充耳不聞,直到這次被被黑客嘲諷打臉,才不得不出來表態。
事後,黑客大哥還透露了一絲身份資訊,原來他人在拉脫維亞。
拉脫維亞是波羅的海國家,原來是前蘇聯加盟國之一。在網上搜尋相關資訊,可以發現「拉脫維亞黑客」,幾乎是和俄羅斯黑客一樣傳奇神秘的存在。
有網友爆料,在拉脫維亞,普通程式設計師薪資平均3-4k歐元(23000-31000人民幣)。
而他領到的這1萬美元獎金,相當於三四個月薪資了。
提前領了一筆「年終獎」,黑客大哥表示很開心。同時他也說,將密切關註GTA 5未來更新,一絲不茍的檢查修復情況。
不知道他還能不能從R星領走更多獎金
(註:所謂「屎山」,是程式設計師間流傳的一個梗,指陳年累月且復雜低效的程式碼,因為改動成本巨大,所有人避之不及。)
——————————————————————————————————————————
GTA 5「屎山程式碼」前情回顧:
一支煙的功夫,
GTA 5線上版
終於開啟了。
「7年了!GTA 5線上版載入還是這麽慢??」
△
Please wait forever to play
Reddit、Steam、HackerNews上,無數玩家吐槽抱怨……
進遊戲少則等5、6分鐘,多則20分鐘。
終於,一個黑客大哥實在忍不了,用逆編譯器逐條檢視執行情況,終於找到原因。
原來,R星(遊戲開發商RockStar)寫的程式碼太低效,載入時,一個if語句竟然迴圈了19.8億次….
幕後黑手:誰占用大量時間?
載入GTA 5 Online到底有多慢?
△
硬體拉滿的土豪玩家請無視
Reddit相關板塊發起的調查中,超過80%的玩家,都要等3分鐘以上,有的甚至超過15分鐘。
而且,從7年前Online上線到今天,這個情況絲毫沒有改善。
暴躁的,已經罵起了臟話……
但奇怪的是,如果你選擇是故事模式(單機版),載入就會快很多,感覺甚至像兩個不同的工作室開發的遊戲。
具體到這位黑客大哥的例子,他自己的硬體配置如下:
CPU,是老而彌堅的AMD FX-8350,2012年上市,采用「推土機」架構,超頻潛力驚人。
顯卡還是GTX 1070。
這樣今天看起來老舊的配置,開啟單機版GTA 5需要1分10秒,而載入線上版則6分鐘起。
黑客大哥用了最簡單的Windows工作管理員,來判斷線上版GTA 5在啟動時,都呼叫了哪些電腦資源。
在1分鐘的時間分界線上,之前是載入的是單機和線上版通用的基礎內容,之後是線上版獨有的內容。
可以看到,線上版GTA 5,載入時呼叫大量CPU資源至少長達4分鐘之久。
而同時,記憶體、GPU、硬碟的使用情況幾乎沒有明顯變化。
所以,問題大機率出在程式碼上。
「R星程式碼寫太爛!」
黑客大哥在開扒R星程式碼之前,就說:
我聞到一股爛程式碼的味道…..
為了找出到底那一部份程式卡住了CPU,他使用了工具
Luke Stackwalker
,對CPU任務堆疊進行采樣分析。
Luke Stackwalker對於閉源應用程式,可以轉存正在執行的行程堆疊,和當前指令指標的位置,以一定時間間隔建立一個呼叫樹。
最後將數據整合,就可以得到程式執行統計數據。
從結果上看,一共有兩個函式「卡住」了CPU:
於是他使用專業的程式碼拆解工具,給GTA 5來了一個「開膛破肚」。
沿著呼叫棧往下走,發現問題出在一個
sscanf
函式上。
sscanf的功能是讀取格式化的字串中的數據,而在GTA 5中,它正在讀取的是一個10M左右,有63000多個條目的JSON檔。
這個檔到底是幹什麽用的?黑客大哥推測,這可能是
遊戲內購商店的相關內容。
在具體執行時,sscanf對於每個有效值,逐個讀取每一個字元,然後返回結果,之後指標移向下一個值,迴圈往復……直到把10M檔全部掃一遍。
再看第二個問題,這是一個儲存命令,物件是
item
,具體是什麽不得而知。
但是保存前,有一個if語句,逐一比較item內計畫的哈希值,檢查它們是否出現在某一列表中。
按照他的計算,這一步if,要執行(63000^2+63000)/2 =
1984531500
次!
沒錯,等待載入前的十多分鐘裏,GTA 5用你的CPU,執行了19.8億次if命令。
如此簡單粗暴的編程思路,讓這位老哥哭笑不得:
既然物件有唯一哈希值,那為什麽不用
hash map
???
(hashmap根據hashCode值儲存數據,大多數情況下可以直接定位到它的值,因而具有很快的存取速度,但遍歷順序不確定。)
至於為什麽這樣,有網友推測最開始,if的迴圈次數並沒有這麽多,而是隨著開發,條目不斷增多,最後到了積重難返的地步。
而之前的程式碼結構,誰也不願意去動。
就這樣,19.8億次if,一遍遍在世界各地玩家cpu上上演。。。
這是不是堪稱遊戲開發史上最意外的「屎山」程式碼?
問題解決,載入時間節省70%
至於第一個問題,黑客大哥采用hook大法,不一一讀取字串,而是:
hook strlen
「緩存 「字串起始和當前長度。
如果在字串範圍內函式在此被呼叫,返回緩存的值
至於if語句問題,就更直接了——完全跳過重復檢查,利用hash map插入計畫,因為這些值是唯一的。
最後的結果如下:
現在,GTA 5線上版載入,從原來的6分鐘,下降到現在的1分50秒!而且,用的還是七八年前的硬體配置。
在此,應該手動@R星:你學廢了嗎?
這位黑客大哥在博文中沒有留下任何身份資訊,也沒有透露用的反編譯工具,但是做好事不留名的他,把打好包的工具上傳到了Github,玩家透過一行程式碼就能下載:
git clone —recurse-submodules https://
github.com/tostercx/GTA
O_Booster_PoC
之後,把dll檔貼上到遊戲根目錄下就OK!
部落格原文
https://
nee.lv/2021/02/28/How-I
-cut-GTA-Online-loading-times-by-70/
Github地址:
https://
github.com/tostercx/GTA
O_Booster_PoC