Tips pengoptimalan CPU dan GPU

Dokumen ini menunjukkan cara mengoptimalkan performa game dengan menggunakan alat untuk mengidentifikasi dan menyelesaikan bottleneck CPU dan GPU.

Pengoptimalan CPU

Jika analisis menunjukkan bahwa game terikat CPU, penyelidikan lebih lanjut sangat penting. Hal ini memerlukan identifikasi thread atau API tertentu yang menyebabkan hambatan dan mengurangi FPS.

Untuk pengoptimalan CPU, solusi universal umumnya tidak efektif. Sebagai gantinya, Anda harus mengidentifikasi beban kerja yang paling berat berdasarkan game atau adegan, lalu mengoptimalkan logika dan fungsi yang relevan.

Alat perekaman waktu game engine

Alat berikut dapat membantu analisis ini:

Insight tidak nyata

Dalam project Unreal Engine, Alat Unreal Insight memfasilitasi analisis informasi rekaman aktivitas waktu untuk setiap thread yang membentuk frame.

Sebagai ilustrasi, GameThread biasanya menggunakan proporsi terbesar dari waktu CPU, terutama karena Tick Time. Selain itu, sebagian besar Tick Time digunakan oleh tugas yang terkait dengan FActorComponentTickFunction.

Untuk mengoptimalkan FActorComponentTick, Anda harus mengecualikan penghitungan dan menerapkan penghapusan untuk karakter dan objek yang diposisikan di luar bidang pandang kamera. Selain itu, memanfaatkan animasi berbasis LOD (Level of Detail) dapat menghasilkan peningkatan performa lebih lanjut.

Linimasa rekaman aktivitas Unreal Insight yang menunjukkan waktu eksekusi GameThread, RenderThread, dan RHIThread
Rekaman aktivitas insight Unreal dengan GameThread, RenderThread, dan RHIThread (klik untuk memperbesar).

Unity Profiler (Unity)

Analisis menggunakan Unity Profiler mengungkapkan bahwa Thread Utama menggunakan lebih dari 45 md, dengan PostLateUpdate.FinishFrameRendering menggunakan 16,23 md, sehingga menjadikannya operasi yang paling memakan waktu. Dalam hal ini, beberapa pemanggilan Inl_RenderCameraStack diamati. Sebaiknya pastikan kebutuhan kamera yang diaktifkan dan optimalkan kamera tersebut dengan tepat.

Linimasa Unity Profiler yang menunjukkan Thread Utama menunggu Gfx.WaitForPresentOnGfxThread
Contoh terikat GPU untuk Unity Profiler (klik untuk memperbesar).

Alat pembuatan profil tingkat sistem

Gunakan alat pembuatan profil berikut:

Perfetto

Dengan menggunakan rekaman aktivitas Perfetto, Anda dapat menentukan penetapan core CPU dan detail eksekusi setiap thread di perangkat yang didukung Android. Hal ini memungkinkan Anda mengidentifikasi hambatan performa dengan menganalisis data eksekusi thread.

Kasus overhead CPU

Rekaman aktivitas menunjukkan bahwa beban kerja di GameThread dan RenderThread menyebabkan penundaan di QueuePresent RHI Thread, sehingga menyebabkan skenario terikat CPU, berdasarkan VSync.

Rekaman aktivitas Perfetto yang menunjukkan waktu eksekusi untuk GameThread, RenderThread, dan RHIThread
Rekaman aktivitas Perfetto dengan detail eksekusi CPU (klik untuk memperbesar).

Kasus overhead GPU

Rekaman aktivitas menunjukkan bahwa penyelesaian GPU itu sendiri melebihi 25 md, yang menandakan skenario terikat GPU.

Rekaman aktivitas Perfetto yang menampilkan blok penyelesaian GPU yang menunggu penyelesaian GPU
Rekaman aktivitas Perfetto dengan detail overhead GPU (klik untuk memperbesar).

Simpleperf

Untuk mengidentifikasi fungsi dengan penggunaan CPU saat ini tertinggi, simpleperf dapat digunakan. Untuk hasil yang optimal, sebaiknya urutkan fungsi ini untuk memprioritaskan dan mengatasi fungsi dengan penggunaan tertinggi terlebih dahulu.

Output Simpleperf yang menampilkan fungsi dengan penggunaan CPU tertinggi
Pembuatan profil CPU Simpleperf: Menganalisis hierarki panggilan fungsi dan pemanfaatan resource (klik untuk memperbesar).

