Dirilis:
Android 12 (Level API 31) - Performance Hint API
Android 13 (Level API 33) - Performance Hint Manager di NDK API
(Pratinjau) Android 15 (DP1) - reportActualWorkDuration()
Dengan petunjuk performa CPU, aplikasi dapat memengaruhi perilaku performa CPU dinamis agar lebih sesuai dengan kebutuhannya. Pada sebagian besar perangkat, Android secara dinamis menyesuaikan kecepatan clock dan jenis core CPU untuk beban kerja berdasarkan permintaan sebelumnya. Jika beban kerja menggunakan lebih banyak resource CPU, kecepatan clock akan ditingkatkan dan beban kerja pada akhirnya akan dipindahkan ke core yang lebih besar. Jika beban kerja menggunakan lebih sedikit resource, Android akan menurunkan alokasi resource. Dengan ADPF, aplikasi dapat mengirimkan sinyal tambahan tentang performa dan batas waktunya. Hal ini membantu sistem meningkatkan kecepatan secara lebih agresif (meningkatkan performa) dan menurunkan kecepatan clock dengan cepat saat beban kerja selesai (menghemat penggunaan daya).
Kecepatan clock
Saat perangkat Android menyesuaikan kecepatan clock CPU secara dinamis, frekuensi tersebut dapat
mengubah performa kode Anda. Mendesain kode yang menangani kecepatan clock dinamis penting untuk memaksimalkan performa, mempertahankan status termal yang aman, dan menggunakan daya secara efisien. Anda tidak dapat langsung menetapkan frekuensi CPU dalam kode aplikasi. Akibatnya, cara umum bagi aplikasi untuk mencoba berjalan pada kecepatan clock CPU yang lebih tinggi adalah dengan menjalankan loop sibuk di thread latar belakang sehingga beban kerja tampaknya lebih menuntut. Hal ini merupakan praktik yang buruk karena menguras daya dan meningkatkan
beban termal pada perangkat saat aplikasi tidak benar-benar menggunakan resource
tambahan. CPU PerformanceHint
API dirancang untuk mengatasi masalah ini.
Dengan memberi tahu sistem durasi kerja sebenarnya dan durasi kerja target, Android akan dapat memperoleh ringkasan kebutuhan CPU aplikasi dan mengalokasikan resource secara efisien. Hal ini akan menghasilkan performa optimal pada tingkat konsumsi daya yang efisien.
Jenis core
Jenis core CPU yang digunakan untuk menjalankan aplikasi 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.
Aplikasi 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 aplikasi.
Contoh perilaku penjadwal Linux default

API PerformanceHint mengabstraksi lebih dari latensi DVFS

- Jika tugas perlu dijalankan di CPU tertentu, PerformanceHint API tahu cara membuat keputusan tersebut untuk Anda.
- Oleh karena itu, Anda tidak perlu menggunakan afinitas.
- Perangkat hadir dengan berbagai topologi; Karakteristik daya dan termal terlalu bervariasi untuk diekspos ke developer aplikasi.
- Anda tidak dapat membuat asumsi apa pun tentang sistem yang mendasarinya.
Solusi
ADPF menyediakan class PerformanceHintManager
sehingga aplikasi dapat mengirimkan petunjuk performa ke Android untuk kecepatan clock CPU dan
jenis core. 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 cara mempraktikkan teori tersebut:
Melakukan inisialisasi PerformanceHintManager dan membuat createHintSession
Dapatkan pengelola menggunakan layanan sistem dan buat sesi petunjuk untuk thread atau grup thread yang mengerjakan 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);
Tetapkan thread jika perlu
Dirilis:
Android 11 (Level API 34)
Gunakan fungsi setThreads
dari PerformanceHintManager.Session
jika 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 menargetkan Level API yang lebih rendah, Anda harus menghancurkan sesi dan membuat ulang sesi baru setiap kali Anda perlu mengubah ID thread.
Melaporkan Durasi Kerja Aktual
Lacak durasi sebenarnya yang diperlukan untuk menyelesaikan pekerjaan dalam nanodetik dan laporkan ke sistem setelah pekerjaan selesai pada setiap siklus. Misalnya, jika ini untuk thread rendering Anda, panggil ini di setiap frame.
Untuk mendapatkan waktu sebenarnya secara 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);
Memperbarui Durasi Kerja Target jika diperlukan
Setiap kali durasi kerja target Anda berubah, misalnya jika pemutar memilih target fps yang berbeda, panggil metode updateTargetWorkDuration
untuk memberi tahu sistem sehingga OS dapat menyesuaikan resource sesuai dengan target baru. Anda tidak perlu memanggilnya di setiap frame dan hanya perlu
memanggilnya saat durasi target berubah.
C++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
Java
hintSession.updateTargetWorkDuration(targetDuration);