Membuat profil Game WebGL dengan tanda about:tracing

Lilli Thompson
Lilli Thompson

Jika tidak dapat mengukurnya, Anda tidak dapat meningkatkannya.

Lord Kelvin

Agar game HTML5 berjalan lebih cepat, Anda harus terlebih dahulu menentukan bottleneck performa, tetapi hal ini bisa jadi sulit. Mengevaluasi data frame per detik (FPS) adalah langkah awal, tetapi untuk melihat gambaran lengkapnya, Anda harus memahami nuansa dalam aktivitas Chrome.

Alat about:tracing memberikan insight yang membantu Anda menghindari solusi cepat yang ditujukan untuk peningkatan performa, tetapi pada dasarnya merupakan tebakan yang baik. Anda akan menghemat banyak waktu dan tenaga, mendapatkan gambaran yang lebih jelas tentang apa yang dilakukan Chrome dengan setiap frame, dan menggunakan informasi ini untuk mengoptimalkan game.

Halo about:tracing

Alat about:tracing Chrome memberi Anda jendela ke semua aktivitas Chrome selama jangka waktu tertentu dengan tingkat perincian yang sangat banyak sehingga Anda mungkin merasa kewalahan pada awalnya. Banyak fungsi di Chrome yang dilengkapi dengan instrumentasi untuk pelacakan secara langsung, sehingga tanpa melakukan instrumentasi manual, Anda tetap dapat menggunakan about:tracing untuk melacak performa. (Lihat bagian selanjutnya tentang cara melakukan instrumentasi JS secara manual)

Untuk melihat tampilan pelacakan, cukup ketik "about:tracing" di omnibox (kolom URL) Chrome.

Omnibox Chrome
Ketik "about:tracing" di omnibox Chrome

Dari alat pelacakan, Anda dapat mulai merekam, menjalankan game selama beberapa detik, lalu melihat data rekaman aktivitas. Berikut adalah contoh tampilan data:

Hasil pelacakan sederhana
Hasil pelacakan sederhana

Ya, memang membingungkan. Mari kita bahas cara membacanya.

Setiap baris mewakili proses yang sedang dibuat profilnya, sumbu kiri-kanan menunjukkan waktu, dan setiap kotak berwarna adalah panggilan fungsi berinstrumen. Ada baris untuk sejumlah jenis resource yang berbeda. Yang paling menarik untuk pembuatan profil game adalah CrGpuMain, yang menunjukkan apa yang dilakukan Unit Pemrosesan Grafis (GPU), dan CrRendererMain. Setiap rekaman aktivitas berisi baris CrRendererMain untuk setiap tab yang terbuka selama periode rekaman aktivitas (termasuk tab about:tracing itu sendiri).

Saat membaca data rekaman aktivitas, tugas pertama Anda adalah menentukan baris CrRendererMain yang sesuai dengan game Anda.

Hasil pelacakan sederhana ditandai
Hasil pelacakan sederhana ditandai

Dalam contoh ini, dua kandidatnya adalah: 2216 dan 6516. Sayangnya, saat ini tidak ada cara yang efektif untuk memilih aplikasi Anda kecuali untuk mencari baris yang melakukan banyak pembaruan berkala (atau jika Anda telah melengkapi kode dengan titik rekaman aktivitas secara manual, untuk mencari baris yang berisi data rekaman aktivitas Anda). Dalam contoh ini, sepertinya 6516 menjalankan loop utama dari frekuensi update. Jika Anda menutup semua tab lain sebelum memulai rekaman aktivitas, menemukan CrRendererMain yang benar akan lebih mudah. Namun, mungkin masih ada baris CrRendererMain untuk proses selain game Anda.

Menemukan bingkai Anda

Setelah Anda menemukan baris yang benar di alat pelacakan untuk game, langkah berikutnya adalah menemukan loop utama. Loop utama terlihat seperti pola berulang dalam data pelacakan. Anda dapat menjelajahi data rekaman aktivitas menggunakan tombol W, A, S, D: A dan D untuk berpindah ke kiri atau kanan (mundur dan maju dalam waktu) dan W dan S untuk memperbesar dan memperkecil data. Anda mengharapkan loop utama menjadi pola yang berulang setiap 16 milidetik jika game berjalan pada 60 Hz.

Sepertinya tiga frame eksekusi
Terlihat seperti tiga frame eksekusi

Setelah menemukan heartbeat game, Anda dapat mempelajari apa yang sebenarnya dilakukan kode Anda di setiap frame. Gunakan W, A, S, D untuk memperbesar hingga Anda dapat membaca teks di kotak fungsi.

