測試遊戲陪玩app開發中的啟動效能,需要這樣做

雲豹科技程式設計師發表於2021-11-10

用於測試啟動的 Shell 命令

本文的編寫目的,更多的在於介紹遊戲陪玩app開發效能、啟動測試以及我進行遊戲陪玩app開發啟動測試背後的原因。但如果您只是希望能夠快速獲得結論,可以直接參考下面的內容:
1、儘可能鎖定 CPU 主頻 (請參閱下文); 2、在命令列執行如下命令 (保證您的裝置處於連線狀態)。
$ for i in `seq 1 100`
> do 
>   adb shell am force-stop com.android.samples.mytest
>   sleep 1
>   adb shell am start-activity -W -n com.android.samples.mytest/.MainActivity | grep "TotalTime" | cut -d ' ' -f 2
> done
上面的命令會迴圈 100 次: 啟動應用、輸出啟動過程耗時,然後終止程式以準備好下一次迴圈。

想把啟動效能測試 “測” 好並非易事

遊戲陪玩app開發啟動效能並不容易明確地被測試出來。測試一段執行時程式碼,有許多解決方案能夠選擇。從 “編寫緊密的迴圈並使用 System.currentTimeMillis() 計算時間增量” 這種瑣碎的方法,到更復雜和有用的解決方案,如使用 AndroidX benchmark 庫所提供的功能。
但是按照定義,遊戲陪玩app開發啟動時的許多操作執行在系統呼叫程式碼之前。那麼如何確定遊戲陪玩app開發整個啟動過程所需要的時間呢?
我瀏覽了一些日誌資訊、檢查了一些底層 API,並詢問了一些平臺團隊的工程師,終於獲得了一些有用的資訊。更棒的是,我現在可以使用 adb shell 工具完全自動化我的測試並輸出資訊,從而可以輕鬆地將結果匯入到電子表格中進行分析。
我會在下面的文字中解釋上述命令所使用的一些程式碼片段,並向您展示一到兩個遊戲陪玩app開發啟動測試的簡單步驟。

ActivityTaskManager 啟動日誌

在 KitKat 釋出後,有一個十分方便的日誌一直在記錄系統資訊。無論何時,當一個 Activity 啟動時,您都能看到日誌中工具輸出了以下資訊:
ActivityTaskManager: Displayed com.android.samples.mytest/.MainActivity: +1s380ms
這個持續時間 (本例中為 1,380ms) 表示了從啟動遊戲陪玩app開發到系統認為其 “已啟動” 所花費的時間,其中包括繪製第一幀 (所以是 “已顯示” 的狀態)。
到達 “已顯示” (Displayed) 狀態的過程並不需要包含您應用就緒之前所做的事情的花費時間。只要遊戲陪玩app開發確定已完成載入和初始化,就可以通過呼叫 Activity.reportFullyDrawn()) 向系統提供這些額外的資訊。當您呼叫了該可選方法時,系統會記錄另一個帶有時間戳和持續時間的日誌:
2020-11-18 15:44:02.171 1279-1336/system_process 
I/ActivityTaskManager: Fully drawn 
com.android.samples.mytest/.MainActivity: +2s384ms
我只想要到 “已顯示” 時所持續的時間,所以內建的日誌對我來講已經足夠好了。

自動化啟動

遊戲陪玩app開發效能測試總是應當多次去執行測試用例,以排除結果中的可變因素。進行的執行次數越多,平均結果就越可靠。我至少會嘗試執行測試十次,但是做的次數更多效果會更好。根據結果的變化程度以及時間的長短 (因為變數的存在會對持續時間更短的測試產生更大的影響),可能需要執行更多次才行。
瘋狂就是重複做相同的事情,卻期待不同的結果。 ——阿爾伯特 愛因斯坦
效能測試推論:
“瘋了” 就是同一件事只做一次,卻希望得到最佳結果。 ——不是愛因斯坦說的
通過點選遊戲陪玩app開發圖示來連續多次啟動應用是一件非常繁瑣的事情。而且這種操作不具備一致性,且有許多難以預測的因素,因為很容易就會引入變數——如您偶然間錯誤地啟動了另一個應用,或者使系統做了額外的工作而無法獲得計時結果。
因此,我真正想要的是某種從命令列啟動應用的方式。有了它,我就可以反覆執行該命令來執行相同的操作,從而避免手動啟動遊戲陪玩app開發帶來的可變性 (和乏味)。
adb (Android 除錯橋) 提供了我所需要的東西。更具體地說,adb shell 提供了用於啟動應用的命令列介面: adb shell am start-activity。該命令還能夠在應用啟動完成之前保持阻塞狀態,因此我們還要使用 -W 引數 (這對下一步來說是必需的。我們下一步將使用後續命令殺死啟動後的應用)。這是遊戲陪玩app開發完整的啟動命令:
$ adb shell am start-activity -W -n 
com.android.samples.mytest/.MainActivity
最後一個引數是應用的包名與元件資訊。
執行此命令將啟動遊戲陪玩app開發(除非該應用已經在前臺,但這種情況並不是理想的狀態,我們將在下一步對這種情況進行處理),並輸出以下資訊:
Starting: Intent { cmp=com.android.samples.mytest/.MainActivity }
Status: ok
LaunchState: COLD
Activity: com.android.samples.mytest/.MainActivity
TotalTime: 1380
WaitTime: 1381
Complete
檢查一下 TotalTime 結果: 結果與我們在日誌中看到的資訊完全相同:
ActivityTaskManager: Displayed 
com.android.samples.mytest/.MainActivity: +1s380ms
這意味著我們無需翻看 logcat,而是可以直接從執行命令的控制檯中便可獲取這些資訊。更棒的是,我們可以剝離多餘的文字並僅保留啟動結果,從而更輕鬆地提取此資料以供其他地方使用。
為了將上面的輸出轉換為啟動持續時間,我使用 grep 和 cut shell 命令來輸出內容 (有多種方法可以執行此操作,我只是隨機選擇了其中一個):
adb shell am start-activity -W -n 
com.android.samples.mytest/.MainActivity | grep "TotalTime" | cut -d ' ' -f 2
現在,當我執行這條命令時,就能如我預期般的只獲得一個簡單的數字:
$ [start-activity command as above...]
1380