Simpleperf membantu Anda memeriksa data tentang fungsi yang menggunakan waktu CPU paling banyak. Untuk mengoptimalkan penggunaan CPU, mulailah dengan fungsi yang paling banyak menggunakan CPU. Dalam contoh ini, USkeletalMeshComponent, yang terkait dengan animasi di ActorComponentTickFunctions, menggunakan CPU paling banyak.

Pengoptimalan GPU

Jika analisis menunjukkan bahwa game terikat GPU, penyelidikan lebih lanjut sangat penting. Hal ini memerlukan penggunaan berbagai alat dan teknik untuk pengoptimalan dan analisis GPU.

Untuk mengoptimalkan GPU, gunakan debugger frame untuk menganalisis pipeline render dan panggilan gambar untuk setiap adegan. Selain itu, Anda harus memahami arsitektur GPU dan perilaku pipeline secara menyeluruh untuk mengidentifikasi operasi yang tidak perlu atau area yang perlu dioptimalkan.

Bagian berikut menjelaskan metode dan alat untuk pengoptimalan GPU.

Menghilangkan RenderPass yang tidak perlu

Untuk meningkatkan performa rendering dan mengurangi beban kerja GPU, hilangkan proses rendering yang tidak perlu. Hal ini mencakup semua render pass yang tidak memiliki panggilan gambar atau yang outputnya tidak digunakan dalam frame akhir.

Gunakan debugger GPU, seperti RenderDoc, untuk menganalisis pipeline rendering dan mengidentifikasi peluang pengoptimalan.

  1. Tidak Ada Panggilan Draw: Periksa apakah render pass menyertakan panggilan draw. Jika tidak ada panggilan gambar, hapus kartu.

  2. Output yang Tidak Digunakan: Periksa apakah proses berikutnya mengakses atau menampilkan output proses rendering, misalnya, warna atau kedalaman. Jika tidak, hapus kartu tersebut.

  3. Kartu yang Dapat Digabungkan: Identifikasi kartu yang dapat Anda gabungkan:

    • Framebuffer atau lampiran yang sama
    • Operasi muat atau penyimpanan yang kompatibel
    • Tidak ada penghalang dependensi di antaranya
Browser peristiwa RenderDoc yang menampilkan panggilan gambar dan render pass Vulkan
Urutan perintah RenderPass dan GPU di RenderDoc (klik untuk memperbesar).

Meminimalkan operasi pemuatan atau penyimpanan

Operasi pemuatan atau penyimpanan sangat menguras resource karena menggunakan banyak memori. Minimalkan operasi load-store yang tidak perlu. Lakukan tindakan ini hanya jika lampiran dalam RenderPass diperlukan. Jika tidak, ganti dengan operasi Clear atau Don't care untuk mengurangi overhead.

Cara mengoptimalkan

Gunakan debugger GPU, seperti RenderDoc, untuk menganalisis pipeline rendering dan mengidentifikasi peluang pengoptimalan berikut:

  1. Pemuatan: Jika lampiran render pass tidak menggunakan data dari pass atau lampiran sebelumnya, operasi pemuatan tidak diperlukan. Dalam kasus seperti ini, penggunaan Don't care atau Clear dapat mengurangi overhead.

  2. Store: Jika lampiran render pass tidak digunakan setelah render pass saat ini, operasi penyimpanan tidak diperlukan. Dalam kasus seperti itu, gunakan Don't care atau Clear.

  3. Ganti: Tentukan apakah setelan pemuatan atau penyimpanan saat ini dapat diganti dengan Clear atau Don't Care tanpa memengaruhi frame akhir.

Pemeriksa resource dan browser peristiwa RenderDoc yang menganalisis tata letak gambar dan meneruskan render
Analisis pipeline rendering RenderDoc (klik untuk memperbesar).

Menghindari penghapusan untuk mengaktifkan Early-Z

Early-Z meningkatkan performa di platform seluler. Namun, instruksi discard dalam shader akan otomatis menonaktifkan Early-Z. Jika petunjuk discard tidak penting, hapus petunjuk tersebut.

Akselerasi Early-Z

Pengoptimalan ini secara signifikan mengurangi operasi shader fragmen dan meningkatkan performa GPU.

Early-Z Pengujian kedalaman dan stensil