Mempelajari frame eksekusi lebih dalam
Mempelajari frame eksekusi secara mendalam

Kumpulan kotak ini menampilkan serangkaian panggilan fungsi, dengan setiap panggilan diwakili oleh kotak berwarna. Setiap fungsi dipanggil oleh kotak di atasnya, jadi dalam hal ini, Anda dapat melihat bahwa MessageLoop::RunTask memanggil RenderWidget::OnSwapBuffersComplete, yang pada gilirannya memanggil RenderWidget::DoDeferredUpdate, dan seterusnya. Dengan membaca data ini, Anda bisa mendapatkan gambaran lengkap tentang apa yang memanggil apa dan berapa lama waktu yang diperlukan untuk setiap eksekusi.

Namun, di sinilah masalahnya. Informasi yang ditampilkan oleh about:tracing adalah panggilan fungsi mentah dari kode sumber Chrome. Anda dapat membuat tebakan yang tepat tentang apa yang dilakukan setiap fungsi dari namanya, tetapi informasinya tidak terlalu mudah digunakan. Hal ini berguna untuk melihat keseluruhan alur frame, tetapi Anda memerlukan sesuatu yang sedikit lebih mudah dibaca manusia untuk benar-benar mengetahui apa yang terjadi.

Menambahkan tag rekaman aktivitas

Untungnya, ada cara mudah untuk menambahkan instrumentasi manual ke kode Anda guna membuat data rekaman aktivitas: console.time dan console.timeEnd.

console.time("update");
update
();
console
.timeEnd("update");
console
.time("render");
update
();
console
.timeEnd("render");

Kode di atas membuat kotak baru di nama tampilan pelacakan dengan tag yang ditentukan, sehingga jika menjalankan ulang aplikasi, Anda akan melihat kotak "update" dan "render" yang menunjukkan waktu yang berlalu antara panggilan awal dan akhir untuk setiap tag.

Tag yang ditambahkan secara manual
Tag ditambahkan secara manual

Dengan menggunakan ini, Anda dapat membuat data pelacakan yang dapat dibaca manusia untuk melacak hotspot dalam kode Anda.

GPU atau CPU?

Dengan grafis yang dipercepat hardware, salah satu pertanyaan terpenting yang dapat Anda ajukan selama pembuatan profil adalah: Apakah kode ini terikat GPU atau terikat CPU? Dengan setiap frame, Anda akan melakukan beberapa pekerjaan rendering di GPU dan beberapa logika di CPU; untuk memahami apa yang membuat game Anda lambat, Anda harus melihat bagaimana pekerjaan diseimbangkan di kedua resource tersebut.

Pertama, temukan baris pada tampilan pelacakan bernama CrGPUMain, yang menunjukkan apakah GPU sedang sibuk pada waktu tertentu.

Rekaman aktivitas GPU dan CPU

Anda dapat melihat bahwa setiap frame game menyebabkan CPU bekerja di CrRendererMain serta di GPU. Rekaman aktivitas di atas menunjukkan kasus penggunaan yang sangat sederhana, yaitu CPU dan GPU tidak ada aktivitas selama sebagian besar frame 16 md.

Tampilan pelacakan sangat membantu saat Anda memiliki game yang berjalan lambat dan tidak yakin resource mana yang sudah dimaksimalkan. Melihat hubungan antara baris GPU dan CPU adalah kunci untuk proses debug. Ambil contoh yang sama seperti sebelumnya, tetapi tambahkan sedikit pekerjaan tambahan dalam loop update.

console.time("update");
doExtraWork
();
update
(Math.min(50, now - time));
console
.timeEnd("update");

console
.time("render");
render
();
console
.timeEnd("render");

Sekarang Anda akan melihat rekaman aktivitas yang terlihat seperti ini:

Rekaman aktivitas GPU dan CPU

Apa yang dapat kita pelajari dari rekaman aktivitas ini? Kita dapat melihat bahwa frame yang digambarkan berkisar dari sekitar 2270 md hingga 2320 md, yang berarti setiap frame memerlukan waktu sekitar 50 md (frekuensi gambar 20 Hz). Anda dapat melihat potongan kotak berwarna yang mewakili fungsi render di samping kotak update, tetapi bingkai sepenuhnya didominasi oleh update itu sendiri.

