Perjalanan sejauh ini
Setahun yang lalu, Chrome mengumumkan dukungan awal untuk proses debug WebAssembly native di Chrome DevTools.
Kami telah menunjukkan dukungan langkah dasar dan membahas peluang penggunaan informasi DWARF, bukan peta sumber, yang terbuka untuk kita di masa mendatang:
- Me-resolve nama variabel
- Jenis pencetakan yang rapi
- Mengevaluasi ekspresi dalam bahasa sumber
- …dan banyak lagi.
Hari ini, kami dengan senang hati menampilkan fitur yang dijanjikan yang telah diwujudkan dan progres yang telah dibuat oleh tim Emscripten dan Chrome DevTools selama tahun ini, khususnya, untuk aplikasi C dan C++.
Sebelum memulai, perlu diingat bahwa ini masih merupakan versi beta dari pengalaman baru. Anda harus menggunakan versi terbaru dari semua alat dengan risiko Anda sendiri, dan jika Anda mengalami masalah, laporkan ke https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Mari kita mulai dengan contoh C sederhana yang sama seperti sebelumnya:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Untuk mengompilasi, kita menggunakan Emscripten terbaru
dan meneruskan flag -g
, seperti dalam postingan asli, untuk menyertakan informasi
debug:
emcc -g temp.c -o temp.html
Sekarang kita dapat menayangkan halaman yang dihasilkan dari server HTTP localhost (misalnya, dengan serve), dan membukanya di Chrome Canary terbaru.
Kali ini, kita juga memerlukan ekstensi helper yang terintegrasi dengan Chrome DevTools dan membantunya memahami semua informasi proses debug yang dienkode dalam file WebAssembly. Instal ekstensi ini dengan membuka link ini: goo.gle/wasm-debugging-extension
Anda juga dapat mengaktifkan proses debug WebAssembly di Eksperimen DevTools. Buka Chrome DevTools, klik ikon roda gigi (⚙) di sudut kanan atas panel DevTools, buka panel Eksperimen, lalu centang WebAssembly Debugging: Enable DWARF support.
Saat Anda menutup Settings, DevTools akan menyarankan untuk memuat ulang itself untuk menerapkan setelan, jadi mari kita lakukan hal itu. Itu saja untuk penyiapan satu kali.
Sekarang kita dapat kembali ke panel Sumber, mengaktifkan Jeda pada pengecualian (ikon ⏸), lalu mencentang Jeda pada pengecualian yang tertangkap dan memuat ulang halaman. Anda akan melihat DevTools dijeda pada pengecualian:
Secara default, kode ini berhenti pada kode glue yang dihasilkan Emscripten, tetapi di sebelah kanan, Anda dapat melihat tampilan Call Stack yang mewakili stacktrace error, dan dapat membuka baris C asli yang memanggil abort
:
Sekarang, jika melihat di tampilan Cakupan, Anda dapat melihat nama asli
dan nilai variabel dalam kode C/C++, dan tidak perlu lagi mencari tahu makna nama yang rusak seperti $localN
dan kaitannya dengan
kode sumber yang telah Anda tulis.
Hal ini tidak hanya berlaku untuk nilai primitif seperti bilangan bulat, tetapi juga untuk jenis gabungan seperti struktur, class, array, dll.
Dukungan jenis kaya
Mari kita lihat contoh yang lebih rumit untuk menunjukkannya. Kali ini, kita akan menggambar fraktal Mandelbrot dengan kode C++ berikut:
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
Anda dapat melihat bahwa aplikasi ini masih cukup kecil-hanya satu file yang berisi 50 baris kode-tetapi kali ini saya juga menggunakan beberapa API eksternal, seperti library SDL untuk grafik serta bilangan kompleks dari library standar C++.
Saya akan mengompilasi dengan flag -g
yang sama seperti di atas untuk menyertakan
informasi debug, dan juga saya akan meminta Emscripten untuk menyediakan library
SDL2 dan mengizinkan memori berukuran arbitrer:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Saat mengunjungi halaman yang dihasilkan di browser, saya dapat melihat bentuk fraktal yang indah dengan beberapa warna acak:
Saat membuka DevTools, sekali lagi, saya dapat melihat file C++ asli. Namun, kali ini kita tidak memiliki error dalam kode (wow!), jadi mari kita tetapkan beberapa titik henti sementara di awal kode.
Saat kita memuat ulang halaman lagi, debugger akan dijeda tepat di dalam sumber C++ kita:
Kita sudah dapat melihat semua variabel di sebelah kanan, tetapi saat ini hanya width
dan height
yang diinisialisasi, sehingga tidak banyak yang perlu
diperiksa.
Mari kita tetapkan titik henti sementara lain di dalam loop Mandelbrot utama, dan lanjutkan eksekusi untuk melompat sedikit ke depan.
Pada tahap ini, palette
telah diisi dengan beberapa warna acak,
dan kita dapat memperluas array itu sendiri, serta setiap
struktur SDL_Color
dan memeriksa komponennya untuk memverifikasi bahwa
semuanya terlihat bagus (misalnya, saluran "alpha" selalu ditetapkan
ke opasitas penuh). Demikian pula, kita dapat memperluas dan memeriksa bagian riil dan imajiner dari bilangan kompleks yang disimpan dalam variabel center
.
Jika ingin mengakses properti bertingkat yang sulit diakses melalui tampilan Cakupan, Anda juga dapat menggunakan evaluasi Konsol. Namun, perlu diperhatikan bahwa ekspresi C++ yang lebih kompleks belum didukung.
Mari kita lanjutkan eksekusi beberapa kali dan kita dapat melihat bagaimana x
bagian dalam
juga berubah, baik dengan melihat kembali tampilan Scope, menambahkan
nama variabel ke daftar pantau, mengevaluasinya di konsol, atau dengan
mengarahkan kursor ke variabel dalam kode sumber:
Dari sini, kita dapat melakukan step-in atau step-over pada pernyataan C++, dan mengamati bagaimana variabel lain juga berubah:
Baik, jadi semua ini berfungsi dengan baik jika informasi debug tersedia, tetapi bagaimana jika kita ingin men-debug kode yang tidak di-build dengan opsi proses debug?
Proses debug WebAssembly mentah
Misalnya, kami meminta Emscripten untuk menyediakan library SDL bawaan bagi
kami, bukan mengompilasi sendiri dari sumber, sehingga-setidaknya
saat ini-debugger tidak dapat menemukan sumber terkait.
Mari kita masuk lagi untuk masuk ke SDL_RenderDrawColor
:
Kita kembali ke pengalaman proses debug WebAssembly mentah.
Sekarang, hal ini terlihat agak menakutkan dan bukan sesuatu yang perlu ditangani oleh sebagian besar developer Web, tetapi terkadang Anda mungkin ingin men-debug library yang dibuat tanpa informasi debug, baik karena library tersebut adalah library pihak ketiga yang tidak dapat Anda kontrol, atau karena Anda menemukan salah satu bug yang hanya terjadi pada produksi.
Untuk membantu dalam kasus tersebut, kami juga telah melakukan beberapa peningkatan pada pengalaman proses debug dasar.
Pertama-tama, jika sebelumnya Anda menggunakan proses debug WebAssembly mentah, Anda mungkin
melihat bahwa seluruh proses disassembly kini ditampilkan dalam satu file. Tidak perlu lagi menebak fungsi mana yang mungkin sesuai dengan entri Sumber wasm-53834e3e/
wasm-53834e3e-7
.
Skema pembuatan nama baru
Kami juga meningkatkan nama dalam tampilan pemisahan. Sebelumnya, Anda hanya akan melihat indeks numerik, atau, dalam kasus fungsi, tidak ada nama sama sekali.
Sekarang kita membuat nama yang mirip dengan alat disassembly lainnya, dengan
menggunakan petunjuk dari bagian nama WebAssembly,
jalur impor/ekspor, dan terakhir, jika semuanya gagal, membuat
nama berdasarkan jenis dan indeks item seperti $func123
. Anda dapat
melihat bagaimana, dalam screenshot di atas, hal ini sudah membantu mendapatkan
stacktrace dan disassembly yang sedikit lebih mudah dibaca.
Jika tidak ada informasi jenis yang tersedia, mungkin sulit untuk memeriksa nilai apa pun selain primitif-misalnya, pointer akan muncul sebagai bilangan bulat biasa, tanpa cara untuk mengetahui apa yang disimpan di belakangnya dalam memori.
Pemeriksaan memori
Sebelumnya, Anda hanya dapat meluaskan objek memori WebAssembly, yang diwakili oleh env.memory
di tampilan Cakupan untuk mencari
setiap byte. Hal ini berfungsi dalam beberapa skenario sederhana, tetapi tidak
sangat mudah untuk diperluas dan tidak memungkinkan untuk menafsirkan ulang data
dalam format selain nilai byte. Kami juga telah menambahkan fitur baru untuk membantu
hal ini: inspector memori linear.
Jika mengklik kanan env.memory
, Anda akan melihat opsi baru
yang disebut Periksa memori:
Setelah diklik, Memory Inspector akan muncul, tempat Anda dapat memeriksa memori WebAssembly dalam tampilan heksadesimal dan ASCII, membuka alamat tertentu, serta menafsirkan data dalam format yang berbeda:
Skenario dan peringatan lanjutan
Membuat profil kode WebAssembly
Saat Anda membuka DevTools, kode WebAssembly akan "dikelompokkan ke bawah" ke
versi yang tidak dioptimalkan untuk mengaktifkan proses debug. Versi ini jauh lebih lambat,
yang berarti Anda tidak dapat mengandalkan console.time
, performance.now
,
dan metode lain untuk mengukur kecepatan kode saat DevTools
terbuka, karena angka yang Anda dapatkan tidak akan mewakili performa di dunia nyata
sama sekali.
Sebagai gantinya, Anda harus menggunakan panel Performa DevTools yang akan menjalankan kode dengan kecepatan penuh dan memberi Anda perincian mendetail tentang waktu yang dihabiskan dalam berbagai fungsi:
Atau, Anda dapat menjalankan aplikasi dengan DevTools tertutup, dan membukanya setelah selesai untuk memeriksa Konsol.
Kami akan meningkatkan kualitas skenario pembuatan profil pada masa mendatang, tetapi untuk saat ini, hal ini merupakan peringatan yang perlu diperhatikan. Jika Anda ingin mempelajari lebih lanjut skenario tingkatan WebAssembly, lihat dokumen kami tentang pipeline kompilasi WebAssembly.
Membangun dan men-debug di berbagai komputer (termasuk Docker / host)
Saat mem-build di Docker, virtual machine, atau di server build jarak jauh, Anda mungkin akan mengalami situasi saat jalur ke file sumber yang digunakan selama build tidak cocok dengan jalur di sistem file Anda sendiri tempat Chrome DevTools berjalan. Dalam hal ini, file akan muncul di panel Sumber, tetapi gagal dimuat.
Untuk memperbaiki masalah ini, kami telah menerapkan fungsi pemetaan jalur di opsi ekstensi C/C++. Anda dapat menggunakannya untuk memetakan ulang jalur arbitrer dan membantu DevTools menemukan sumber.
Misalnya, jika project di mesin host Anda berada di jalur
C:\src\my_project
, tetapi di-build di dalam penampung Docker tempat
jalur tersebut direpresentasikan sebagai /mnt/c/src/my_project
, Anda dapat memetakan ulang
jalur tersebut selama proses debug dengan menentukan jalur tersebut sebagai awalan:
Awalan pertama yang cocok akan "menang". Jika Anda sudah terbiasa dengan debugger C++
lainnya, opsi ini mirip dengan perintah set substitute-path
di GDB atau setelan target.source-map
di LLDB.
Men-debug build yang dioptimalkan
Seperti bahasa lainnya, proses debug berfungsi paling baik jika pengoptimalan dinonaktifkan. Pengoptimalan dapat menggabungkan fungsi satu sama lain, mengurutkan ulang kode, atau menghapus bagian kode sepenuhnya-dan semua ini memiliki kemungkinan untuk membingungkan debugger dan, akibatnya, Anda sebagai pengguna.
Jika Anda tidak keberatan dengan pengalaman proses debug yang lebih terbatas dan masih ingin
men-debug build yang dioptimalkan, sebagian besar pengoptimalan akan berfungsi seperti
yang diharapkan, kecuali untuk penyematan fungsi. Kami berencana untuk mengatasi masalah
yang tersisa di masa mendatang, tetapi, untuk saat ini, gunakan -fno-inline
untuk
menonaktifkannya saat mengompilasi dengan pengoptimalan level -O
, misalnya:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Memisahkan informasi debug
Informasi debug menyimpan banyak detail tentang kode Anda, jenis, variabel, fungsi, cakupan, dan lokasi yang ditentukan-apa pun yang mungkin berguna bagi debugger. Akibatnya, file ini sering kali dapat lebih besar dari kode itu sendiri.
Untuk mempercepat pemuatan dan kompilasi modul WebAssembly, sebaiknya
pisahkan informasi debug ini ke dalam file WebAssembly
terpisah. Untuk melakukannya di Emscripten, teruskan tanda -gseparate-dwarf=…
dengan
nama file yang diinginkan:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
Dalam hal ini, aplikasi utama hanya akan menyimpan nama file
temp.debug.wasm
, dan ekstensi helper akan dapat menemukan dan
memuatnya saat Anda membuka DevTools.
Jika digabungkan dengan pengoptimalan seperti yang dijelaskan di atas, fitur ini bahkan dapat digunakan untuk mengirimkan build produksi yang hampir dioptimalkan dari aplikasi Anda, lalu men-debugnya dengan file sisi lokal. Dalam hal ini, kita juga harus mengganti URL yang disimpan untuk membantu ekstensi menemukan file samping, misalnya:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
Lanjutkan…
Wah, banyak sekali fitur barunya!
Dengan semua integrasi baru tersebut, Chrome DevTools menjadi debugger yang efektif dan canggih, tidak hanya untuk JavaScript, tetapi juga untuk aplikasi C dan C++, sehingga memudahkan Anda mengambil aplikasi yang dibuat dalam berbagai teknologi dan membawanya ke Web lintas platform bersama.
Namun, perjalanan kita belum berakhir. Beberapa hal yang akan kami kerjakan mulai sekarang:
- Membersihkan kekurangan dalam pengalaman proses debug.
- Menambahkan dukungan untuk pemformat jenis kustom.
- Mengusahakan peningkatan pada profiling untuk aplikasi WebAssembly.
- Menambahkan dukungan untuk cakupan kode agar lebih mudah menemukan kode yang tidak digunakan.
- Meningkatkan dukungan untuk ekspresi dalam evaluasi konsol.
- Menambahkan dukungan untuk lebih banyak bahasa.
- …dan lainnya!
Sementara itu, bantu kami dengan mencoba versi beta saat ini pada kode Anda sendiri dan laporkan masalah apa pun yang ditemukan ke https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Mendownload saluran pratinjau
Sebaiknya gunakan Chrome Canary, Dev, atau Beta sebagai browser pengembangan default Anda. Saluran pratinjau ini memberi Anda akses ke fitur DevTools terbaru, memungkinkan Anda menguji API platform web canggih, dan membantu Anda menemukan masalah di situs sebelum pengguna melakukannya.
Hubungi tim Chrome DevTools
Gunakan opsi berikut untuk membahas fitur baru, update, atau hal lain yang terkait dengan DevTools.
- Kirim masukan dan permintaan fitur kepada kami di crbug.com.
- Laporkan masalah DevTools menggunakan Opsi lainnya > Bantuan > Laporkan masalah DevTools di DevTools.
- Tweet ke @ChromeDevTools.
- Berikan komentar di video YouTube Yang baru di DevTools atau video YouTube Tips DevTools.