困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%

3 月初,遊戲玩家 tostercx 宣稱發明了一種新方法,可以把《俠盜獵車手 Online》(檢查 GTA 5)的加載時間縮短 70%。對玩家羣體來説,這無疑是一個好消息。


一直以來,《俠盜獵車手 Online》因慢如蝸牛的加載時間已經“臭名昭著”。社交媒體 Reddit 上有一份針對這個問題的調查,結果發現超過 80%的玩家都受到加載時間太慢的困擾。關鍵是,這個問題已經存在了 7 年,而遊戲開發商 Rockstar Games 卻沒有給出任何解決方案。


而 tostercx 決心深究,他發現加載時間慢的問題在於啓動《俠盜獵車手 Online》時存在單線程 CPU 瓶頸,並且遊戲在費勁地解析 10MB 的 JSON 文件。對此,他認為,解決這款遊戲加載時間慢的問題,只需要一名開發人員不到一天的時間。


隨後,他寫了一篇技術文章發在博客上,引起很大反響,不僅被 Hacker News 置頂,而且網友紛紛轉發,甚至獲得遊戲開發商 Rockstar 10000 美元的獎勵。


Rockstar 在官方通告中稱,“經過徹底的調查,我們可以確定玩家 tostercx 確實揭示了《俠盜獵車手 Online》PC 版加載時間有待改善的遊戲代碼問題。作為調查結果,我們做了一些改進,這些改進會在更新中得到應用。”

慢如蝸牛的加載時間


作為《俠盜獵車手 Online》玩家,tostercx 不久前又上線打了幾個任務,但是他發現這款遊戲的加載時間仍然和 7 年前剛發佈的時候一樣慢。


於是,他去網上搜索,想了解是否已經有人解決了這個問題。而網上大多數的結果都是一些個人評論和猜測,比如這款遊戲太複雜了所以加載很慢,p2p 網絡架構太垃圾了所以加載快不了,等等。


當然,還有一些提升加載速度的建議,比如先載入故事模式,然後玩一次單人任務;另外,還有幾個可以跳過啓動 logo 視頻的 mod。


但是,這些辦法結合起來只能節省 10-30 秒。而他玩這款遊戲,所需的故事模式加載時間是 1 分 10 秒,而在線模式加載時間是 6 分鐘。詳情如下:


複製代碼


tostercx 在博客寫道,“我知道我的機器配置已經過時,但是加載到在線模式竟然需要 6 倍左右的時間?即使用上別人總結的從故事模式切換到在線模式的加載技巧,也沒產生什麼效果。”

開始調查


Reddit 的一份調查表明,超過 80%的玩家都受到這個問題的困擾。


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


只有 20%的玩家所用的加載時間不到 3 分鐘,而他們極有可能是因為配備了高端遊戲 PC。根據 tostercx 的基準測試,高端遊戲 PC 加載在線模式,只需要大約 2 分鐘。


tostercx 發現:即使如此,他們的故事模式還是需要近 1 分鐘的加載時間?他們從故事模式切換到在線模式只需一分多鐘。


“我知道,他們的硬件配置要好很多,但肯定不會好 5 倍那麼厲害。”他説。

繼續研究


利用任務管理器之類的強大工具,tostercx 開始研究哪些資源可能成為瓶頸。


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


遊戲花了一點時間加載用於故事模式和在線模式的通用資源,這部分時間與高端 PC 的耗時差不多。然後,遊戲在他的計算機上拉滿一個核心跑 4 分鐘時間,這 4 分鐘其他什麼事都不幹。


正如上圖所示,磁盤利用率為 0,網絡利用率在幾秒鐘後也降為 0,GPU 利用率為 0,而內存使用,則完全是一條直線。


tostercx 表示,“它是在挖掘加密貨幣還是在幹什麼勾當?我聞到代碼的味道了。真的是很糟糕的代碼。”

問題根因


在 tostercx 看來,雖然自己的機器很老(老舊的 AMD CPU 有 8 個核心),製造時間也有很久,但是這可能無法解釋所有的加載時間差異。


讓他感到奇怪的是,遊戲只佔用了 CPU 資源。他以為會有大量的磁盤讀取過程來加載資源,或很多網絡請求負載嘗試在 p2p 網絡中協商會話。


“但是現在這樣?這可能是一個 bug。”

Profiling

