效能提示 API

發布日期

Android 12 (API 級別 31) - Performance Hint API

Android 13 (API 級別 33) - NDK API 中的效能提示管理工具

(預先發布版) Android 15 (DP1) - reportActualWorkDuration()

透過 CPU 效能提示,遊戲可能會影響動態 CPU 效能 才能更符合自身需求在大多數裝置上,Android 都會以動態方式 依據先前的需求,評估工作負載的 CPU 時脈速度和核心類型。 如果工作負載使用更多 CPU 資源,時鐘速度會增加 則最終會移至更大的核心如果工作負載耗用較少 隨後 Android 會減少資源分配有了 ADPF 或遊戲傳送更多有關效能和期限的信號。這個 協助系統更積極地調高 (提升效能) 並降低 。

時脈速度

當 Android 裝置動態調整 CPU 時脈速度時, 變更程式碼的效能設計處理動態時鐘的程式碼 速度對最佳效能而言至關重要,熱能保持安全溫度 狀態,有效運用電源您無法直接指派 CPU 頻率 。因此,應用程式嘗試以 CPU 時脈速度是在背景執行緒中執行忙碌迴圈,讓工作負載 似乎更要求嚴苛。這種行為會浪費力量,但會浪費電力 當應用程式並非實際使用 再複習一下,機構節點 是所有 Google Cloud Platform 資源的根節點CPU PerformanceHint API 的設計可解決這個問題。變更者: 告知系統實際工作時間長度和目標工作持續時間。 Android 將能大致瞭解應用程式的 CPU 需求和分配情形 有效率地管理資源如此才能實現最佳效能,實現有效率的高效電力 提高用量上限

核心類型

執行遊戲的 CPU 核心類型是另一項重要效能 。Android 裝置通常會變更指派給執行緒的 CPU 核心 依據最近的工作負載行為動態調度資源CPU 核心指派作業 含有多種核心類型的 SoC在某些裝置上 核心應短暫使用,且在缺乏熱能性的情況下 時間。

您的遊戲不應嘗試設定 CPU 核心相依性,原因如下:

  • 工作負載的最佳核心類型會因裝置型號而異。
  • 執行大型核心的永續發展機制因 SoC 和 以及個別裝置型號提供的熱解解決方案
  • 環境對熱力狀態的影響可能會使核心更加複雜 就是用哪一種烤箱或刀子都可以 那麼預先建構的容器或許是最佳選擇舉例來說,天氣或手機保護殼可能會改變熱力狀態 裝置本身的狀態
  • 核心選擇無法因應效能更高的新裝置, 以及熱力功能因此,裝置通常會忽略遊戲的處理器 興趣相似。

預設 Linux 排程器行為範例

Linux 排程器行為
圖 1. 管理者可能需要約 200 毫秒才能提高或降低 CPU 頻率。ADPF 可與動態電壓與頻率縮放系統 (DVFS) 搭配運作,為每瓦提供最佳效能

PerformanceHint API 的抽象化機制比 DVFS 延遲時間長

ADPF 的摘要比 DVFS 延遲時間長
圖 2. ADPF 知道如何代替您做出最佳決策
  • 如果工作需要在特定 CPU 上執行,PerformanceHint API 知道如何 代您做出決定
  • 因此,您不需要使用相依性。
  • 裝置各有不同的拓撲;功率與熱力包括 因此缺乏多樣性, 導致應用程式開發人員的知名度差不多
  • 請勿就執行的基礎系統做出任何假設。

解決方案

ADPF 則提供 PerformanceHintManager 類別,讓遊戲能向 Android 傳送效能提示給 Android 以瞭解 CPU 時脈速度 核心類型這樣一來,OS 就可以根據 SoC 和 裝置的熱解解決方案如果應用程式使用這個 API 搭配熱能 因此可以為 OS 提供更多相關資訊 可能引發節流的繁忙迴圈和其他程式設計技術。

以下說明遊戲使用效能提示的方式:

  1. 為行為相似的主要執行緒建立提示工作階段。例如:
  2. 遊戲應盡早執行這項作業 (建議至少 2 毫秒,最好超過 4 毫秒) 就必須增加系統資源
  3. 在每個提示工作階段中,預測各工作階段所需的執行時間。 一般來說,時間長度相當於影格間隔,但應用程式可以使用 較短的間隔。

以下說明如何實際應用理論:

初始化 PerformanceHintManager 和 createHintSession

使用系統服務取得管理員,並為執行緒建立提示工作階段 或執行緒群組處理相同工作負載

C++

int32_t tids[1];
tids[0] = gettid();
int64_t target_fps_nanos = getFpsNanos();
APerformanceHintManager* hint_manager = APerformanceHint_getManager();
APerformanceHintSession* hint_session =
  APerformanceHint_createSession(hint_manager, tids, 1, target_fps_nanos);

Java

int[] tids = {
  android.os.Process.myTid()
};
long targetFpsNanos = getFpsNanos();
PerformanceHintManager performanceHintManager =
  (PerformanceHintManager) this.getSystemService(Context.PERFORMANCE_HINT_SERVICE);
PerformanceHintManager.Session hintSession =
  performanceHintManager.createHintSession(tids, targetFpsNanos);

視需要設定執行緒

發布日期

Android 11 (API 級別 34)

使用 setThreads 在其他執行緒時,PerformanceHintManager.Session 函式 供稍後新增舉例來說,如果建立物理執行緒 然後需要將其新增至工作階段,您可以使用這個 setThreads API。

C++

auto tids = thread_ids.data();
std::size_t size = thread_ids_.size();
APerformanceHint_setThreads(hint_session, tids, size);

Java

int[] tids = new int[3];

// add all your thread IDs. Remember to use android.os.Process.myTid() as that
// is the linux native thread-id.
// Thread.currentThread().getId() will not work because it is jvm's thread-id.
hintSession.setThreads(tids);

如要指定較低的 API 級別,則需刪除工作階段 每次需要變更執行緒 ID 時,再重新建立新的工作階段。

回報實際工作時間長度

以奈秒為單位追蹤完成工作所需的實際時間長度,並產生報表 每個週期完成工作後 系統就會將其送回系統中舉例來說 這要用於轉譯執行緒,請在每個影格上呼叫這個程式碼。

如要穩定取得實際時間,請使用:

C++

clock_gettime(CLOCK_MONOTONIC, &clock); // if you prefer "C" way from <time.h>
// or
std::chrono::high_resolution_clock::now(); // if you prefer "C++" way from <chrono>

Java

System.nanoTime();

例如:

C++

// All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)`
auto start_time = std::chrono::high_resolution_clock::now();

// do work

auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
int64_t actual_duration = static_cast<int64_t>(duration);

APerformanceHint_reportActualWorkDuration(hint_session, actual_duration);

Java

long startTime = System.nanoTime();

// do work

long endTime = System.nanoTime();
long duration = endTime - startTime;

hintSession.reportActualWorkDuration(duration);

視需要更新目標工作時間長度

每當目標工作持續時間改變時,例如玩家選擇 不同的目標每秒影格數,請呼叫 updateTargetWorkDuration 方法,讓系統知道 OS 才能根據 複製到新的目標您不必在每個影格都呼叫這個程式碼,只需 在目標時間長度變更時呼叫此函式。

C++

APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);

Java

hintSession.updateTargetWorkDuration(targetDuration);