Tabel yang membandingkan metrik performa CPU dan GPU saat Early-Z diaktifkan versus dinonaktifkan
Dampak performa akselerasi Early-Z (klik untuk memperbesar).

Cara mengoptimalkan

Gunakan debugger GPU, seperti RenderDoc, untuk menganalisis pipeline rendering dan mengidentifikasi peluang pengoptimalan berikut:

  1. Penggunaan discard dalam shader fragmen: Kata kunci discard mencegah GPU melakukan pengujian kedalaman awal karena visibilitas fragmen tidak diketahui sebelumnya.

  2. Modifikasi gl_FragDepth: Memodifikasi gl_FragDepth secara dinamis mengubah kedalaman fragmen, yang menonaktifkan pengoptimalan Z Awal karena kedalaman akhir tidak diketahui sebelum pemrosesan fragmen.

  3. Diaktifkan dari alfa ke cakupan: Jika diaktifkan dari alfa ke cakupan (sering digunakan dalam rendering MSAA), cakupan fragmen bergantung pada nilai alfa. Hal ini dapat menunda pengujian kedalaman dan menonaktifkan Early-Z.

Perbandingan fragmen per piksel dengan dan tanpa kata kunci shader buang
RenderDoc GPU debugger untuk analisis (klik untuk memperbesar).

Mengoptimalkan format tekstur

Pemilihan format tekstur yang optimal akan mengurangi penggunaan memori, meningkatkan efisiensi bandwidth, dan meningkatkan performa rendering. Menggunakan format presisi tinggi yang berlebihan dapat membuang-buang resource GPU tanpa memberikan keuntungan visual.

Cara mengoptimalkan

Gunakan debugger GPU, seperti RenderDoc, untuk menganalisis pipeline rendering dan mengidentifikasi peluang pengoptimalan berikut:

  1. Gunakan D24S8, bukan D32S8 untuk buffer stensil kedalaman: Penggunaan D24S8 untuk buffer stensil kedalaman mengurangi penggunaan memori sebesar 20% dibandingkan dengan D32S8, dengan sedikit atau tanpa perbedaan kualitas visual yang terlihat di sebagian besar aplikasi.
  2. Gunakan kompresi ASTC untuk tekstur warna: Kompresi ASTC mengurangi penggunaan memori tekstur secara signifikan—hingga 8x dibandingkan dengan format yang tidak dikompresi—sekaligus mempertahankan kualitas visual yang tinggi.
  3. Gunakan format half-float, bukan full-float: Gunakan R16F atau RG16F untuk mengurangi bandwidth memori dan konsumsi penyimpanan. Format ini sangat cocok untuk buffer pasca-pemrosesan.

Mengoptimalkan kompleksitas geometri

Meminimalkan kompleksitas geometris meningkatkan performa rendering, terutama di perangkat seluler dengan kemampuan GPU terbatas. Hal ini melibatkan penggunaan jumlah verteks dan segitiga yang lebih sedikit, menggabungkan objek untuk mengurangi panggilan gambar, dan menghilangkan geometri yang tidak dirender atau tidak diperlukan. Teknik seperti penyederhanaan mesh, Level Detail (LOD), dan penghapusan frustum atau oklusi dapat mengurangi beban kerja GPU secara signifikan dan meningkatkan kecepatan frame.

Cara mengoptimalkan

Gunakan alat pembuatan profil dan debugger GPU, seperti RenderDoc, Android GPU Inspector, atau penganalisis performa lainnya, untuk mengidentifikasi bottleneck performa terkait geometri.

  1. Kurangi Jumlah Segitiga: Minimalkan penggunaan poligon, terutama untuk objek kecil atau jauh.

  2. Gunakan Tingkat Detail (LOD): Berdasarkan jarak kamera, mesh yang lebih sederhana digunakan secara otomatis.

  3. Gabungkan Mesh Kecil: Gabungkan objek statis untuk mengurangi panggilan gambar dan overhead CPU.

  4. Frustum dan Occlusion Culling: Hindari merender objek yang berada di luar tampilan atau terhalang oleh elemen lain.

Menghapus lampiran yang tidak diperlukan

Lampiran render pass (misalnya, warna, kedalaman, stensil) menggunakan bandwidth memori dan resource GPU, meskipun tidak digunakan. Menghapus lampiran yang tidak perlu atau berlebihan akan meningkatkan performa dan mengurangi konsumsi daya, terutama di platform seluler.

Cara mengoptimalkan

Gunakan alat pembuatan profil dan debugger GPU, seperti RenderDoc, Android GPU Inspector, atau penganalisis performa lainnya, untuk mengidentifikasi bottleneck performa terkait geometri.

  1. Periksa penggunaan sebenarnya: Apakah ada panggilan gambar atau shader yang menulis ke atau membaca dari lampiran?
  2. Analisis output frame: Gunakan RenderDoc atau utilitas serupa untuk menentukan apakah lampiran berkontribusi pada gambar akhir.
  3. Pertimbangkan lampiran sementara atau dummy: Lampiran sementara atau operasi penyimpanan 'Tidak Penting' harus digunakan untuk data sementara yang tidak memerlukan penyimpanan persisten.

Mengoptimalkan presisi shader

Menggunakan presisi yang terlalu tinggi (misalnya, highp, bukan mediump atau lowp) dalam shader akan meningkatkan beban kerja GPU, konsumsi daya, dan tekanan register, terutama pada GPU seluler. Dengan menggunakan presisi yang memadai dan terendah untuk variabel (misalnya, posisi, warna, UV), Anda dapat meningkatkan performa tanpa dampak visual yang terlihat.

Tabel yang membandingkan metrik performa CPU dan GPU saat menggunakan presisi shader mediump versus highp
Dampak performa presisi shader (klik untuk memperbesar).

Cara mengoptimalkan

Gunakan alat pembuatan profil dan debugger GPU seperti RenderDoc, Android GPU Inspector, atau penganalisis performa lainnya untuk mengidentifikasi bottleneck performa terkait geometri.

  1. Tinjau kode shader: Nilai variabel shader dan konfirmasi bahwa presisi tinggi hanya digunakan jika diperlukan, seperti untuk komputasi ruang layar atau kedalaman. Gunakan presisi sedang atau rendah untuk warna, koordinat UV, atau nilai yang tidak memerlukan presisi tinggi.

  2. Gunakan debugger GPU: Utilitas diagnostik, seperti RenderDoc atau profiler GPU seluler (misalnya, AGI, Mali/GPU Inspector), mengidentifikasi penggunaan register yang tinggi atau shader yang terhenti terkait dengan masalah presisi.

Profiler Penggunaan Bervariasi Mali menampilkan interpolasi 16-bit bersama dengan kode shader menggunakan mediump
Contoh alat pembuatan profil dan debugger GPU (klik untuk memperbesar).

Mengaktifkan penghapusan sisi belakang

Merender segitiga yang menghadap menjauhi kamera (sisi belakang) sering kali tidak diperlukan untuk objek solid.

Cara mengoptimalkan

Penggunaan VK_CULL_MODE_NONE dapat memengaruhi performa secara negatif karena memaksa GPU merender sisi depan dan belakang, yang meningkatkan beban kerja rendering.

Log perintah Vulkan yang menampilkan vkCmdSetCullMode yang ditetapkan ke VK_CULL_MODE_NONE
Log debug dengan penghapusan sisi belakang (klik untuk memperbesar).

Meminimalkan overdraw dalam adegan UI

Hilangkan panggilan gambar dan proses rendering yang tidak perlu, terutama di adegan UI, untuk meningkatkan performa rendering dan mengurangi beban kerja GPU. Misalnya, dalam adegan UI di mana seluruh dunia dirender sebelum melapisi UI di seluruh layar, merender dunia menjadi berlebihan.

Cara mengoptimalkan

Gunakan debugger GPU, seperti RenderDoc, untuk menganalisis pipeline rendering dan mengidentifikasi peluang pengoptimalan berikut:

  1. Verifikasi tidak adanya overdraw yang berlebihan. Dalam konteks antarmuka pengguna, tempat seluruh layar mungkin dirender, pastikan bahwa proses rendering sebelumnya tidak digambar berlebihan tanpa alasan.
  2. Aktifkan pengujian dan seleksi kedalaman untuk mengoptimalkan performa.
  3. Pertimbangkan urutan rendering dari depan ke belakang.
Penampil tekstur dan browser peristiwa RenderDoc mengidentifikasi proses rendering overdraw yang tidak perlu
Contoh untuk menghilangkan panggilan gambar dan proses rendering yang tidak diperlukan (klik untuk memperbesar).