Profiler(分析器)是查找 CPU 瓶頸的好工具。這裏只有一個問題——大多數 Profiler 都需要檢測源代碼,才能對程序運行過程中所發生的事情有一個完整的瞭解。


而 tostercx 沒有源代碼,也不需要微秒級的讀數——其瓶頸長達 4 分鐘。


然後,瞭解一下堆棧採樣:對閉源應用程序來説,Profiler 只有一個選項。轉儲正在運行的進程的堆棧和當前指令指針的位置,以按設置的時間間隔構建一個調用樹。然後將它們加起來以獲取當前狀況的統計信息。


據他了解,只有一個 Profiler 可以在 Windows 上執行這些操作,而且它已經十多年沒有更新了。它就是 Luke Stackwalker!


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


一般來説,Luke 會將相同的函數歸為一組,但由於他沒有調試符號,因此不得不盯着附近的地址來猜測它是否在同一位置。那麼我們看到了什麼?不是一個瓶頸,而是兩個!

繼續深入

tostercx 借用了其朋友的行業標準級反彙編程序的完全合法副本,然後把 GTA 拆開來看個究竟。


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


這根本不對頭。大多數著名遊戲都帶有針對逆向工程的內置保護措施,可以防止盜版、作弊和修改。這倒不是説這類措施一定有用。 這裏似乎存在某種混淆/加密,已經用亂碼代替了大多數指令。


但是,這不是關鍵,“我們只需要在執行我們要看的部分時轉儲遊戲的內存即可”。在運行之前,必須對指令進行混淆處理,他使用了 Process Dump。

問題一:這是……strlen?!

反彙編現在不太混亂的轉儲會發現,其中一個地址的一個標籤被拉出到了某個地方!這是 strlen?在調用堆棧中,下一個標記為 vscan_fn,此後標記結束。tostercx 認為它就是 sscanf。


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


它正在解析某些內容。解析什麼?反彙編太花時間了,因此他決定使用 x64dbg 從正在運行的進程中轉儲一些樣本。後來經過一些調試步驟,他發現它是……JSON!他們正在解析 JSON,一個帶有約 63k 項的條目,體積高達 10MB 的 JSON


複製代碼


它是什麼?根據一些參考資料,它似乎是“在線商店目錄”的數據。它可能包含了你可以在 GTA Online 中購買的所有物品和升級的列表

問題二:使用哈希數組嗎?

原來第二名=個罪犯和第一個是緊挨着的。就像在這段醜陋的反編譯內容中看到的那樣,它們甚至都在相同的 if 語句中被調用:

困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


第二個問題?解析項目後,它立即存儲在一個數組(或一個內聯的 C++列表?不確定)中。每個條目如下所示:


複製代碼


但是在存儲之前?它會逐一檢查整個數組,對比項目的哈希值以查看它是否在列表中。條目總共有約 63k,也就是説需要(n^2+n)/2=(63000^2+63000)/2=1984531500。可是大多數操作都沒用。tostercx 表示,“既然你有唯一的哈希,為什麼不使用哈希圖呢?”


困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70%


他在反編譯時將其命名為 hashmap,但它顯然 not_a_hashmap。這還沒完。加載 JSON 之前,hash-array-list-thing 是空的。而且 JSON 中的所有項目都是唯一的!他們甚至不需要檢查它是否在列表中!它們甚至有一個直接插入項目的函數!就用它就行了!有沒有搞錯!?

解決方案

tostercx 在找到問題後,寫了一個**.dll,將其注入 GTA 中,並 hook 上一些函數**,搞定加載時間慢的問題。


JSON 問題比較棘手,他無法替換它們的解析器。用不依賴 strlen 的 sscanf 替換 sscanf 更為現實。但是有一種更簡單的方法。



如下:


複製代碼


至於哈希數組問題,其實更簡單——完全跳過重複檢查並直接插入項目,因為我們知道值是唯一的。


複製代碼


很快,這辦法就奏效了,《俠盜獵車手 Online》加載時間縮短 70%。如下:


複製代碼


根據這名玩家的總結:



附:


玩家 tostercx 的 PoC 完整資料https://github.com/tostercx/GTAO_Booster_PoC


官方更新 https://support.rockstargames.com/articles/360061161574/

版權聲明:本文源自 網絡, 於,由 楠木軒 整理發佈,共 3285 字。

轉載請註明: 困擾80%玩家,祖傳7年的加載時間問題,被一玩家縮短70% - 楠木軒