Android 8.0 包含針對吞吐量和延遲的 Binder 和 hwbinder 效能測試。雖然存在許多用於檢測可察覺的效能問題的場景,但運行此類場景可能非常耗時,並且通常在系統整合之後才能獲得結果。使用提供的效能測試可以更輕鬆地在開發過程中進行測試,更早發現嚴重問題並改善使用者體驗。
性能測試包括以下四類:
- 活頁夾吞吐量(可在
system/libhwbinder/vts/performance/Benchmark_binder.cpp
中找到) - 活頁夾延遲(可在
frameworks/native/libs/binder/tests/schd-dbg.cpp
中找到) - hwbinder 吞吐量(可在
system/libhwbinder/vts/performance/Benchmark.cpp
中找到) - hwbinder 延遲(可在
system/libhwbinder/vts/performance/Latency.cpp
中找到)
關於binder和hwbinder
Binder 和 hwbinder 是 Android 進程間通訊 (IPC) 基礎設施,它們共享相同的 Linux 驅動程序,但具有以下質的差異:
方面 | 活頁夾 | 硬體綁定程式 |
---|---|---|
目的 | 為框架提供通用的IPC方案 | 與硬體通信 |
財產 | 針對 Android 框架使用進行了最佳化 | 最小開銷低延遲 |
更改前台/後台的調度策略 | 是的 | 不 |
爭論透過 | 使用 Parcel 物件支援的序列化 | 使用分散緩衝區並避免複製 Parcel 序列化所需資料的開銷 |
優先繼承 | 不 | 是的 |
Binder 和 hwbinder 流程
systrace 視覺化工具顯示交易如下:
在上面的例子中:
- 四 (4) 個 schd-dbg 進程是客戶端進程。
- 四 (4) 個 Binder 程序是伺服器程序(名稱以Binder開頭,以序號結尾)。
- 客戶端進程始終與伺服器進程配對,伺服器進程專用於其客戶端。
- 所有客戶端-伺服器進程對均由核心同時獨立調度。
在CPU 1中,OS核心執行客戶端發出請求。然後,它會盡可能使用相同的 CPU 來喚醒伺服器進程、處理請求,並在請求完成後切換回上下文。
吞吐量與延遲
在完美的事務中,客戶端和伺服器進程無縫切換,吞吐量和延遲測試不會產生明顯不同的訊息。但是,當作業系統核心正在處理來自硬體的中斷請求 (IRQ)、等待鎖定或只是選擇不立即處理訊息時,可能會形成延遲泡沫。
吞吐量測試產生大量具有不同有效負載大小的事務,為常規事務時間(在最佳情況下)和綁定器可以實現的最大吞吐量提供了良好的估計。
相反,延遲測試不會對有效負載執行任何操作,以最大限度地縮短常規交易時間。我們可以使用事務時間來估計binder開銷,統計最壞情況,併計算延遲滿足指定期限的事務的比例。
處理優先權反轉
當具有較高優先權的執行緒在邏輯上等待具有較低優先權的執行緒時,就會發生優先權反轉。即時(RT)應用程式存在優先反轉問題:
當使用 Linux Completely Fair Scheduler (CFS) 調度時,即使其他執行緒具有更高的優先級,執行緒也始終有機會運行。因此,採用 CFS 調度的應用程式會依照預期行為處理優先權反轉,而不是作為問題。然而,當Android框架需要RT調度來保證高優先權執行緒的特權時,必須解決優先權反轉的問題。
綁定器事務期間的優先權反轉範例(RT 執行緒在等待綁定器執行緒服務時在邏輯上被其他 CFS 執行緒阻塞):
為了避免阻塞,當 Binder 執行緒處理來自 RT 用戶端的請求時,可以使用優先權繼承將 Binder 執行緒暫時升級為 RT 執行緒。請記住,RT 調度的資源有限,應謹慎使用。在有n個CPU的系統中,目前RT執行緒的最大數量也是n ;如果所有 CPU 都被其他 RT 執行緒佔用,則其他 RT 執行緒可能需要等待(從而錯過其最後期限)。
要解決所有可能的優先權反轉,您可以對binder 和hwbinder 使用優先權繼承。然而,由於 Binder 在整個系統中廣泛使用,因此為 Binder 事務啟用優先級繼承可能會向系統發送超出其服務能力的 RT 執行緒。
運行吞吐量測試
吞吐量測試針對binder/hwbinder 交易吞吐量運作。在未過載的系統中,延遲泡棉很少見,只要迭代次數夠多,就可以消除其影響。
- 綁定器吞吐量測試位於
system/libhwbinder/vts/performance/Benchmark_binder.cpp
。 - hwbinder吞吐量測試位於
system/libhwbinder/vts/performance/Benchmark.cpp
。
檢測結果
使用不同有效負載大小的交易的吞吐量測試結果範例:
Benchmark Time CPU Iterations --------------------------------------------------------------------- BM_sendVec_binderize/4 70302 ns 32820 ns 21054 BM_sendVec_binderize/8 69974 ns 32700 ns 21296 BM_sendVec_binderize/16 70079 ns 32750 ns 21365 BM_sendVec_binderize/32 69907 ns 32686 ns 21310 BM_sendVec_binderize/64 70338 ns 32810 ns 21398 BM_sendVec_binderize/128 70012 ns 32768 ns 21377 BM_sendVec_binderize/256 69836 ns 32740 ns 21329 BM_sendVec_binderize/512 69986 ns 32830 ns 21296 BM_sendVec_binderize/1024 69714 ns 32757 ns 21319 BM_sendVec_binderize/2k 75002 ns 34520 ns 20305 BM_sendVec_binderize/4k 81955 ns 39116 ns 17895 BM_sendVec_binderize/8k 95316 ns 45710 ns 15350 BM_sendVec_binderize/16k 112751 ns 54417 ns 12679 BM_sendVec_binderize/32k 146642 ns 71339 ns 9901 BM_sendVec_binderize/64k 214796 ns 104665 ns 6495
- 時間表示即時測量的往返延遲。
- CPU表示調度CPU進行測試時的累積時間。
- 迭代次數表示測試函數執行的次數。
例如,對於 8 位元組有效負載:
BM_sendVec_binderize/8 69974 ns 32700 ns 21296
…綁定器可以實現的最大吞吐量計算如下:
8 位元組有效負載的最大吞吐量 = (8 * 21296)/69974 ~= 2.423 b/ns ~= 2.268 Gb/s
測試選項
若要取得 .json 格式的結果,請使用--benchmark_format=json
參數執行測試:
libhwbinder_benchmark --benchmark_format=json
{
"context": {
"date": "2017-05-17 08:32:47",
"num_cpus": 4,
"mhz_per_cpu": 19,
"cpu_scaling_enabled": true,
"library_build_type": "release"
},
"benchmarks": [
{
"name": "BM_sendVec_binderize/4",
"iterations": 32342,
"real_time": 47809,
"cpu_time": 21906,
"time_unit": "ns"
},
….
}
運行延遲測試
延遲測試測量客戶端開始初始化交易、切換到伺服器進程進行處理以及接收結果所需的時間。該測試還會尋找可能對交易延遲產生負面影響的已知不良調度程序行為,例如不支援優先權繼承或尊重同步標誌的調度程序。
- 綁定器延遲測試位於
frameworks/native/libs/binder/tests/schd-dbg.cpp
。 - hwbinder 延遲測試位於
system/libhwbinder/vts/performance/Latency.cpp
。
檢測結果
結果(以 .json 格式)顯示平均/最佳/最差延遲以及錯過的截止日期數量的統計數據。
測試選項
延遲測試採用以下選項:
命令 | 描述 |
---|---|
-i value | 指定迭代次數。 |
-pair value | 指定進程對的數量。 |
-deadline_us 2500 | 指定我們的截止日期。 |
-v | 獲取詳細(調試)輸出。 |
-trace | 在達到截止日期時停止追蹤。 |
以下部分詳細介紹了每個選項、描述用法並提供範例結果。
指定迭代次數
禁用大量迭代和詳細輸出的範例:
libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
"other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
"fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
"other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
"fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}
這些測試結果顯示:
-
"pair":3
- 創建一對客戶端和伺服器。
-
"iterations": 5000
- 包括 5000 次迭代。
-
"deadline_us":2500
- 截止時間為2500us(2.5ms);大多數交易預計都會達到這個值。
-
"I": 10000
- 單一測試迭代包括兩 (2) 個事務:
- 正常優先順序的交易(
CFS other
) - 一筆交易即時優先 (
RT-fifo
)
- 正常優先順序的交易(
-
"S": 9352
- 9352 筆交易在同一個 CPU 中同步。
-
"R": 0.9352
- 表示客戶端和伺服器在同一CPU上同步的比率。
-
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
- 普通優先權呼叫方發出的所有事務的平均 (
avg
)、最差 (wst
) 和最佳 (bst
) 情況。兩筆交易miss
截止日期,使得滿足率 (meetR
) 為 0.9996。 -
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
- 與
other_ms
類似,但適用於用戶端以rt_fifo
優先權發出的交易。 fifo_ms 可能(但不是必需)比fifo_ms
具有更好的結果,具有較低的avg
和wst
值以及較高的meetR
(在後台加載時差異可能更加顯著)other_ms
注意:後台負載可能會影響延遲測試中的吞吐量結果和other_ms
組。只要後台負載的優先權低於RT-fifo
,只有fifo_ms
可能會顯示類似的結果。
指定對值
每個客戶端進程都與專用於該客戶端的伺服器進程配對,並且每對都可以獨立調度到任何 CPU。但是,只要 SYNC 標誌為honor
,CPU 遷移就不應該在交易期間發生。
確保系統不超載!雖然過載系統中的高延遲是可以預期的,但過載系統的測試結果並不能提供有用的資訊。要測試壓力較高的系統,請使用-pair #cpu-1
(或謹慎使用-pair #cpu
)。使用-pair n
和n > #cpu
進行測試會使系統過載並產生無用的信息。
指定截止日期值
經過廣泛的使用者情境測試(在合格的產品上執行延遲測試),我們確定 2.5ms 是滿足的期限。對於要求更高的新應用程式(例如1000張照片/秒),這個截止日期值將會改變。
指定詳細輸出
使用-v
選項顯示詳細輸出。例子:
libhwbinder_latency -i 1 -v
-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
- 此服務執行緒是使用
SCHED_OTHER
優先權建立的,並在CPU:1
中運行,pid 8674
。 - 然後第一個事務由
fifo-caller
啟動。為了服務此事務,hwbinder 將伺服器的優先權(pid: 8674 tid: 8676
)升級為 99 ,並使用瞬態調度類別對其進行標記(列印為???
)。然後,調度程序將伺服器進程放入CPU:0
中運行,並將其與客戶端同步到相同 CPU。 - 第二個事務呼叫方具有
SCHED_OTHER
優先權。伺服器降級自身並以SCHED_OTHER
優先權為呼叫者提供服務。
使用追蹤進行調試
您可以指定-trace
選項來偵錯延遲問題。使用時,延遲測試會在偵測到不良延遲時停止追蹤日誌記錄。例子:
atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace log:/sys/kernel/debug/tracing/trace
以下組件可能會影響延遲:
- Android 建置模式。 Eng 模式通常比 userdebug 模式慢。
- 框架。框架服務如何使用
ioctl
來配置binder? - 活頁夾驅動程式。驅動程式是否支援細粒度鎖定?它包含所有性能調整補丁嗎?
- 內核版本。核心的即時能力越好,結果就越好。
- 內核配置。核心配置是否包含
DEBUG
配置,例如DEBUG_PREEMPT
和DEBUG_SPIN_LOCK
? - 內核調度程序。核心是否有能源感知調度程序 (EAS) 或異構多處理 (HMP) 調度程序?任何核心驅動程式(
cpu-freq
驅動程式、cpu-idle
驅動程式、cpu-hotplug
等)是否會影響調度程式?