冷啟動是效能測試的最佳起點

在您檢查遊戲陪玩app開發啟動效能前,最好先了解 “冷啟動” 和 “熱啟動” 之間的區別。
“冷啟動” 是指遊戲陪玩app開發在安裝後的第一次啟動、重啟,或者不在後臺時的啟動。
另一方面,“熱啟動” 是指遊戲陪玩app開發已經啟動且正在後臺執行 (但被暫停了) 時的啟動。
這兩種情況都值得去測試和理解。但總的來說,冷啟動才是進行遊戲陪玩app開發啟動效能測試的最佳起點,這其中有兩個原因:
  • 一致性 : 冷啟動可以確保遊戲陪玩app開發每次啟動時都經歷相同的操作。應用被熱啟動時,我們沒法明確知道哪些步驟被跳過,而哪些步驟被執行,因而也無從得知您到底在對什麼進行計時 (也無法保證重複測試時所測試的內容是否一致);
  • 最壞情況 : 按照定義,冷啟動是最壞的情況——這是遊戲陪玩app開發經歷啟動過程時間最長的場景。您需要專注於最壞情況的統計資料,而不是狀況最好的熱啟動。如果您忽略最壞情況,許多重大問題將無法被解決。
為了讓遊戲陪玩app開發在每次執行時強制進行冷啟動,您需要在兩次執行期間終止應用。再一次強調,在螢幕上執行這一操作 (例如,將應用從啟動器的 “概覽” 列表中滑出) 是乏味且容易出錯的,而 adb shell 可以解決這一問題。
有幾個不同的 shell 命令可用於終止應用。最顯而易見的是 adb shell am kill…… 但事實上這條命令並不能解決問題。當您啟動應用後,應用會處在前臺,而 kill 不會終止處在前臺的應用。作為替代,您需要使用 force-quit 命令:
adb shell am force-stop com.android.samples.mytest
您可以使用應用的包名告訴它需要終止哪個應用。

我喜歡迴圈,讓我們來迴圈它

現在,您已經有了可以啟動應用、輸出啟動持續時間資料,以及退出應用並使其可以再次啟動的一系列命令。您可以一遍又一遍地在控制檯中輸入這些內容,但是在 shell 中,我們可以將這些命令放在迴圈裡,然後只用一個命令就可以重複執行它。
在執行此操作時,為了避免遊戲陪玩app開發被終止而產生副作用 (例如,當應用程式被終止時,系統會將啟動器拉到前臺),您可能會想要在終止應用後延緩下一次的啟動。為此,我增加了一秒鐘的 sleep 以在兩次操作之間插入一個小的緩衝時間。
下面是我所使用的命令的最終版本,其中包括了終止應用、等待一秒鐘,然後重啟應用。我將這一過程迴圈執行了 100 次,從而可以提供一個合理的樣本量:
$ for i in `seq 1 100`
> do 
>   adb shell am force-stop com.android.samples.mytest
>   sleep 1
>   adb shell am start-activity -W -n com.android.samples.mytest/.MainActivity | grep "TotalTime" | cut -d ' ' -f 2
> done
在執行此命令時,每當啟動完成,我都可以獲得輸出到控制檯的啟動持續時間,而這正是我要跟蹤和分析的資料。
注意 : 以上操作其實有更簡單的方式,您可以使用 -S (用於首先停止 Activity) 和 -R COUNT (用於執行 start-activity 命令 COUNT 次) 來迴圈啟動 Activity,所以我也可以用下面的命令完成以上操作:
$ adb shell am start-activity -S -W -R 100-n 
com.android.samples.mytest/.MainActivity | grep "TotalTime" | cut -d ' ' -f 2
但是,為了在遊戲陪玩app開發應用的終止和啟動之間加入緩衝時間,以確保其處於非活動的狀態,我希望能使用 sleep 1 命令,因此我採用了更為冗長的方式進行迴圈。此外,shell 指令碼的程式碼非常優雅,不是嗎?

儘可能地鎖住主頻

CPU 架構,尤其是 CPU 頻率,是影響移動裝置效能的重要因素。具體而言,移動裝置減少電量消耗及避免出現過熱的問題的主要方法之一,便是限制 CPU 速度。
限制 CPU 對於節省電量很有用,但卻對遊戲陪玩app開發效能測試有負面影響,因為在這類測試中,結果的一致性至關重要。
理想情況下,在執行遊戲陪玩app開發效能測試時,您應該控制 CPU 頻率。然而您是否能夠執行這一操作取決於您所擁有的裝置——您需要擁有裝置的 root 訪問許可權才能控制 CPU 調速器,從而才能控制 CPU 頻率,並且不同的裝置執行這一行為的方式也可能不同。
接下來的內容僅適用於您的裝置允許且您可以取得 root 訪問許可權的情況。而在裝置方面,我知道 Pixel 裝置可以獲得訪問許可權,但這不代表其他裝置也同樣可以。
在任何情況下,如果可以的話,建議您鎖定 CPU 主頻。對於您特定的測試而言,可能不會有明顯的影響 (實際上,系統通常會在啟動應用時使 CPU 執行在較高的頻率上,因此可能已經提供了所需的一致性)。但是,這麼做至少可以消除 CPU 主頻這一可變因素。
手動鎖定 CPU 頻率可能很棘手,但幸運的是,AndroidX benchmark 幫您簡化了這一操作。實際上,您甚至不需要為 benchmark API 編寫程式碼——您可以通過使用其提供的 lockClocks 與 unlockClocks 工具來使用該庫。
首先,向工程級別的 build.gradle 檔案中加入 benchmark 的依賴:
// 檢視 Benchmark 庫的最新版本號
// https://developer.android.google.cn/jetpack/androidx/releases/benchmark
def benchmark_version = "1.0.0"
classpath "androidx.benchmark:benchmark-gradle-plugin:$benchmark_version"
接下來,在遊戲陪玩app開發應用級別的 build.gradle 檔案中應用 benchmark 外掛:
apply plugin: androidx.benchmark
現在,您可以同步您的工程 (Android Studio 可能已經在強迫您執行此操作),同步完成後便可以從 gradlew 中使用鎖定任務。
現在,您可以通過在命令列上執行命令來鎖定主頻了 (我是通過 Android Studio 內部的 “終端” 工具執行它的,但是您也可以在 IDE 外部執行它):
$ ./gradlew lockClocks
當我執行完命令後,便可以在命令列看到如下輸出:
Locked CPUs 4,5,6,7 to 1267200 / 2457600 KHz
Disabled CPUs 0,1,2,3
這段輸出表明 benchmark 可以在我的 Pixel 2 上正常工作。更好的訊息是,遊戲陪玩app開發啟動測試現在花費的時間比以前要長得多。您也許會好奇,為什麼主頻變慢了?
該 benchmark 工具將主頻鎖定在便於持續執行的級別,而不是高效能級別。如果將主頻設定為儘可能高,則可能會獲得更好的效能,但是:
  • 為了讓遊戲陪玩app開發測試結果足夠逼真,您甚至可能會期望更差的效能,就像許多使用者在現實中所遇到的情況一樣。您不會想要只看到最佳情況下的效能,因為那並不是人們通常會在現實中遇到的;
  • CPU 在高頻率下執行太長時間會導致過熱。我不知道系統在過熱時將如何響應 (希望它會降低主頻或在出現嚴重問題之前自動關閉系統),但是我也不想知道答案。
請注意,完成遊戲陪玩app開發測試後,您需要將主頻解鎖。裝置會在重新啟動時進行解鎖,但是您也可以通過執行相反的 gradle 任務來解鎖主頻:
$ ./gradlew unlockClocks
其實這一命令只是重新啟動裝置以執行重置操作。

這樣就完成了!

鎖定時鐘後,我準備好了一切: 能夠可靠重現啟動狀況的系統、一個執行後可以返回結果流的簡單命令列。我可以複製結果並貼上到電子表格中並進行分析 (通過將啟動時間平均值與我想嘗試的各種情況進行比較)。
理想情況下,我不需要撰寫文章來說明如何完成所有這些操作。老實說,您並不需要上文中的全部說明。(但是知道事情的工作原理和原因總是更有趣,不是嗎?) 您真正需要的只是 for() 迴圈 shell 命令,以及可選的鎖定主頻的方法。
$ for i in `seq 1 100`
> do 
>   adb shell am force-stop com.android.samples.mytest
>   sleep 1
>   adb shell am start-activity -W -n com.android.samples.mytest/.MainActivity | grep "TotalTime" | cut -d ' ' -f 2
> done
簡化遊戲陪玩app開發效能測試和分析,以及總體上提高遊戲陪玩app開發效能,還需要繼續探索,希望以上命令和資訊對大家的遊戲陪玩app開發啟動效能測試有所幫助。
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理 原文連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2841582/,如需轉載,請註明出處,否則將追究法律責任。

相關文章