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 menemukan bottleneck performa terlebih dahulu, tetapi ini bisa jadi sulit. Mengevaluasi data frame per detik (FPS) adalah permulaan, tetapi untuk melihat gambaran lengkapnya, Anda harus benar-benar memahaminya dalam aktivitas Chrome.

Alat about:tracing memberikan wawasan yang membantu Anda menghindari solusi terburu-buru yang ditujukan untuk peningkatan kinerja, tetapi pada dasarnya merupakan tebakan dengan maksud yang baik. Anda akan menghemat banyak waktu dan energi, mendapatkan gambaran yang lebih jelas tentang apa yang dilakukan Chrome dengan setiap frame, dan menggunakan informasi ini untuk mengoptimalkan game Anda.

Halo tentang:pelacakan

Alat pelacakan Chrome menyediakan jendela ke semua aktivitas Chrome selama periode waktu dengan begitu banyak perincian sehingga Anda mungkin awalnya merasa kesulitan. Banyak fungsi di Chrome yang diinstrumentasikan untuk melacak secara langsung, sehingga tanpa melakukan instrumentasi manual apa pun, Anda masih dapat menggunakan about:pelacakan untuk melacak performa. (Lihat bagian selanjutnya tentang menginstrumentasikan JS secara manual)

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

omnibox Chrome
Ketik "about:tracing" ke dalam omnibox Chrome

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

Hasil pelacakan yang sederhana
Hasil pelacakan sederhana

Ya, hal ini sangat membingungkan. Mari kita bicara tentang 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 berbagai jenis resource. Yang paling menarik untuk pembuatan profil game adalah CrGpuMain, yang menunjukkan apa yang dilakukan Graphics Processing Unit (GPU), dan CrRendererMain. Setiap trace berisi baris CrRendererMain untuk setiap tab yang terbuka selama periode trace (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 sempurna untuk memilih aplikasi Anda kecuali untuk mencari baris yang melakukan banyak pembaruan berkala (atau jika Anda telah menginstrumentasikan kode Anda secara manual dengan titik pelacakan, untuk mencari baris yang berisi data pelacakan Anda). Dalam contoh ini, sepertinya 6516 menjalankan loop utama dari frekuensi update. Jika Anda menutup semua tab lain sebelum memulai pelacakan, menemukan CrRendererMain yang benar akan lebih mudah. Namun, mungkin masih ada baris CrRendererMain untuk proses selain game Anda.

Menemukan bingkai

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

Sepertinya tiga frame eksekusi
Sepertinya tiga frame eksekusi

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

Mendalami frame eksekusi
Mendalami frame eksekusi

Kumpulan kotak ini menunjukkan 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 disebut RenderWidget::OnSwapBuffersComplete, yang kemudian disebut RenderWidget::DoDeferredUpdate, dan seterusnya. Dengan membaca data ini, Anda bisa mendapatkan gambaran lengkap tentang apa yang disebut dengan apa dan berapa lama waktu yang dibutuhkan setiap eksekusi.

Tapi di sini, bagian ini menjadi sedikit melekat. Informasi yang diekspos oleh about:tracing adalah panggilan fungsi mentah dari kode sumber Chrome. Anda dapat membuat perkiraan yang matang tentang apa yang dilakukan setiap fungsi dari namanya, tetapi informasinya tidak mudah digunakan. Akan berguna untuk melihat aliran {i>frame<i} secara keseluruhan, tetapi Anda memerlukan sesuatu yang sedikit lebih mudah dibaca manusia untuk benar-benar mengetahui apa yang sedang terjadi.

Menambahkan tag trace

Untungnya ada cara yang mudah untuk menambahkan instrumentasi manual ke kode Anda untuk 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 dalam nama tampilan pelacakan dengan tag yang ditentukan, jadi jika Anda menjalankan kembali aplikasi, Anda akan melihat kotak "update" dan "render" yang menunjukkan waktu yang berlalu antara panggilan awal dan akhir untuk setiap tag.

Tag ditambahkan secara manual
Tag ditambahkan secara manual

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

GPU atau CPU?

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

Pertama, temukan garis 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 kerja CPU di CrRendererMain serta di GPU. Rekaman aktivitas di atas menunjukkan kasus penggunaan yang sangat sederhana di mana CPU dan GPU tidak ada aktivitas untuk sebagian besar setiap frame 16 md.

Tampilan rekaman aktivitas sangat membantu saat Anda memiliki game yang berjalan lambat dan tidak yakin resource mana yang telah ditingkatkan. Kunci untuk proses debug adalah mengamati hubungan antara garis GPU dan CPU. Ambil contoh yang sama seperti sebelumnya, tetapi tambahkan sedikit pekerjaan tambahan di 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 ditunjukkan oleh rekaman aktivitas ini? Kita dapat melihat bahwa frame yang difoto berangkat dari sekitar 2270 md menjadi 2320 md, yang berarti bahwa setiap frame memerlukan waktu sekitar 50 md (kecepatan frame 20 Hz). Anda dapat melihat potongan kotak berwarna yang mewakili fungsi render di samping kotak update, tetapi bingkai tersebut sepenuhnya didominasi oleh update itu sendiri.

Berbeda dengan yang terjadi pada CPU, Anda dapat melihat bahwa GPU masih tidak ada aktivitas untuk sebagian besar setiap frame. Untuk mengoptimalkan kode ini, Anda dapat mencari operasi yang bisa dilakukan dalam kode shader, lalu memindahkannya ke GPU untuk mengoptimalkan penggunaan resource.

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 shader fragmen. 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 trace kode yang menggunakan shader tersebut?

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

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

Jika Anda tidak mengetahui secara pasti penyebab kecepatan frame rendah, Anda dapat mengamati update 5 Hz dan tergoda untuk masuk ke kode game dan mulai mencoba mengoptimalkan atau menghapus logika game. Dalam hal ini, hal itu sama sekali tidak bagus, karena logika di game loop bukanlah yang menghabiskan waktu. Faktanya, yang ditunjukkan oleh rekaman aktivitas ini adalah melakukan lebih banyak pekerjaan CPU setiap frame pada dasarnya akan "bebas" karena CPU bergantung pada waktu diam, sehingga memberikan lebih banyak pekerjaan tidak akan memengaruhi berapa lama frame yang dibutuhkan.

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 Anda ingin menguji alat pembuatan profil, Anda dapat memilih judul WebGL favorit Anda dari Chrome Web Store dan membuat profilnya dengan about:tracing. Ini adalah contoh rekaman aktivitas yang diambil dari game WebGL yang luar biasa Skid Racer.

Melacak game sungguhan
Melacak game sungguhan

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

Kesimpulan

Jika Anda ingin game berjalan pada kecepatan 60 Hz, maka untuk setiap frame, semua operasi harus sesuai dengan 16 md CPU dan 16 md waktu GPU. Anda memiliki dua resource yang dapat digunakan secara paralel, dan Anda dapat mengalihkan pekerjaan dari kedua resource tersebut untuk memaksimalkan performa. Tampilan pelacakan Chrome adalah alat yang sangat berharga untuk mendapatkan insight tentang fungsi kode yang sebenarnya dan akan membantu memaksimalkan waktu pengembangan dengan menangani masalah yang tepat.

Apa langkah selanjutnya?

Selain GPU, Anda juga dapat melacak bagian lain dari runtime Chrome. Chrome Canary, versi awal Chrome, diinstrumentasikan untuk melacak IO, IndexedDB, dan beberapa aktivitas lainnya. Anda harus membaca artikel Chromium ini untuk mendapatkan pemahaman yang lebih mendalam tentang status pelacakan peristiwa saat ini.

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