Dirilis:
Android 12 (Level API 31) - Performance Hint API
Android 13 (API Level 33) - Performance Hint Manager di NDK API
(Pratinjau) Android 15 (DP1) - reportActualWorkDuration()
Dengan petunjuk performa CPU, game dapat memengaruhi performa CPU dinamis agar lebih sesuai dengan kebutuhannya. Pada sebagian besar perangkat, Android secara dinamis menyesuaikan kecepatan clock CPU dan jenis core untuk suatu workload berdasarkan permintaan sebelumnya. Jika beban kerja menggunakan lebih banyak sumber daya CPU, kecepatan clock akan ditingkatkan dan akhirnya dipindahkan ke inti yang lebih besar. Jika beban kerja menggunakan lebih sedikit sumber daya, maka Android akan menurunkan alokasi sumber daya. Dengan ADPF, aplikasi atau {i>game<i} dapat mengirim sinyal tambahan tentang kinerja dan tenggat waktunya. Ini membantu sistem melakukan peningkatan secara lebih agresif (meningkatkan performa) dan menurunkan bekerja dengan cepat ketika beban kerja selesai (menghemat penggunaan daya).
Kecepatan clock
Saat perangkat Android menyesuaikan kecepatan clock CPU secara dinamis, frekuensinya dapat
mengubah performa kode. Merancang kode yang menangani jam dinamis
kecepatan tinggi penting untuk memaksimalkan kinerja, menjaga
status, dan menggunakan daya secara efisien. Anda tidak dapat menetapkan frekuensi CPU secara langsung
dalam kode aplikasi Anda. Hasilnya, cara umum bagi aplikasi untuk mencoba berjalan pada
Kecepatan clock CPU adalah untuk menjalankan loop sibuk di thread latar belakang sehingga beban kerja
tampaknya lebih menuntut. Ini adalah praktik yang buruk karena
membuang daya dan meningkatkan
beban termal pada perangkat saat aplikasi
benar-benar tidak menggunakan beban
Google Cloud Platform. API PerformanceHint
CPU dirancang untuk mengatasi masalah ini. Menurut
memberi tahu sistem tentang durasi
kerja yang sebenarnya dan durasi kerja target,
Android akan bisa mendapatkan gambaran
tentang kebutuhan CPU aplikasi dan mengalokasikan
resource secara efisien. Hal ini akan menghasilkan performa optimal dengan daya yang efisien
tingkat konsumsi konten.
Jenis core
Jenis core CPU yang digunakan untuk menjalankan game Anda adalah faktor performa yang penting. Perangkat Android sering mengubah core CPU yang ditetapkan ke thread secara dinamis berdasarkan perilaku beban kerja terbaru. Penetapan core CPU bahkan lebih kompleks pada SoC dengan beberapa jenis core. Pada beberapa perangkat ini, core yang lebih besar hanya dapat digunakan sebentar tanpa beralih ke kondisi yang tidak berkelanjutan secara termal.
Game Anda tidak boleh mencoba menetapkan afinitas core CPU karena alasan berikut:
- Jenis core terbaik untuk beban kerja bervariasi menurut model perangkat.
- Keberlanjutan menjalankan core yang lebih besar bervariasi menurut SoC dan berbagai solusi termal yang disediakan oleh setiap model perangkat.
- Dampak lingkungan pada status termal dapat semakin mempersulit pilihan core. Misalnya, cuaca atau casing ponsel dapat mengubah status termal perangkat.
- Pemilihan core tidak dapat mengakomodasi perangkat baru dengan performa tambahan dan kemampuan termal. Akibatnya, perangkat sering kali mengabaikan afinitas prosesor game.
Contoh perilaku penjadwal Linux default
![Perilaku Scheduler Linux](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_linux_sched_behavior.png?authuser=9&hl=id)
PerformanceHint API mengabstraksi lebih dari sekadar latensi DVFS
![Abstrak ADPF lebih dari Latensi DVFS](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_dvfs_latency.png?authuser=9&hl=id)
- Jika tugas perlu dijalankan pada CPU tertentu, PerformanceHint API tahu cara membuat keputusan itu atas nama Anda.
- Oleh karena itu, Anda tidak perlu menggunakan afinitas.
- Perangkat dilengkapi dengan berbagai topologi; Karakteristik daya dan termal terlalu bervariasi untuk dipaparkan kepada pengembang aplikasi.
- Anda tidak dapat membuat asumsi apa pun tentang sistem dasar yang Anda jalankan.
Solusi
ADPF menyediakan PerformanceHintManager
sehingga game dapat mengirimkan petunjuk performa ke Android terkait kecepatan clock CPU dan
jenis inti. OS kemudian dapat memutuskan cara terbaik untuk menggunakan petunjuk berdasarkan SoC dan
solusi termal perangkat. Jika aplikasi Anda menggunakan API ini beserta pemantauan status termal,
aplikasi dapat memberikan petunjuk yang lebih tepat ke OS, bukan menggunakan
loop sibuk dan teknik coding lainnya yang dapat menyebabkan throttling.
Berikut ini cara game menggunakan petunjuk performa:
- Buat sesi petunjuk untuk thread utama yang berperilaku serupa. Contoh:
- Thread rendering dan dependensinya mendapatkan satu sesi
- Di Cocos, thread mesin utama dan thread render mendapatkan satu sesi
- Di Unity, integrasikan plugin Penyedia Android Performa Adaptif
- Di Unreal, integrasikan plugin Unreal Adaptive Performance dan gunakan Opsi skalabilitas untuk mendukung berbagai tingkat kualitas
- Thread IO mendapatkan sesi satunya
- Thread audio mendapatkan sesi ketiga
- Thread rendering dan dependensinya mendapatkan satu sesi
- Game harus melakukannya lebih awal, setidaknya 2 md, dan sebaiknya lebih dari 4 md sebelum sebuah sesi memerlukan peningkatan resource sistem.
- Di setiap sesi petunjuk, prediksikan durasi yang diperlukan untuk menjalankan setiap sesi. Durasi umumnya setara dengan interval {i>frame<i}, tetapi aplikasi dapat menggunakan yang lebih pendek jika beban kerja tidak bervariasi secara signifikan di seluruh frame.
Berikut adalah cara mempraktikkan teori:
Melakukan inisialisasi PerformanceHintManager dan createHintSession
Meminta pengelola menggunakan layanan sistem dan membuat sesi petunjuk untuk thread Anda atau grup thread yang bekerja pada workload yang sama.
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);
Menyetel thread jika perlu
Dirilis:
Android 11 (Level API 34)
Menggunakan setThreads
fungsi PerformanceHintManager.Session
saat Anda memiliki thread lain
yang perlu ditambahkan nanti. Misalnya, jika Anda membuat thread fisika
nanti dan perlu menambahkannya ke sesi, Anda dapat menggunakan setThreads
API ini.
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);
Jika Anda menargetkan API Level yang lebih rendah, Anda harus menghancurkan sesi dan membuat ulang sesi baru setiap kali Anda perlu mengubah ID thread.
Durasi Pekerjaan Sebenarnya Laporan
Lacak durasi sebenarnya yang diperlukan untuk menyelesaikan pekerjaan dalam nanodetik dan laporkan ke sistem setelah menyelesaikan pekerjaan pada setiap siklus. Misalnya, jika ini untuk thread rendering Anda, panggil metode ini di setiap frame.
Untuk mendapatkan waktu aktual dengan andal, gunakan:
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();
Contoh:
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);
Perbarui Durasi Kerja Target jika diperlukan
Setiap kali durasi kerja target Anda berubah, misalnya jika pemain memilih
fps target yang berbeda, panggil updateTargetWorkDuration
untuk memberi tahu sistem sehingga OS
dapat menyesuaikan sumber daya sesuai
dengan target baru. Anda tidak harus memanggilnya
di setiap {i>frame<i} dan hanya perlu
memanggilnya saat durasi target berubah.
C++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
Java
hintSession.updateTargetWorkDuration(targetDuration);