Android系統“資源排程框架”
一、一些問題的思考
“資源”是什麼
計算機基礎中提到,一套完整的計算機系統有三部分組成:應用程式、作業系統(OS)和計算機的硬體。
其中硬體又可分五大組成:控制器(CU)、運算器(ALU)、儲存器(Memory)、輸入裝置(Input)和輸出裝置(Output)。
本文提到的“資源”指硬體的效能資源,所闡述的問題就是程式執行時分配到的硬體資源。
比如cpu的大小核心及數量,比如cpu、gpu、ddr、flash的執行頻率。
“資源”和效能有什麼關係
簡單理解以cpu為例。程式的執行最終反映為cpu執行機器碼,cpu時脈頻率越高,相同時間內執行的語句就越多,自然程式執行越快。
如此就讓人感覺到“效能”更強。
為什麼需要資源排程
下面是兩個生活化場景,可以思考一下。
1、同樣一款遊戲,同樣的畫質幀率設定下為啥有的機器卡卡的,有的比較流暢。
2、同樣的一款遊戲,為啥換什麼配置的機器都感覺一個樣。一樣卡或者一樣流暢。
開發者(系統廠商和應用開發者)有一致的目標:讓應用程式流暢執行。但是應用直接操作控制cpu、gpu等硬體是不被允許的。
aosp中,cpu、gpu的資源排程預設還是核心在控制,系統框架間接控制。預設的策略考慮的是通用性,安全性。
但是現實針對具體的效能場景,往往需要更加精細的資源排程,這樣在同樣的硬體基礎上能更充分的利用硬體資源提升使用者體驗。而不是“一核有難多核圍觀”
誰(程式)涉及到排程資源?
考慮以下典型場景
1、輸入互動場景:cpu提頻保證輸入互動流暢
2、應用/遊戲啟動場景:cpu提頻甚至繫結大核心,分配更多算力加速啟動
3、下載時檔案讀寫場景:提升flash頻率,加速IO
4、遊戲關鍵時刻:cpu、gpu提頻,重點分配遊戲程式
5、系統資源不夠了:app得知資源不夠主動裁減某些任務負載(比如降低畫質),來保證自己的重要任務流暢
1和2平臺系統側來觸發資源排程是比較合理的,但是3、4、5場景顯然app才好知道,自己什麼時候讀寫檔案,什麼時候遊戲爆發團戰,什麼時候自己太猛讓cpu、gpu快撐不住了,比如主動降低自己的畫質保證流暢度。
從這兩種角度來看,我們可以得知,資源排程、效能調優需要系統和應用的共同努力。系統和應用均需要獲得資源排程介面。
現狀是?
- AOSP
aosp在效能優化上不斷進步,但是目前為止還是沒有一套硬體的資源排程框架供給fwk與app,瞭解到的只有Framework中Powermanager#powerHint介面。
- 晶片廠商
晶片廠商在自己的平臺上提供了基礎的資源排程框架,像高通的perfLock,MTK的PerfService,提供了基礎的cpu、gpu資源排程入口。
但這僅針對他們自己的晶片硬體如cpu、gpu。不包含其他廠商的硬體資源例如儲存flash,並且是系統級別的介面,是給手機廠商用的,沒有針對第三方應用提供一套SDK方案。
並且晶片平臺之間這些框架是不通用的哈哈哈。
-
結論
aosp和晶片廠商release出的程式碼,目前沒有現成的一套體系,讓系統框架或app來控制底層硬體執行效能,包括不限於cpu,gpu,記憶體,io,網路。
手機廠商實現一套自己的資源排程框架是必選項。
我們的需求
從上面的問題以及思考、討論中,使得我們的需求,訴求輪廓逐漸清晰:直接控制系統資源,直接獲取系統執行狀態。
我們要控制cpu的頻率及執行的核心
我們要控制gpu的頻率
我們要控制ddr、Flash的頻率
我們要得知當前系統的壓力
構思一下軟體架構
系統程式和app程式都要用,java和native都要用。
那麼要給app提供sdk,比如ndk、java lib的編譯依賴
要給系統框架提供系統服務介面,java系統服務和native系統服務。
由於本架構是用於溝通硬體的,所以fwk裡僅做鑑權和請求簡單分解,真正的實現最好放到native或者更進一步放到核心裡,避免java層native層多份實現
為了時效性可以整到單獨的程式裡,而不是放在system_server中。
下圖是個示意圖
圖:資源排程軟體架構示意圖
有了這套資源排程框架,就能直接控制cpu等系統資源和接收系統狀態了。
需要考慮介面的可移植性,不同晶片平臺之間、不同android版本之間。除了目前常用的,還要對其他未來可能的硬體資源創造方便的增刪介面。
還需要考慮到鑑權和策略控制,誰可以用和什麼情況下允許用、時長頻次等兜底策略。
二、目前國內手機廠商的做法調查
當前時間:2021-07
你抄我呀,我抄你,友商之間甜蜜蜜。
ov米差不多,華為只提供c的api。
然後ov米的介面風格是做的更少,直接把提頻綁核放權給應用。而華為選擇做的更多,給應用的是設定幀率、設定場景這種概念性介面,真正提升多少幀率由系統決定。
下面一起來瞅一瞅。
華為-計算加速服務-效能加速庫
官網連結:華為計算加速服務
華為計算加速服務(HUAWEI Accelerate Kit,簡稱Acc Kit)支援多執行緒庫和效能加速庫,可實現高效的多執行緒加速能力和效能加速能力。
效能加速庫是Acc Kit中的效能加速模組,它為您提供了設定顯示幀率、設定關鍵執行緒、監聽系統狀態等硬體能力相關的介面。效能加速庫允許您深度參與華為硬體平臺的效能排程,使您能夠更有效地利用華為平臺的硬體能力。通過效能加速庫自主控制效能引數,可使硬體響應更及時、更準確,能有效解決應用在部分場景的卡頓、掉幀等問題,同時又避免了低負載場景的效能過剩,最大程度提升整機能效比。
場景介紹
典型場景 | 策略描述 |
---|---|
高負載場景 | 遊戲渲染場景下,通過設定關鍵執行緒保證使用者執行緒的資源排程優先順序,使得使用者新增的執行緒優先被系統呼叫。 |
負載突變場景 | 通過系統效能監控介面,您更容易預知負載變化,及時通知硬體提高重新整理率,使應用啟動更快,遊戲執行更流暢。 |
低重新整理率場景 | 導航場景,通知硬體降低重新整理率,切換到導航內動畫時及時提高重新整理率,在不影響使用者體驗情況下維持較低功耗。 |
混合場景 | 普通應用內視訊播放場景中降低重新整理率,滑動時提高重新整理率,獲取最佳效果和能效比。 |
PerfGeniusApi
Public Constructor Summary
Public Destructor Summary
Public Method Summary
PerfGeniusApi
~ PerfGeniusApi
Init
GetApiVersion
SetFrameRate
ResetFrameRate
GetCurrentFrameRate
GetSupportedFrameRate
SetScene
GetPerformanceLevel
AddKeyThreads
RemoveKeyThreads
RegisterSystemEventCallback
UnRegisterSystemEventCallback
RegisterPerformanceTracer
UnRegisterPerformanceTracer
GetPerfGeniusApiHandle
DeletePerfGeniusApiHandle
小米-應用加速器(MiBridge)
官網連結:應用加速器(MiBridge)介紹
框架
MiBridge是提供給應用接入到系統的一個介面
• 輕量級,JAR包,大小隻有幾kb。
• 低成本,與系統間連線採用Binder通訊機制
API
boolean checkDebugPermission(Context context, String pkg, int uid, String auth_key)
boolean checkPermission(String pkg, int uid)
int requestCpuHighFreq(int uid, int level, int timeoutms)
int cancelCpuHighFreq(int uid)
int requestThreadPriority(int uid , int req_tid, int timeoutms)
int cancelThreadPriority (int uid , int req_tid)
requestGpuHighFreq,requestIOHighFreq,requestMemory,requestNetwork等
OPPO-HyperBoost
官網連結:HyperBoost介紹
應用場景
1)系統資源排程:關鍵使用場景下通知系統及時分配合理資源,保證應用流暢執行。
2)4D振感:支援多種精細的線性馬達波形振感,開發者可以通過傳入波形序號直接呼叫振動,帶來更精彩的應用體驗。
3)智慧幀率(敬請期待):根據應用場景智慧調節幀率,動態調整幀率策略,預防卡頓。
工作原理框架
通用介面說明
API原型 | API說明 |
---|---|
public HyperBoostUnitClient getHyperBoostClient(Context context) | 功能:初始化SDK,過程中完成鑑權和回執 引數:context:傳入Activity上下文 |
public int getVersion() | 功能:獲取SDK版本號,如1.0.1 sdk的版本號為100001 |
public boolean registerClient() | 功能:初始化HyperBoost引擎,需要在鑑權成功回撥中使用 |
public boolean registerNotifier(HyperBoostCallback callback) | 功能:註冊溫控警報回撥 引數:callback:用於溫控回撥的標準介面類實現 |
public boolean specificAction(String info) | 功能:針對應用特調優化場景預留介面,適用於商務對接過的三方應用,雙方協定優化方案和通訊協議,呼叫此介面通知服務端 引數:info:用於雙方特調優化的通訊的協議內容 |
普通應用介面說明
API原型 | API說明 |
---|---|
public boolean appBootCompleted() | 功能:應用冷啟動時手機系統預設會有一段時間的加速,APP啟動邏輯完成時若呼叫該介面通知系統,手機系統恢復一般狀態,可以減少系統功耗。 |
public boolean appActionLoading(int loadTime, int level) | 功能:在應用載入等重負載場景下,呼叫此介面可以將系統效能在一定時間內拉高,為應用分配更大的系統資源,減少使用者等待。為防止濫用造成功耗問題,單次呼叫最長加速時長為10秒,呼叫間隔最短為30秒。 引數: loadTime:CPU提頻時長,單位ms,最大有效值10000 level:提頻等級,分為三級,提頻力度依次遞增,應用按需呼叫。 可傳入引數: HyperBoostCommonUtil.CPU_BOOST_LEVEL_COMMON; HyperBoostCommonUtil.CPU_BOOST_LEVEL_HIGH; HyperBoostCommonUtil.CPU_BOOST_LEVEL_STRONG; |
public boolean appActionBurst(int burstTime, int level) | 功能:對於短時間內負載較大的操作,可呼叫此介面,短時間內將CPU效能拉高。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數: burstTime:CPU提頻時長,單位ms,最大有效值1000 level:同appActionLoading方法 |
public boolean appActionDdr(int burstTime, int level) | 功能:短時間內提高記憶體讀寫速度和傳輸效率。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數:burstTime:DDR提頻時長,單位ms,最大有效值1000 level:暫不生效,可預設傳HyperBoostCommonUtil.DDR_BOOST_LEVEL_COMMON; |
public boolean appActionGpu(int burstTime, int level) | 功能:短時間內拉高GPU工作頻率,適用於應用畫面渲染、頁面切換等場景。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數: burstTime:GPU提頻時長,單位ms,最大有效值1000 level:暫不生效,可預設傳HyperBoostCommonUtil.GPU_BOOST_LEVEL_COMMON; |
public boolean appActionEnd() | 功能:標識應用重負載場景結束,暫時不需要效能提升,系統將恢復正常狀態,降低功耗。 |
public boolean appActionBind(int tid, boolean isBind) | 功能:傳入執行緒id,系統將保障該執行緒執行在大核或超大核上。適用於應用負載較重,耗時較長的執行緒場景,如音視訊類應用的視訊編解碼執行緒。 引數: tid: 需要繫結大核的執行緒id,需傳入android系統級執行緒id isBind:傳入HyperBoostCommonUtil.BIND_GOLD_CORE表示繫結大核,傳入HyperBoostCommonUtil.UNBIND_GOLD_CORE表示解綁大核; |
遊戲應用介面說明
API原型 | API說明 |
---|---|
public boolean gameBootCompleted() | 功能:遊戲冷啟動時手機系統預設會有一段時間的加速,遊戲啟動邏輯完成時若呼叫該介面通知系統,手機系統恢復一般狀態,可以減少系統功耗。 |
public boolean gameSceneStart() | 功能:標識遊戲開始。為了保持遊戲期間效能穩定,通過呼叫該介面通知手機系統已正式開始打遊戲,這時手機系統會開啟觸控式螢幕靈敏度優化、自動追幀等優化策略,從而使遊戲效能更加穩定 |
public boolean gameSceneEnd() | 功能:標識遊戲結束。在遊戲結束或者回到遊戲大廳時呼叫該介面,這時手機系統會關閉上述的觸控式螢幕優化等優化策略,從而減少不必要的功耗,提升手機續航。 |
public boolean gameActionLoading(int loadTime, int level) | 功能:在遊戲地圖載入等重負載場景下,呼叫此介面可以將系統效能在一定時間內拉高,為應用分配更大的系統資源,減少使用者等待。為防止濫用造成功耗問題,單次呼叫最長加速時長為30秒,呼叫間隔最短為60秒。 引數: loadTime:CPU提頻時長,單位ms,最大有效值30000 level:提頻等級,分為三級,提頻力度依次遞增,應用按需呼叫。 可傳入引數: HyperBoostCommonUtil.CPU_BOOST_LEVEL_COMMON; HyperBoostCommonUtil.CPU_BOOST_LEVEL_HIGH; HyperBoostCommonUtil.CPU_BOOST_LEVEL_STRONG; |
public boolean gameActionBurst(int burstTime, int level) | 功能:對於短時間內負載較大的操作,可呼叫此介面,短時間內將CPU效能拉高。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數: burstTime:CPU提頻時長,單位ms,最大有效值1000 level:同appActionLoading方法 |
public boolean gameActionDdr(int burstTime, int level) | 功能:短時間內提高記憶體讀寫速度和傳輸效率。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數: burstTime:DDR提頻時長,單位ms,最大有效值1000 level:暫不生效,可預設傳HyperBoostCommonUtil.DDR_BOOST_LEVEL_COMMON; |
public boolean gameActionGpu(int burstTime, int level) | 功能:短時間內拉高GPU工作頻率,適用於遊戲畫面渲染、頁面切換等場景。防止濫用造成功耗問題,單次呼叫最長加速時長為1秒,呼叫間隔最短為3秒。 引數: burstTime:GPU提頻時長,單位ms,最大有效值1000 level:暫不生效,可預設傳HyperBoostCommonUtil.GPU_BOOST_LEVEL_COMMON; |
public boolean gameActionEnd() | 功能:標識遊戲重負載場景結束,暫時不需要效能提升,系統將恢復正常狀態,降低功耗。 |
public boolean gameActionBind(int tid, boolean isBind) | 功能:傳入執行緒id,系統將保障該執行緒執行在大核或超大核上。適用於遊戲負載較重,耗時較長的執行緒場景,比如在地圖資源載入的時候,配合提頻一起使用。 引數: tid: 需要繫結大核的執行緒id,需傳入android系統級執行緒id isBind:傳入HyperBoostCommonUtil.BIND_GOLD_CORE表示繫結大核,傳入HyperBoostCommonUtil.UNBIND_GOLD_CORE表示解綁大核; |
VIVO-Multi-turbo
官網連結:Multi-turbo SDK介紹
1、Multi-turbo SDK介紹
Multi-turbo SDK支援遊戲應用和普通應用,普通應用在某些關鍵場景下可通過Multi-turbo SDK提供的介面,通知手機系統及時分配合理的系統資源,保障應用的流暢執行。遊戲應用可以給系統提供精準的場景、設定等資訊,系統可給遊戲應用反饋系統狀態等,利用這些資訊雙方可以更好的協作,更進一步改善玩家的遊戲體驗。
2、工作原理
開發者在需要的場景下,呼叫合適的Multi-turbo SDK提供的介面,手機系統層接受到相應需求,快速分配合理的系統資源,從而使應用執行更流暢;同時應用可註冊對應系統狀態回撥,系統可以為註冊系統回撥的應用反饋對應系統狀態資訊,應用也可根據系統狀態資訊做一些相應調整,從而達到更好的效果。
API
public boolean checkPermission(String code)
public void appShortTurbo(int duration, int level)
public void appLongTurbo(int duration, int level)
public void appTurboEnd()
public void gameLongTurbo(int duration)
public void gameShortTurbo(int duration)
public void gameTurboEnd()
public void gameSceneStart()
public void gameSceneEnd()
public void updateGameInfo(String infoJson)
public String getPhoneInfo(int type)
public void registerCallBack(CallBack callBack, int flags)
三、最後
第一章的現狀有提到,實現一套自己的資源排程框架是手機廠商的必經之路。
技術架構和核心方法上難點不大,只是copy一套系統服務和封裝核心介面。
重點還是這些介面使用,因為涉及到全域性的效能,所以完善的測試是必要的。