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 langkah awal, tetapi untuk melihat gambaran lengkapnya, Anda harus memahami nuansa dalam aktivitas Chrome.

Alat about:tracing memberikan insight yang membantu Anda menghindari solusi terburu-buru yang ditujukan untuk peningkatan performa, tetapi yang pada dasarnya merupakan spekulasi yang dirancang dengan 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:tracing

Alat tentang:pelacakan Chrome memberi Anda jendela untuk melihat semua aktivitas Chrome selama jangka waktu tertentu dengan begitu banyak perincian sehingga Anda mungkin pada awalnya merasa kewalahan. Banyak fungsi di Chrome diinstrumentasikan untuk langsung melakukan pelacakan, sehingga tanpa melakukan instrumentasi manual apa pun, Anda masih dapat menggunakan about:tracing untuk melacak performa Anda. (Lihat bagian selanjutnya tentang menginstrumentasikan JS Anda secara manual)

Untuk melihat tampilan pelacakan, cukup ketik "about:tracing" ke dalam 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, itu membingungkan. Mari kita bicara tentang cara membacanya.

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

Saat membaca data trace, 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 rapi untuk memilih aplikasi Anda kecuali mencari baris yang melakukan banyak update berkala (atau jika Anda telah secara manual menginstrumentasikan kode dengan titik pelacakan, untuk mencari baris yang berisi data pelacakan). Dalam contoh ini, sepertinya 6516 menjalankan loop utama dari frekuensi pembaruan. Jika Anda menutup semua tab lain sebelum memulai pelacakan, mencari tahu 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 Anda, langkah berikutnya adalah menemukan loop utama. Loop utama terlihat seperti pola berulang dalam data pelacakan. Anda dapat menavigasi data pelacakan dengan menggunakan tombol W, A, S, D: A dan D untuk bergerak ke kiri atau kanan (maju mundur dalam waktu), serta W dan S untuk memperbesar dan memperkecil data. Anda akan memperkirakan loop utama berupa pola yang berulang setiap 16 milidetik jika game Anda berjalan pada 60 Hz.

Sepertinya tiga frame eksekusi
Tampaknya seperti tiga frame eksekusi

Setelah menemukan detak jantung 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.

Masuk ke dalam {i>frame<i} eksekusi
Mendalami frame eksekusi

Kumpulan kotak ini menampilkan serangkaian panggilan fungsi, dengan setiap panggilan diwakili oleh kotak berwarna. Setiap fungsi dipanggil oleh kotak di atasnya, sehingga dalam hal ini, Anda dapat melihat bahwa MessageLoop::RunTask memanggil RenderWidget::OnSwapBuffersComplete, yang selanjutnya 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 untuk setiap eksekusi.

Tapi di sinilah titik-titik itu menjadi sedikit lengket. 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 nama tersebut, tetapi informasinya tidak benar-benar mudah digunakan. Ini berguna untuk melihat alur keseluruhan {i>frame<i} Anda, 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, sehingga jika Anda menjalankan ulang aplikasi, Anda akan melihat "update" dan "render" kotak yang menunjukkan waktu yang berlalu antara panggilan awal dan akhir untuk setiap tag.

Tag 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 dengan akselerasi hardware, salah satu pertanyaan terpenting yang dapat Anda tanyakan selama pembuatan profil adalah: Apakah kode ini terikat dengan GPU atau terikat CPU? Pada setiap {i>frame<i} Anda akan melakukan beberapa pekerjaan rendering di GPU dan beberapa logika pada CPU; Untuk memahami apa yang membuat game lambat, Anda perlu melihat keseimbangan di kedua resource tersebut.

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

Tampilan pelacakan sangat membantu saat Anda memiliki game yang berjalan lambat dan Anda tidak yakin resource mana yang ingin maksimal. Melihat keterkaitan garis GPU dan CPU adalah kunci untuk proses debug. 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 pelacakan ini? Kita dapat melihat bahwa frame yang digambarkan berubah dari sekitar 2270 ms ke 2320 ms, yang berarti bahwa setiap frame membutuhkan waktu sekitar 50 ms (frame rate 20 Hz). Anda dapat melihat potongan kotak berwarna yang mewakili fungsi render di sebelah kotak pembaruan, namun bingkai sepenuhnya didominasi oleh pembaruan itu sendiri.

Berbeda dengan apa yang terjadi pada CPU, Anda dapat melihat bahwa GPU masih menganggur di hampir setiap frame. Untuk mengoptimalkan kode ini, Anda dapat mencari operasi yang dapat dilakukan dalam kode shader dan memindahkannya ke GPU untuk memanfaatkan resource sebaik mungkin.

Bagaimana dengan 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 tampilan trace kode yang menggunakan shader tersebut?

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

Sekali lagi, perhatikan durasi {i>frame<i}. Di sini pola berulang berjalan dari sekitar 2750 ms ke 2950 ms, durasi 200 ms (frame rate sekitar 5Hz). Baris CrRendererMain hampir sepenuhnya kosong yang berarti bahwa CPU sering kali tidak ada aktivitas, sementara GPU kelebihan beban. Hal ini merupakan tanda bahwa shader Anda terlalu berat.

Jika Anda tidak dapat melihat secara persis penyebab kecepatan frame yang rendah, Anda dapat mengamati update 5 Hz dan tergoda untuk memasukkan kode game dan mulai mencoba mengoptimalkan atau menghapus logika game. Dalam hal ini, hal itu tidak akan berguna, karena logika dalam {i>game loop<i} bukanlah yang menghabiskan waktu. Faktanya, yang ditunjukkan oleh jejak ini adalah bahwa melakukan lebih banyak pekerjaan CPU, setiap frame pada dasarnya akan "bebas" di mana CPU menganggur, jadi memberinya lebih banyak pekerjaan tidak akan mempengaruhi waktu yang dibutuhkan {i>frame<i}.

Contoh Nyata

Sekarang mari kita lihat 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 profil dengan about:tracing. Ini adalah contoh rekaman aktivitas yang diambil dari game WebGL yang luar biasa, Skid Racer.

Melacak game sungguhan
Merekam game sungguhan

Sepertinya setiap frame memerlukan waktu sekitar 20 md, yang berarti kecepatan frame sekitar 50 FPS. Anda dapat melihat bahwa pekerjaannya seimbang antara CPU dan GPU, tetapi GPU adalah sumber daya yang paling banyak dicari. Jika Anda ingin melihat seperti apa 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 CPU 16 md dan waktu GPU 16 md. Anda memiliki dua resource yang dapat digunakan secara paralel, dan Anda dapat mengalihkan pekerjaan di antara resource tersebut untuk memaksimalkan performa. Tampilan about:tracing pada Chrome adalah alat yang sangat berharga untuk mendapatkan insight tentang apa yang sebenarnya dilakukan kode Anda 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, Chrome versi tahap awal, diinstrumentasikan untuk melacak IO, IndexedDB, dan beberapa aktivitas lainnya. Anda harus membaca artikel Chromium ini untuk lebih memahami status pelacakan peristiwa saat ini.

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