Berbeda dengan yang terjadi di CPU, Anda dapat melihat bahwa GPU masih tidak ada aktivitasnya untuk sebagian besar frame. Untuk mengoptimalkan kode ini, Anda dapat mencari operasi yang dapat dilakukan dalam kode shader dan memindahkannya ke GPU untuk memanfaatkan resource secara optimal.

Bagaimana jika kode shader itu sendiri lambat dan GPU terlalu banyak bekerja? Bagaimana jika kita menghapus pekerjaan yang tidak perlu dari CPU dan menambahkan beberapa pekerjaan dalam kode fragment shader. Berikut adalah shader fragmen yang tidak perlu mahal:

#ifdef GL_ES
precision highp
float;
#endif
void main(void) {
 
for(int i=0; i<9999; i++) {
    gl_FragColor
= vec4(1.0, 0, 0, 1.0);
 
}
}

Seperti apa tampilan pelacakan kode yang menggunakan shader tersebut?

Rekaman aktivitas GPU dan CPU saat menggunakan kode GPU yang lambat
Rekaman aktivitas GPU dan CPU saat menggunakan kode GPU yang lambat

Sekali lagi, perhatikan durasi frame. Di sini, pola berulang berlangsung dari sekitar 2.750 md hingga 2.950 md, dengan durasi 200 md (kecepatan frame sekitar 5 Hz). Baris CrRendererMain hampir sepenuhnya kosong, yang berarti CPU sebagian besar waktu tidak ada aktivitas, sementara GPU kelebihan beban. Ini adalah tanda pasti bahwa shader Anda terlalu berat.

Jika tidak mengetahui dengan tepat apa yang menyebabkan kecepatan frame rendah, Anda dapat mengamati update 5 Hz dan tergoda untuk membuka kode game dan mulai mencoba mengoptimalkan atau menghapus logika game. Dalam hal ini, hal itu sama sekali tidak akan berguna, karena logika dalam loop game bukanlah yang menghabiskan waktu. Faktanya, yang ditunjukkan oleh rekaman aktivitas ini adalah melakukan lebih banyak tugas CPU pada setiap frame pada dasarnya akan "bebas" karena CPU tidak ada aktivitas, sehingga memberinya lebih banyak tugas tidak akan memengaruhi waktu yang diperlukan frame.

Contoh Nyata

Sekarang, mari kita lihat tampilan data pelacakan dari game sungguhan. Salah satu hal keren tentang game yang dibuat dengan teknologi web terbuka adalah Anda dapat melihat apa yang terjadi di produk favorit Anda. Jika ingin menguji alat pembuatan profil, Anda dapat memilih judul WebGL favorit dari Chrome Web Store dan membuat profilnya dengan about:tracing. Ini adalah contoh rekaman aktivitas yang diambil dari game WebGL Skid Racer yang luar biasa.

Melacak game sungguhan
Melacak game sungguhan

Sepertinya setiap frame memerlukan waktu sekitar 20 md, yang berarti kecepatan frame sekitar 50 FPS. Anda dapat melihat bahwa pekerjaan seimbang antara CPU dan GPU, tetapi GPU adalah resource yang paling banyak diminati. Jika Anda ingin melihat seperti apa membuat profil contoh nyata game WebGL, coba mainkan beberapa judul Chrome Web Store yang dibuat dengan WebGL, termasuk:

Kesimpulan

Jika Anda ingin game berjalan pada 60 Hz, untuk setiap frame, semua operasi Anda harus sesuai dengan waktu CPU 16 md dan waktu GPU 16 md. Anda memiliki dua resource yang dapat digunakan secara paralel, dan Anda dapat mengalihkan pekerjaan di antara keduanya untuk memaksimalkan performa. Tampilan about:tracing Chrome adalah alat yang sangat berharga untuk mendapatkan insight tentang apa yang sebenarnya dilakukan kode Anda dan akan membantu Anda memaksimalkan waktu pengembangan dengan mengatasi masalah yang tepat.

Apa langkah selanjutnya?

Selain GPU, Anda juga dapat melacak bagian lain runtime Chrome. Chrome Canary, versi awal Chrome, dilengkapi dengan instrumen untuk melacak IO, IndexedDB, dan beberapa aktivitas lainnya. Anda harus membaca artikel Chromium ini untuk memahami lebih dalam status peristiwa pelacakan saat ini.

Jika Anda adalah developer game web, pastikan untuk menonton video di bawah. Ini adalah presentasi dari tim Game Developer Advocate Google di GDC 2012 tentang pengoptimalan performa untuk game Chrome: